diff options
-rw-r--r-- | include/linux/if.h | 1 | ||||
-rw-r--r-- | net/bridge/br_if.c | 4 | ||||
-rw-r--r-- | net/wireless/core.c | 4 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 12 | ||||
-rw-r--r-- | net/wireless/util.c | 31 |
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 | ||
971 | static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, | 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 | 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 | } |