aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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}