Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Johannes Berg and committed by
John W. Linville
ad4bb6f8 9bc383de

+48 -4
+1
include/linux/if.h
··· 70 70 #define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to 71 71 * release skb->dst 72 72 */ 73 + #define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */ 73 74 74 75 #define IF_GET_IFACE 0x0001 /* for querying only */ 75 76 #define IF_GET_PROTO 0x0002
+4
net/bridge/br_if.c
··· 390 390 if (dev->br_port != NULL) 391 391 return -EBUSY; 392 392 393 + /* No bridging devices that dislike that (e.g. wireless) */ 394 + if (dev->priv_flags & IFF_DONT_BRIDGE) 395 + return -EOPNOTSUPP; 396 + 393 397 p = new_nbp(br, dev); 394 398 if (IS_ERR(p)) 395 399 return PTR_ERR(p);
+4
net/wireless/core.c
··· 697 697 #endif 698 698 if (!dev->ethtool_ops) 699 699 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; 700 704 break; 701 705 case NETDEV_GOING_DOWN: 702 706 switch (wdev->iftype) {
+8 -4
net/wireless/nl80211.c
··· 969 969 } 970 970 971 971 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) 973 974 { 974 - if (!use_4addr) 975 + if (!use_4addr) { 976 + if (netdev && netdev->br_port) 977 + return -EBUSY; 975 978 return 0; 979 + } 976 980 977 981 switch (iftype) { 978 982 case NL80211_IFTYPE_AP_VLAN: ··· 1037 1033 if (info->attrs[NL80211_ATTR_4ADDR]) { 1038 1034 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); 1039 1035 change = true; 1040 - err = nl80211_valid_4addr(rdev, params.use_4addr, ntype); 1036 + err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); 1041 1037 if (err) 1042 1038 goto unlock; 1043 1039 } else { ··· 1115 1111 1116 1112 if (info->attrs[NL80211_ATTR_4ADDR]) { 1117 1113 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); 1118 - err = nl80211_valid_4addr(rdev, params.use_4addr, type); 1114 + err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); 1119 1115 if (err) 1120 1116 goto unlock; 1121 1117 }
+31
net/wireless/util.c
··· 658 658 !(rdev->wiphy.interface_modes & (1 << ntype))) 659 659 return -EOPNOTSUPP; 660 660 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 + 661 666 if (ntype != otype) { 662 667 dev->ieee80211_ptr->use_4addr = false; 663 668 ··· 691 686 692 687 if (!err && params && params->use_4addr != -1) 693 688 dev->ieee80211_ptr->use_4addr = params->use_4addr; 689 + 690 + if (!err) { 691 + dev->priv_flags &= ~IFF_DONT_BRIDGE; 692 + switch (ntype) { 693 + case NL80211_IFTYPE_STATION: 694 + if (dev->ieee80211_ptr->use_4addr) 695 + break; 696 + /* fall through */ 697 + case NL80211_IFTYPE_ADHOC: 698 + dev->priv_flags |= IFF_DONT_BRIDGE; 699 + break; 700 + case NL80211_IFTYPE_AP: 701 + case NL80211_IFTYPE_AP_VLAN: 702 + case NL80211_IFTYPE_WDS: 703 + case NL80211_IFTYPE_MESH_POINT: 704 + /* bridging OK */ 705 + break; 706 + case NL80211_IFTYPE_MONITOR: 707 + /* monitor can't bridge anyway */ 708 + break; 709 + case NL80211_IFTYPE_UNSPECIFIED: 710 + case __NL80211_IFTYPE_AFTER_LAST: 711 + /* not happening */ 712 + break; 713 + } 714 + } 694 715 695 716 return err; 696 717 }