@@ -70,6 +70,7 @@
#define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to
* release skb->dst
*/
+#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */
#define IF_GET_IFACE 0x0001 /* for querying only */
#define IF_GET_PROTO 0x0002
@@ -390,6 +390,10 @@ int br_add_if(struct net_bridge *br, str
if (dev->br_port != NULL)
return -EBUSY;
+ /* No bridging devices that dislike that (e.g. wireless) */
+ if (dev->priv_flags & IFF_DONT_BRIDGE)
+ return -EOPNOTSUPP;
+
p = new_nbp(br, dev);
if (IS_ERR(p))
return PTR_ERR(p);
@@ -658,6 +658,11 @@ int cfg80211_change_iface(struct cfg8021
!(rdev->wiphy.interface_modes & (1 << ntype)))
return -EOPNOTSUPP;
+ /* if it's part of a bridge, reject changing type to station/ibss */
+ if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC ||
+ ntype == NL80211_IFTYPE_STATION))
+ return -EBUSY;
+
if (ntype != otype) {
dev->ieee80211_ptr->use_4addr = false;
@@ -687,5 +692,31 @@ int cfg80211_change_iface(struct cfg8021
if (!err && params && params->use_4addr != -1)
dev->ieee80211_ptr->use_4addr = params->use_4addr;
+ if (!err) {
+ dev->priv_flags &= ~IFF_DONT_BRIDGE;
+ switch (ntype) {
+ case NL80211_IFTYPE_STATION:
+ if (dev->ieee80211_ptr->use_4addr)
+ break;
+ /* fall through */
+ case NL80211_IFTYPE_ADHOC:
+ dev->priv_flags |= IFF_DONT_BRIDGE;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
+ /* bridging OK */
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ /* monitor can't bridge anyway */
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case __NL80211_IFTYPE_AFTER_LAST:
+ /* not happening */
+ break;
+ }
+ }
+
return err;
}
@@ -691,6 +691,10 @@ static int cfg80211_netdev_notifier_call
#endif
if (!dev->ethtool_ops)
dev->ethtool_ops = &cfg80211_ethtool_ops;
+
+ if ((wdev->iftype == NL80211_IFTYPE_STATION ||
+ wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
+ dev->priv_flags |= IFF_DONT_BRIDGE;
break;
case NETDEV_GOING_DOWN:
switch (wdev->iftype) {
@@ -969,10 +969,14 @@ static int parse_monitor_flags(struct nl
}
static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
- u8 use_4addr, enum nl80211_iftype iftype)
+ struct net_device *netdev, u8 use_4addr,
+ enum nl80211_iftype iftype)
{
- if (!use_4addr)
+ if (!use_4addr) {
+ if (netdev && netdev->br_port)
+ return -EBUSY;
return 0;
+ }
switch (iftype) {
case NL80211_IFTYPE_AP_VLAN:
@@ -1033,7 +1037,7 @@ static int nl80211_set_interface(struct
if (info->attrs[NL80211_ATTR_4ADDR]) {
params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
change = true;
- err = nl80211_valid_4addr(rdev, params.use_4addr, ntype);
+ err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
if (err)
goto unlock;
} else {
@@ -1111,7 +1115,7 @@ static int nl80211_new_interface(struct
if (info->attrs[NL80211_ATTR_4ADDR]) {
params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
- err = nl80211_valid_4addr(rdev, params.use_4addr, type);
+ err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
if (err)
goto unlock;
}