aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c160
1 files changed, 141 insertions, 19 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 04681a46eda8..b4f40fe84a01 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -53,6 +53,7 @@ enum nl80211_multicast_groups {
53 NL80211_MCGRP_SCAN, 53 NL80211_MCGRP_SCAN,
54 NL80211_MCGRP_REGULATORY, 54 NL80211_MCGRP_REGULATORY,
55 NL80211_MCGRP_MLME, 55 NL80211_MCGRP_MLME,
56 NL80211_MCGRP_VENDOR,
56 NL80211_MCGRP_TESTMODE /* keep last - ifdef! */ 57 NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
57}; 58};
58 59
@@ -61,6 +62,7 @@ static const struct genl_multicast_group nl80211_mcgrps[] = {
61 [NL80211_MCGRP_SCAN] = { .name = "scan", }, 62 [NL80211_MCGRP_SCAN] = { .name = "scan", },
62 [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", }, 63 [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", },
63 [NL80211_MCGRP_MLME] = { .name = "mlme", }, 64 [NL80211_MCGRP_MLME] = { .name = "mlme", },
65 [NL80211_MCGRP_VENDOR] = { .name = "vendor", },
64#ifdef CONFIG_NL80211_TESTMODE 66#ifdef CONFIG_NL80211_TESTMODE
65 [NL80211_MCGRP_TESTMODE] = { .name = "testmode", } 67 [NL80211_MCGRP_TESTMODE] = { .name = "testmode", }
66#endif 68#endif
@@ -380,6 +382,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
380 [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 }, 382 [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
381 [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 }, 383 [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
382 [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 },
383}; 387};
384 388
385/* policy for the key attributes */ 389/* policy for the key attributes */
@@ -1188,7 +1192,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
1188 struct nlattr *nl_bands, *nl_band; 1192 struct nlattr *nl_bands, *nl_band;
1189 struct nlattr *nl_freqs, *nl_freq; 1193 struct nlattr *nl_freqs, *nl_freq;
1190 struct nlattr *nl_cmds; 1194 struct nlattr *nl_cmds;
1191 struct nlattr *nl_vendor_cmds;
1192 enum ieee80211_band band; 1195 enum ieee80211_band band;
1193 struct ieee80211_channel *chan; 1196 struct ieee80211_channel *chan;
1194 int i; 1197 int i;
@@ -1455,6 +1458,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
1455 if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) 1458 if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
1456 CMD(channel_switch, CHANNEL_SWITCH); 1459 CMD(channel_switch, CHANNEL_SWITCH);
1457 } 1460 }
1461 CMD(set_qos_map, SET_QOS_MAP);
1458 1462
1459#ifdef CONFIG_NL80211_TESTMODE 1463#ifdef CONFIG_NL80211_TESTMODE
1460 CMD(testmode_cmd, TESTMODE); 1464 CMD(testmode_cmd, TESTMODE);
@@ -1587,16 +1591,38 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
1587 state->split_start++; 1591 state->split_start++;
1588 break; 1592 break;
1589 case 11: 1593 case 11:
1590 nl_vendor_cmds = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); 1594 if (dev->wiphy.n_vendor_commands) {
1591 if (!nl_vendor_cmds) 1595 const struct nl80211_vendor_cmd_info *info;
1592 goto nla_put_failure; 1596 struct nlattr *nested;
1597
1598 nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
1599 if (!nested)
1600 goto nla_put_failure;
1601
1602 for (i = 0; i < dev->wiphy.n_vendor_commands; i++) {
1603 info = &dev->wiphy.vendor_commands[i].info;
1604 if (nla_put(msg, i + 1, sizeof(*info), info))
1605 goto nla_put_failure;
1606 }
1607 nla_nest_end(msg, nested);
1608 }
1609
1610 if (dev->wiphy.n_vendor_events) {
1611 const struct nl80211_vendor_cmd_info *info;
1612 struct nlattr *nested;
1593 1613
1594 for (i = 0; i < dev->wiphy.n_vendor_commands; i++) 1614 nested = nla_nest_start(msg,
1595 if (nla_put(msg, i + 1, 1615 NL80211_ATTR_VENDOR_EVENTS);
1596 sizeof(struct nl80211_vendor_cmd_info), 1616 if (!nested)
1597 &dev->wiphy.vendor_commands[i].info))
1598 goto nla_put_failure; 1617 goto nla_put_failure;
1599 nla_nest_end(msg, nl_vendor_cmds); 1618
1619 for (i = 0; i < dev->wiphy.n_vendor_events; i++) {
1620 info = &dev->wiphy.vendor_events[i];
1621 if (nla_put(msg, i + 1, sizeof(*info), info))
1622 goto nla_put_failure;
1623 }
1624 nla_nest_end(msg, nested);
1625 }
1600 1626
1601 /* done */ 1627 /* done */
1602 state->split_start = 0; 1628 state->split_start = 0;
@@ -6726,7 +6752,9 @@ static struct sk_buff *
6726__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, 6752__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
6727 int approxlen, u32 portid, u32 seq, 6753 int approxlen, u32 portid, u32 seq,
6728 enum nl80211_commands cmd, 6754 enum nl80211_commands cmd,
6729 enum nl80211_attrs attr, gfp_t gfp) 6755 enum nl80211_attrs attr,
6756 const struct nl80211_vendor_cmd_info *info,
6757 gfp_t gfp)
6730{ 6758{
6731 struct sk_buff *skb; 6759 struct sk_buff *skb;
6732 void *hdr; 6760 void *hdr;
@@ -6744,6 +6772,16 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
6744 6772
6745 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) 6773 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
6746 goto nla_put_failure; 6774 goto nla_put_failure;
6775
6776 if (info) {
6777 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
6778 info->vendor_id))
6779 goto nla_put_failure;
6780 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
6781 info->subcmd))
6782 goto nla_put_failure;
6783 }
6784
6747 data = nla_nest_start(skb, attr); 6785 data = nla_nest_start(skb, attr);
6748 6786
6749 ((void **)skb->cb)[0] = rdev; 6787 ((void **)skb->cb)[0] = rdev;
@@ -6884,29 +6922,54 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
6884 return err; 6922 return err;
6885} 6923}
6886 6924
6887struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, 6925struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
6888 int approxlen, gfp_t gfp) 6926 enum nl80211_commands cmd,
6927 enum nl80211_attrs attr,
6928 int vendor_event_idx,
6929 int approxlen, gfp_t gfp)
6889{ 6930{
6890 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 6931 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
6932 const struct nl80211_vendor_cmd_info *info;
6933
6934 switch (cmd) {
6935 case NL80211_CMD_TESTMODE:
6936 if (WARN_ON(vendor_event_idx != -1))
6937 return NULL;
6938 info = NULL;
6939 break;
6940 case NL80211_CMD_VENDOR:
6941 if (WARN_ON(vendor_event_idx < 0 ||
6942 vendor_event_idx >= wiphy->n_vendor_events))
6943 return NULL;
6944 info = &wiphy->vendor_events[vendor_event_idx];
6945 break;
6946 default:
6947 WARN_ON(1);
6948 return NULL;
6949 }
6891 6950
6892 return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0, 6951 return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
6893 NL80211_CMD_TESTMODE, 6952 cmd, attr, info, gfp);
6894 NL80211_ATTR_TESTDATA, gfp);
6895} 6953}
6896EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb); 6954EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
6897 6955
6898void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) 6956void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
6899{ 6957{
6900 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; 6958 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
6901 void *hdr = ((void **)skb->cb)[1]; 6959 void *hdr = ((void **)skb->cb)[1];
6902 struct nlattr *data = ((void **)skb->cb)[2]; 6960 struct nlattr *data = ((void **)skb->cb)[2];
6961 enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
6903 6962
6904 nla_nest_end(skb, data); 6963 nla_nest_end(skb, data);
6905 genlmsg_end(skb, hdr); 6964 genlmsg_end(skb, hdr);
6965
6966 if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
6967 mcgrp = NL80211_MCGRP_VENDOR;
6968
6906 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0, 6969 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
6907 NL80211_MCGRP_TESTMODE, gfp); 6970 mcgrp, gfp);
6908} 6971}
6909EXPORT_SYMBOL(cfg80211_testmode_event); 6972EXPORT_SYMBOL(__cfg80211_send_event_skb);
6910#endif 6973#endif
6911 6974
6912static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) 6975static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
@@ -9039,7 +9102,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
9039 return __cfg80211_alloc_vendor_skb(rdev, approxlen, 9102 return __cfg80211_alloc_vendor_skb(rdev, approxlen,
9040 rdev->cur_cmd_info->snd_portid, 9103 rdev->cur_cmd_info->snd_portid,
9041 rdev->cur_cmd_info->snd_seq, 9104 rdev->cur_cmd_info->snd_seq,
9042 cmd, attr, GFP_KERNEL); 9105 cmd, attr, NULL, GFP_KERNEL);
9043} 9106}
9044EXPORT_SYMBOL(__cfg80211_alloc_reply_skb); 9107EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
9045 9108
@@ -9061,6 +9124,57 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
9061EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply); 9124EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
9062 9125
9063 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
9064#define NL80211_FLAG_NEED_WIPHY 0x01 9178#define NL80211_FLAG_NEED_WIPHY 0x01
9065#define NL80211_FLAG_NEED_NETDEV 0x02 9179#define NL80211_FLAG_NEED_NETDEV 0x02
9066#define NL80211_FLAG_NEED_RTNL 0x04 9180#define NL80211_FLAG_NEED_RTNL 0x04
@@ -9793,6 +9907,14 @@ static const struct genl_ops nl80211_ops[] = {
9793 .internal_flags = NL80211_FLAG_NEED_WIPHY | 9907 .internal_flags = NL80211_FLAG_NEED_WIPHY |
9794 NL80211_FLAG_NEED_RTNL, 9908 NL80211_FLAG_NEED_RTNL,
9795 }, 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 },
9796}; 9918};
9797 9919
9798/* notification functions */ 9920/* notification functions */