summaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c81
1 files changed, 74 insertions, 7 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1e728ff..e69da8d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -105,6 +105,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
.len = NL80211_HT_CAPABILITY_LEN },
+
+ [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
+ [NL80211_ATTR_IE] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
};
/* message building helper */
@@ -738,7 +742,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_KEY_IDX])
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
- if (key_idx > 3)
+ if (key_idx > 5)
return -EINVAL;
if (info->attrs[NL80211_ATTR_MAC])
@@ -804,30 +808,41 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
int err;
struct net_device *dev;
u8 key_idx;
+ int (*func)(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index);
if (!info->attrs[NL80211_ATTR_KEY_IDX])
return -EINVAL;
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
- if (key_idx > 3)
+ if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) {
+ if (key_idx < 4 || key_idx > 5)
+ return -EINVAL;
+ } else if (key_idx > 3)
return -EINVAL;
/* currently only support setting default key */
- if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
+ if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] &&
+ !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT])
return -EINVAL;
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err)
return err;
- if (!drv->ops->set_default_key) {
+ if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
+ func = drv->ops->set_default_key;
+ else
+ func = drv->ops->set_default_mgmt_key;
+
+ if (!func) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
- err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
+ err = func(&drv->wiphy, dev, key_idx);
rtnl_unlock();
out:
@@ -863,7 +878,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- if (key_idx > 3)
+ if (key_idx > 5)
return -EINVAL;
/*
@@ -894,6 +909,10 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (params.key_len != 13)
return -EINVAL;
break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ if (params.key_len != 16)
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
@@ -928,7 +947,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_KEY_IDX])
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
- if (key_idx > 3)
+ if (key_idx > 5)
return -EINVAL;
if (info->attrs[NL80211_ATTR_MAC])
@@ -1889,6 +1908,11 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
mutex_lock(&cfg80211_drv_mutex);
r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
mutex_unlock(&cfg80211_drv_mutex);
+ /* This means the regulatory domain was already set, however
+ * we don't want to confuse userspace with a "successful error"
+ * message so lets just treat it as a success */
+ if (r == -EALREADY)
+ r = 0;
return r;
}
@@ -2134,6 +2158,43 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
+static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct mgmt_extra_ie_params params;
+
+ memset(&params, 0, sizeof(params));
+
+ if (!info->attrs[NL80211_ATTR_MGMT_SUBTYPE])
+ return -EINVAL;
+ params.subtype = nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
+ if (params.subtype > 15)
+ return -EINVAL; /* FC Subtype field is 4 bits (0..15) */
+
+ if (info->attrs[NL80211_ATTR_IE]) {
+ params.ies = nla_data(info->attrs[NL80211_ATTR_IE]);
+ params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ }
+
+ err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ if (err)
+ return err;
+
+ if (drv->ops->set_mgmt_extra_ie) {
+ rtnl_lock();
+ err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, &params);
+ rtnl_unlock();
+ } else
+ err = -EOPNOTSUPP;
+
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -2295,6 +2356,12 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_SET_MGMT_EXTRA_IE,
+ .doit = nl80211_set_mgmt_extra_ie,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
/* multicast groups */
OpenPOWER on IntegriCloud