aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorKyeyoon Park <kyeyoonp@qca.qualcomm.com>2013-12-17 02:01:30 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-12-19 10:29:22 -0500
commitfa9ffc745610f31c6bc136d5a6a1782e00870e72 (patch)
treeadb2799c4d6a78a95d291582a02c42027b2527c2 /net/wireless/nl80211.c
parent567ffc3509b2d3f965a49a18631d3da7f9a96d4f (diff)
cfg80211: Add support for QoS mapping
This allows QoS mapping from external networks to be implemented as defined in IEEE Std 802.11-2012, 10.24.9. APs can use this to advertise DSCP ranges and exceptions for mapping frames to a specific UP over Wi-Fi. The payload of the QoS Map Set element (IEEE Std 802.11-2012, 8.4.2.97) is sent to the driver through the new NL80211_ATTR_QOS_MAP attribute to configure the local behavior either on the AP (based on local configuration) or on a station (based on information received from the AP). Signed-off-by: Kyeyoon Park <kyeyoonp@qca.qualcomm.com> Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8a7ff041349b..b4f40fe84a01 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -382,6 +382,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
382 [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 }, 382 [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
383 [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 }, 383 [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
384 [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, 384 [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
385 [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
386 .len = IEEE80211_QOS_MAP_LEN_MAX },
385}; 387};
386 388
387/* policy for the key attributes */ 389/* policy for the key attributes */
@@ -1456,6 +1458,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
1456 if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) 1458 if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
1457 CMD(channel_switch, CHANNEL_SWITCH); 1459 CMD(channel_switch, CHANNEL_SWITCH);
1458 } 1460 }
1461 CMD(set_qos_map, SET_QOS_MAP);
1459 1462
1460#ifdef CONFIG_NL80211_TESTMODE 1463#ifdef CONFIG_NL80211_TESTMODE
1461 CMD(testmode_cmd, TESTMODE); 1464 CMD(testmode_cmd, TESTMODE);
@@ -9121,6 +9124,57 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
9121EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply); 9124EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
9122 9125
9123 9126
9127static int nl80211_set_qos_map(struct sk_buff *skb,
9128 struct genl_info *info)
9129{
9130 struct cfg80211_registered_device *rdev = info->user_ptr[0];
9131 struct cfg80211_qos_map *qos_map = NULL;
9132 struct net_device *dev = info->user_ptr[1];
9133 u8 *pos, len, num_des, des_len, des;
9134 int ret;
9135
9136 if (!rdev->ops->set_qos_map)
9137 return -EOPNOTSUPP;
9138
9139 if (info->attrs[NL80211_ATTR_QOS_MAP]) {
9140 pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
9141 len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
9142
9143 if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
9144 len > IEEE80211_QOS_MAP_LEN_MAX)
9145 return -EINVAL;
9146
9147 qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
9148 if (!qos_map)
9149 return -ENOMEM;
9150
9151 num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
9152 if (num_des) {
9153 des_len = num_des *
9154 sizeof(struct cfg80211_dscp_exception);
9155 memcpy(qos_map->dscp_exception, pos, des_len);
9156 qos_map->num_des = num_des;
9157 for (des = 0; des < num_des; des++) {
9158 if (qos_map->dscp_exception[des].up > 7) {
9159 kfree(qos_map);
9160 return -EINVAL;
9161 }
9162 }
9163 pos += des_len;
9164 }
9165 memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
9166 }
9167
9168 wdev_lock(dev->ieee80211_ptr);
9169 ret = nl80211_key_allowed(dev->ieee80211_ptr);
9170 if (!ret)
9171 ret = rdev_set_qos_map(rdev, dev, qos_map);
9172 wdev_unlock(dev->ieee80211_ptr);
9173
9174 kfree(qos_map);
9175 return ret;
9176}
9177
9124#define NL80211_FLAG_NEED_WIPHY 0x01 9178#define NL80211_FLAG_NEED_WIPHY 0x01
9125#define NL80211_FLAG_NEED_NETDEV 0x02 9179#define NL80211_FLAG_NEED_NETDEV 0x02
9126#define NL80211_FLAG_NEED_RTNL 0x04 9180#define NL80211_FLAG_NEED_RTNL 0x04
@@ -9853,6 +9907,14 @@ static const struct genl_ops nl80211_ops[] = {
9853 .internal_flags = NL80211_FLAG_NEED_WIPHY | 9907 .internal_flags = NL80211_FLAG_NEED_WIPHY |
9854 NL80211_FLAG_NEED_RTNL, 9908 NL80211_FLAG_NEED_RTNL,
9855 }, 9909 },
9910 {
9911 .cmd = NL80211_CMD_SET_QOS_MAP,
9912 .doit = nl80211_set_qos_map,
9913 .policy = nl80211_policy,
9914 .flags = GENL_ADMIN_PERM,
9915 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
9916 NL80211_FLAG_NEED_RTNL,
9917 },
9856}; 9918};
9857 9919
9858/* notification functions */ 9920/* notification functions */