diff options
author | Kyeyoon Park <kyeyoonp@qca.qualcomm.com> | 2013-12-17 02:01:30 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-12-19 10:29:22 -0500 |
commit | fa9ffc745610f31c6bc136d5a6a1782e00870e72 (patch) | |
tree | adb2799c4d6a78a95d291582a02c42027b2527c2 /net/wireless/nl80211.c | |
parent | 567ffc3509b2d3f965a49a18631d3da7f9a96d4f (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.c | 62 |
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) | |||
9121 | EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply); | 9124 | EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply); |
9122 | 9125 | ||
9123 | 9126 | ||
9127 | static 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 */ |