aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-11-18 18:56:30 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-19 11:08:54 -0500
commitad4bb6f8883a13bb0f65b194dae36c62a02ac779 (patch)
treeb395936203ac891b9a537c26b4602f727c4387d0
parent9bc383de37090ba7ca3ff32a12c9d809dc5867f0 (diff)
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>
-rw-r--r--include/linux/if.h1
-rw-r--r--net/bridge/br_if.c4
-rw-r--r--net/wireless/core.c4
-rw-r--r--net/wireless/nl80211.c12
-rw-r--r--net/wireless/util.c31
5 files changed, 48 insertions, 4 deletions
diff --git a/include/linux/if.h b/include/linux/if.h
index 3b2a46bf8f8d..3a9f410a296b 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -70,6 +70,7 @@
70#define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to 70#define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to
71 * release skb->dst 71 * release skb->dst
72 */ 72 */
73#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */
73 74
74#define IF_GET_IFACE 0x0001 /* for querying only */ 75#define IF_GET_IFACE 0x0001 /* for querying only */
75#define IF_GET_PROTO 0x0002 76#define IF_GET_PROTO 0x0002
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index a6f74b2b9571..a2cbe61f6e65 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -390,6 +390,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
390 if (dev->br_port != NULL) 390 if (dev->br_port != NULL)
391 return -EBUSY; 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 p = new_nbp(br, dev); 397 p = new_nbp(br, dev);
394 if (IS_ERR(p)) 398 if (IS_ERR(p))
395 return PTR_ERR(p); 399 return PTR_ERR(p);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index e2cc6e7522dd..fc5e9b508607 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -697,6 +697,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
697#endif 697#endif
698 if (!dev->ethtool_ops) 698 if (!dev->ethtool_ops)
699 dev->ethtool_ops = &cfg80211_ethtool_ops; 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 break; 704 break;
701 case NETDEV_GOING_DOWN: 705 case NETDEV_GOING_DOWN:
702 switch (wdev->iftype) { 706 switch (wdev->iftype) {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b7b0f67b0c61..149539ade15e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -969,10 +969,14 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
969} 969}
970 970
971static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, 971static 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 return 0; 978 return 0;
979 }
976 980
977 switch (iftype) { 981 switch (iftype) {
978 case NL80211_IFTYPE_AP_VLAN: 982 case NL80211_IFTYPE_AP_VLAN:
@@ -1033,7 +1037,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
1033 if (info->attrs[NL80211_ATTR_4ADDR]) { 1037 if (info->attrs[NL80211_ATTR_4ADDR]) {
1034 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); 1038 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1035 change = true; 1039 change = true;
1036 err = nl80211_valid_4addr(rdev, params.use_4addr, ntype); 1040 err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
1037 if (err) 1041 if (err)
1038 goto unlock; 1042 goto unlock;
1039 } else { 1043 } else {
@@ -1111,7 +1115,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
1111 1115
1112 if (info->attrs[NL80211_ATTR_4ADDR]) { 1116 if (info->attrs[NL80211_ATTR_4ADDR]) {
1113 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); 1117 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);
1115 if (err) 1119 if (err)
1116 goto unlock; 1120 goto unlock;
1117 } 1121 }
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 17a7a4cfc617..59361fdcb5d0 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -658,6 +658,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
658 !(rdev->wiphy.interface_modes & (1 << ntype))) 658 !(rdev->wiphy.interface_modes & (1 << ntype)))
659 return -EOPNOTSUPP; 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 if (ntype != otype) { 666 if (ntype != otype) {
662 dev->ieee80211_ptr->use_4addr = false; 667 dev->ieee80211_ptr->use_4addr = false;
663 668
@@ -687,5 +692,31 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
687 if (!err && params && params->use_4addr != -1) 692 if (!err && params && params->use_4addr != -1)
688 dev->ieee80211_ptr->use_4addr = params->use_4addr; 693 dev->ieee80211_ptr->use_4addr = params->use_4addr;
689 694
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
690 return err; 721 return err;
691} 722}