Skip to content

Commit ad4bb6f

Browse files
jmberglinvjw
authored andcommitted
cfg80211: disallow bridging managed/adhoc interfaces
A number of people have tried to add a wireless interface (in managed mode) to a bridge and then complained that it doesn't work. It cannot work, however, because in 802.11 networks all packets need to be acknowledged and as such need to be sent to the right address. Promiscuous doesn't help here. The wireless address format used for these links has only space for three addresses, the * transmitter, which must be equal to the sender (origin) * receiver (on the wireless medium), which is the AP in the case of managed mode * the recipient (destination), which is on the APs local network segment In an IBSS, it is similar, but the receiver and recipient must match and the third address is used as the BSSID. To avoid such mistakes in the future, disallow adding a wireless interface to a bridge. Felix has recently added a four-address mode to the AP and client side that can be used (after negotiating that it is possible, which must happen out-of-band by setting up both sides) for bridging, so allow that case. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
1 parent 9bc383d commit ad4bb6f

File tree

5 files changed

+48
-4
lines changed

5 files changed

+48
-4
lines changed

include/linux/if.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
#define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to
7171
* release skb->dst
7272
*/
73+
#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */
7374

7475
#define IF_GET_IFACE 0x0001 /* for querying only */
7576
#define IF_GET_PROTO 0x0002

net/bridge/br_if.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
390390
if (dev->br_port != NULL)
391391
return -EBUSY;
392392

393+
/* No bridging devices that dislike that (e.g. wireless) */
394+
if (dev->priv_flags & IFF_DONT_BRIDGE)
395+
return -EOPNOTSUPP;
396+
393397
p = new_nbp(br, dev);
394398
if (IS_ERR(p))
395399
return PTR_ERR(p);

net/wireless/core.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
697697
#endif
698698
if (!dev->ethtool_ops)
699699
dev->ethtool_ops = &cfg80211_ethtool_ops;
700+
701+
if ((wdev->iftype == NL80211_IFTYPE_STATION ||
702+
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
703+
dev->priv_flags |= IFF_DONT_BRIDGE;
700704
break;
701705
case NETDEV_GOING_DOWN:
702706
switch (wdev->iftype) {

net/wireless/nl80211.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -969,10 +969,14 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
969969
}
970970

971971
static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
972-
u8 use_4addr, enum nl80211_iftype iftype)
972+
struct net_device *netdev, u8 use_4addr,
973+
enum nl80211_iftype iftype)
973974
{
974-
if (!use_4addr)
975+
if (!use_4addr) {
976+
if (netdev && netdev->br_port)
977+
return -EBUSY;
975978
return 0;
979+
}
976980

977981
switch (iftype) {
978982
case NL80211_IFTYPE_AP_VLAN:
@@ -1033,7 +1037,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
10331037
if (info->attrs[NL80211_ATTR_4ADDR]) {
10341038
params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
10351039
change = true;
1036-
err = nl80211_valid_4addr(rdev, params.use_4addr, ntype);
1040+
err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
10371041
if (err)
10381042
goto unlock;
10391043
} else {
@@ -1111,7 +1115,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
11111115

11121116
if (info->attrs[NL80211_ATTR_4ADDR]) {
11131117
params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1114-
err = nl80211_valid_4addr(rdev, params.use_4addr, type);
1118+
err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
11151119
if (err)
11161120
goto unlock;
11171121
}

net/wireless/util.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
658658
!(rdev->wiphy.interface_modes & (1 << ntype)))
659659
return -EOPNOTSUPP;
660660

661+
/* if it's part of a bridge, reject changing type to station/ibss */
662+
if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC ||
663+
ntype == NL80211_IFTYPE_STATION))
664+
return -EBUSY;
665+
661666
if (ntype != otype) {
662667
dev->ieee80211_ptr->use_4addr = false;
663668

@@ -687,5 +692,31 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
687692
if (!err && params && params->use_4addr != -1)
688693
dev->ieee80211_ptr->use_4addr = params->use_4addr;
689694

695+
if (!err) {
696+
dev->priv_flags &= ~IFF_DONT_BRIDGE;
697+
switch (ntype) {
698+
case NL80211_IFTYPE_STATION:
699+
if (dev->ieee80211_ptr->use_4addr)
700+
break;
701+
/* fall through */
702+
case NL80211_IFTYPE_ADHOC:
703+
dev->priv_flags |= IFF_DONT_BRIDGE;
704+
break;
705+
case NL80211_IFTYPE_AP:
706+
case NL80211_IFTYPE_AP_VLAN:
707+
case NL80211_IFTYPE_WDS:
708+
case NL80211_IFTYPE_MESH_POINT:
709+
/* bridging OK */
710+
break;
711+
case NL80211_IFTYPE_MONITOR:
712+
/* monitor can't bridge anyway */
713+
break;
714+
case NL80211_IFTYPE_UNSPECIFIED:
715+
case __NL80211_IFTYPE_AFTER_LAST:
716+
/* not happening */
717+
break;
718+
}
719+
}
720+
690721
return err;
691722
}

0 commit comments

Comments
 (0)