summaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-11-19 11:55:19 +0100
committerJohn W. Linville <linville@tuxdriver.com>2009-11-19 17:08:53 +0100
commit9bc383de37090ba7ca3ff32a12c9d809dc5867f0 (patch)
tree2b502b918f585427b45357e5a9a781ea9f06c263 /net/wireless
parentcfg80211: convert bools into flags (diff)
downloadlinux-9bc383de37090ba7ca3ff32a12c9d809dc5867f0.tar.xz
linux-9bc383de37090ba7ca3ff32a12c9d809dc5867f0.zip
cfg80211: introduce capability for 4addr mode
It's very likely that not many devices will support four-address mode in station or AP mode so introduce capability bits for both modes, set them in mac80211 and check them when userspace tries to use the mode. Also, keep track of 4addr in cfg80211 (wireless_dev) and not in mac80211 any more. mac80211 can also be improved for the VLAN case by not looking at the 4addr flag but maintaining the station pointer for it correctly. However, keep track of use_4addr for station mode in mac80211 to avoid all the derefs. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/nl80211.c34
-rw-r--r--net/wireless/util.c5
2 files changed, 38 insertions, 1 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 6634188f9453..b7b0f67b0c61 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -968,6 +968,28 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
return 0;
}
+static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
+ u8 use_4addr, enum nl80211_iftype iftype)
+{
+ if (!use_4addr)
+ return 0;
+
+ switch (iftype) {
+ case NL80211_IFTYPE_AP_VLAN:
+ if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
+ return 0;
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
+ return 0;
+ break;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
@@ -1011,6 +1033,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
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);
+ if (err)
+ goto unlock;
} else {
params.use_4addr = -1;
}
@@ -1034,6 +1059,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
else
err = 0;
+ if (!err && params.use_4addr != -1)
+ dev->ieee80211_ptr->use_4addr = params.use_4addr;
+
unlock:
dev_put(dev);
cfg80211_unlock_rdev(rdev);
@@ -1081,8 +1109,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
}
- if (info->attrs[NL80211_ATTR_4ADDR])
+ 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);
+ if (err)
+ goto unlock;
+ }
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 5aa39f7cf9b9..17a7a4cfc617 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -659,6 +659,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
return -EOPNOTSUPP;
if (ntype != otype) {
+ dev->ieee80211_ptr->use_4addr = false;
+
switch (otype) {
case NL80211_IFTYPE_ADHOC:
cfg80211_leave_ibss(rdev, dev, false);
@@ -682,5 +684,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
+ if (!err && params && params->use_4addr != -1)
+ dev->ieee80211_ptr->use_4addr = params->use_4addr;
+
return err;
}