mirror of
https://github.com/S3NEO/android_kernel_samsung_msm8226.git
synced 2024-11-07 03:47:13 +00:00
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). CRs-fixed: 650927 Change-Id: I72ab05c7aa98528b05f6278df192cc25358c2666 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> Git-commit: fa9ffc745610f31c6bc136d5a6a1782e00870e72 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git [ppotte@codeaurora.org: manually solved merge conflicts] Signed-off-by: Pradeep Reddy POTTETI <ppotte@codeaurora.org>
This commit is contained in:
parent
4b04b0842a
commit
1368a38cd0
8 changed files with 162 additions and 4 deletions
|
@ -637,6 +637,12 @@
|
||||||
* (&struct nl80211_vendor_cmd_info) of the supported vendor commands.
|
* (&struct nl80211_vendor_cmd_info) of the supported vendor commands.
|
||||||
* This may also be sent as an event with the same attributes.
|
* This may also be sent as an event with the same attributes.
|
||||||
*
|
*
|
||||||
|
* @NL80211_CMD_SET_QOS_MAP: Set Interworking QoS mapping for IP DSCP values.
|
||||||
|
* The QoS mapping information is included in %NL80211_ATTR_QOS_MAP. If
|
||||||
|
* that attribute is not included, QoS mapping is disabled. Since this
|
||||||
|
* QoS mapping is relevant for IP packets, it is only valid during an
|
||||||
|
* association. This is cleared on disassociation and AP restart.
|
||||||
|
*
|
||||||
* @NL80211_CMD_MAX: highest used command number
|
* @NL80211_CMD_MAX: highest used command number
|
||||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||||
*/
|
*/
|
||||||
|
@ -807,6 +813,8 @@ enum nl80211_commands {
|
||||||
|
|
||||||
NL80211_CMD_VENDOR,
|
NL80211_CMD_VENDOR,
|
||||||
|
|
||||||
|
NL80211_CMD_SET_QOS_MAP,
|
||||||
|
|
||||||
/* add new commands above here */
|
/* add new commands above here */
|
||||||
|
|
||||||
/* used to define NL80211_CMD_MAX below */
|
/* used to define NL80211_CMD_MAX below */
|
||||||
|
@ -1446,6 +1454,10 @@ enum nl80211_commands {
|
||||||
* @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy
|
* @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy
|
||||||
* info, containing a nested array of possible events
|
* info, containing a nested array of possible events
|
||||||
*
|
*
|
||||||
|
* @NL80211_ATTR_QOS_MAP: IP DSCP mapping for Interworking QoS mapping. This
|
||||||
|
* data is in the format defined for the payload of the QoS Map Set element
|
||||||
|
* in IEEE Std 802.11-2012, 8.4.2.97.
|
||||||
|
*
|
||||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||||
*/
|
*/
|
||||||
|
@ -1773,6 +1785,8 @@ enum nl80211_attrs {
|
||||||
|
|
||||||
NL80211_ATTR_VENDOR_EVENTS,
|
NL80211_ATTR_VENDOR_EVENTS,
|
||||||
|
|
||||||
|
NL80211_ATTR_QOS_MAP,
|
||||||
|
|
||||||
/* add attributes here, update the policy in nl80211.c */
|
/* add attributes here, update the policy in nl80211.c */
|
||||||
|
|
||||||
__NL80211_ATTR_AFTER_LAST,
|
__NL80211_ATTR_AFTER_LAST,
|
||||||
|
|
|
@ -1406,6 +1406,50 @@ struct cfg80211_update_ft_ies_params {
|
||||||
size_t ie_len;
|
size_t ie_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct cfg80211_dscp_exception - DSCP exception
|
||||||
|
*
|
||||||
|
* @dscp: DSCP value that does not adhere to the user priority range definition
|
||||||
|
* @up: user priority value to which the corresponding DSCP value belongs
|
||||||
|
*/
|
||||||
|
struct cfg80211_dscp_exception {
|
||||||
|
u8 dscp;
|
||||||
|
u8 up;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct cfg80211_dscp_range - DSCP range definition for user priority
|
||||||
|
*
|
||||||
|
* @low: lowest DSCP value of this user priority range, inclusive
|
||||||
|
* @high: highest DSCP value of this user priority range, inclusive
|
||||||
|
*/
|
||||||
|
struct cfg80211_dscp_range {
|
||||||
|
u8 low;
|
||||||
|
u8 high;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* QoS Map Set element length defined in IEEE Std 802.11-2012, 8.4.2.97 */
|
||||||
|
#define IEEE80211_QOS_MAP_MAX_EX 21
|
||||||
|
#define IEEE80211_QOS_MAP_LEN_MIN 16
|
||||||
|
#define IEEE80211_QOS_MAP_LEN_MAX \
|
||||||
|
(IEEE80211_QOS_MAP_LEN_MIN + 2 * IEEE80211_QOS_MAP_MAX_EX)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct cfg80211_qos_map - QoS Map Information
|
||||||
|
*
|
||||||
|
* This struct defines the Interworking QoS map setting for DSCP values
|
||||||
|
*
|
||||||
|
* @num_des: number of DSCP exceptions (0..21)
|
||||||
|
* @dscp_exception: optionally up to maximum of 21 DSCP exceptions from
|
||||||
|
* the user priority DSCP range definition
|
||||||
|
* @up: DSCP range definition for a particular user priority
|
||||||
|
*/
|
||||||
|
struct cfg80211_qos_map {
|
||||||
|
u8 num_des;
|
||||||
|
struct cfg80211_dscp_exception dscp_exception[IEEE80211_QOS_MAP_MAX_EX];
|
||||||
|
struct cfg80211_dscp_range up[8];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct cfg80211_ops - backend description for wireless configuration
|
* struct cfg80211_ops - backend description for wireless configuration
|
||||||
*
|
*
|
||||||
|
@ -1597,6 +1641,7 @@ struct cfg80211_update_ft_ies_params {
|
||||||
* when number of MAC addresses entries is passed as 0. Drivers which
|
* when number of MAC addresses entries is passed as 0. Drivers which
|
||||||
* advertise the support for MAC based ACL have to implement this callback.
|
* advertise the support for MAC based ACL have to implement this callback.
|
||||||
*
|
*
|
||||||
|
* @set_qos_map: Set QoS mapping information to the driver
|
||||||
*/
|
*/
|
||||||
struct cfg80211_ops {
|
struct cfg80211_ops {
|
||||||
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
|
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
|
||||||
|
@ -1798,6 +1843,10 @@ struct cfg80211_ops {
|
||||||
|
|
||||||
int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
|
int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
|
||||||
const struct cfg80211_acl_data *params);
|
const struct cfg80211_acl_data *params);
|
||||||
|
int (*set_qos_map)(struct wiphy *wiphy,
|
||||||
|
struct net_device *dev,
|
||||||
|
struct cfg80211_qos_map *qos_map);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2705,8 +2754,10 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
||||||
/**
|
/**
|
||||||
* cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
|
* cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
|
||||||
* @skb: the data frame
|
* @skb: the data frame
|
||||||
|
* @qos_map: Interworking QoS mapping or %NULL if not in use
|
||||||
*/
|
*/
|
||||||
unsigned int cfg80211_classify8021d(struct sk_buff *skb);
|
unsigned int cfg80211_classify8021d(struct sk_buff *skb,
|
||||||
|
struct cfg80211_qos_map *qos_map);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cfg80211_find_ie - find information element in data
|
* cfg80211_find_ie - find information element in data
|
||||||
|
|
|
@ -134,7 +134,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
/* use the data classifier to determine what 802.1d tag the
|
/* use the data classifier to determine what 802.1d tag the
|
||||||
* data frame has */
|
* data frame has */
|
||||||
skb->priority = cfg80211_classify8021d(skb);
|
skb->priority = cfg80211_classify8021d(skb, NULL);
|
||||||
|
|
||||||
return ieee80211_downgrade_queue(local, skb);
|
return ieee80211_downgrade_queue(local, skb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,6 +155,10 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
|
||||||
kfree(wdev->connect_keys);
|
kfree(wdev->connect_keys);
|
||||||
wdev->connect_keys = NULL;
|
wdev->connect_keys = NULL;
|
||||||
|
|
||||||
|
if (rdev->ops->set_qos_map) {
|
||||||
|
rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delete all the keys ... pairwise keys can't really
|
* Delete all the keys ... pairwise keys can't really
|
||||||
* exist any more anyway, but default keys might.
|
* exist any more anyway, but default keys might.
|
||||||
|
|
|
@ -152,8 +152,12 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
|
||||||
return -ENOTCONN;
|
return -ENOTCONN;
|
||||||
|
|
||||||
err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
|
err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
|
||||||
if (!err)
|
if (!err) {
|
||||||
wdev->mesh_id_len = 0;
|
wdev->mesh_id_len = 0;
|
||||||
|
if (rdev->ops->set_qos_map) {
|
||||||
|
rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
||||||
[NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
|
[NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
|
[NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
|
[NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
|
||||||
|
[NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
|
||||||
|
.len = IEEE80211_QOS_MAP_LEN_MAX },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* policy for the key attributes */
|
/* policy for the key attributes */
|
||||||
|
@ -950,6 +952,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||||
i++;
|
i++;
|
||||||
NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
|
NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
|
||||||
}
|
}
|
||||||
|
CMD(set_qos_map, SET_QOS_MAP);
|
||||||
|
|
||||||
#ifdef CONFIG_NL80211_TESTMODE
|
#ifdef CONFIG_NL80211_TESTMODE
|
||||||
CMD(testmode_cmd, TESTMODE);
|
CMD(testmode_cmd, TESTMODE);
|
||||||
|
@ -6796,6 +6799,57 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cfg80211_vendor_cmd_reply);
|
EXPORT_SYMBOL(cfg80211_vendor_cmd_reply);
|
||||||
|
|
||||||
|
static int nl80211_set_qos_map(struct sk_buff *skb,
|
||||||
|
struct genl_info *info)
|
||||||
|
{
|
||||||
|
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||||
|
struct cfg80211_qos_map *qos_map = NULL;
|
||||||
|
struct net_device *dev = info->user_ptr[1];
|
||||||
|
u8 *pos, len, num_des, des_len, des;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!rdev->ops->set_qos_map)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (info->attrs[NL80211_ATTR_QOS_MAP]) {
|
||||||
|
pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
|
||||||
|
len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
|
||||||
|
|
||||||
|
if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
|
||||||
|
len > IEEE80211_QOS_MAP_LEN_MAX)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
|
||||||
|
if (!qos_map)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
|
||||||
|
if (num_des) {
|
||||||
|
des_len = num_des *
|
||||||
|
sizeof(struct cfg80211_dscp_exception);
|
||||||
|
memcpy(qos_map->dscp_exception, pos, des_len);
|
||||||
|
qos_map->num_des = num_des;
|
||||||
|
for (des = 0; des < num_des; des++) {
|
||||||
|
if (qos_map->dscp_exception[des].up > 7) {
|
||||||
|
kfree(qos_map);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos += des_len;
|
||||||
|
}
|
||||||
|
memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
wdev_lock(dev->ieee80211_ptr);
|
||||||
|
ret = nl80211_key_allowed(dev->ieee80211_ptr);
|
||||||
|
if (!ret)
|
||||||
|
ret = rdev->ops->set_qos_map(&rdev->wiphy, dev, qos_map);
|
||||||
|
wdev_unlock(dev->ieee80211_ptr);
|
||||||
|
|
||||||
|
kfree(qos_map);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#define NL80211_FLAG_NEED_WIPHY 0x01
|
#define NL80211_FLAG_NEED_WIPHY 0x01
|
||||||
#define NL80211_FLAG_NEED_NETDEV 0x02
|
#define NL80211_FLAG_NEED_NETDEV 0x02
|
||||||
#define NL80211_FLAG_NEED_RTNL 0x04
|
#define NL80211_FLAG_NEED_RTNL 0x04
|
||||||
|
@ -7408,6 +7462,14 @@ static struct genl_ops nl80211_ops[] = {
|
||||||
.internal_flags = NL80211_FLAG_NEED_NETDEV |
|
.internal_flags = NL80211_FLAG_NEED_NETDEV |
|
||||||
NL80211_FLAG_NEED_RTNL,
|
NL80211_FLAG_NEED_RTNL,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.cmd = NL80211_CMD_SET_QOS_MAP,
|
||||||
|
.doit = nl80211_set_qos_map,
|
||||||
|
.policy = nl80211_policy,
|
||||||
|
.flags = GENL_ADMIN_PERM,
|
||||||
|
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||||
|
NL80211_FLAG_NEED_RTNL,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct genl_multicast_group nl80211_mlme_mcgrp = {
|
static struct genl_multicast_group nl80211_mlme_mcgrp = {
|
||||||
|
|
|
@ -721,6 +721,10 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
||||||
for (i = 0; i < 6; i++)
|
for (i = 0; i < 6; i++)
|
||||||
rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
|
rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
|
||||||
|
|
||||||
|
if (rdev->ops->set_qos_map) {
|
||||||
|
rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CFG80211_WEXT
|
#ifdef CONFIG_CFG80211_WEXT
|
||||||
memset(&wrqu, 0, sizeof(wrqu));
|
memset(&wrqu, 0, sizeof(wrqu));
|
||||||
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||||||
|
|
|
@ -641,7 +641,8 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
||||||
EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
|
EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
|
||||||
|
|
||||||
/* Given a data frame determine the 802.1p/1d tag to use. */
|
/* Given a data frame determine the 802.1p/1d tag to use. */
|
||||||
unsigned int cfg80211_classify8021d(struct sk_buff *skb)
|
unsigned int cfg80211_classify8021d(struct sk_buff *skb,
|
||||||
|
struct cfg80211_qos_map *qos_map)
|
||||||
{
|
{
|
||||||
unsigned int dscp;
|
unsigned int dscp;
|
||||||
|
|
||||||
|
@ -664,6 +665,21 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (qos_map) {
|
||||||
|
unsigned int i, tmp_dscp = dscp >> 2;
|
||||||
|
|
||||||
|
for (i = 0; i < qos_map->num_des; i++) {
|
||||||
|
if (tmp_dscp == qos_map->dscp_exception[i].dscp)
|
||||||
|
return qos_map->dscp_exception[i].up;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
if (tmp_dscp >= qos_map->up[i].low &&
|
||||||
|
tmp_dscp <= qos_map->up[i].high)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return dscp >> 5;
|
return dscp >> 5;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cfg80211_classify8021d);
|
EXPORT_SYMBOL(cfg80211_classify8021d);
|
||||||
|
@ -817,6 +833,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||||
|
|
||||||
dev->ieee80211_ptr->use_4addr = false;
|
dev->ieee80211_ptr->use_4addr = false;
|
||||||
dev->ieee80211_ptr->mesh_id_up_len = 0;
|
dev->ieee80211_ptr->mesh_id_up_len = 0;
|
||||||
|
if (rdev->ops->set_qos_map) {
|
||||||
|
rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
switch (otype) {
|
switch (otype) {
|
||||||
case NL80211_IFTYPE_ADHOC:
|
case NL80211_IFTYPE_ADHOC:
|
||||||
|
|
Loading…
Reference in a new issue