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.c286
1 files changed, 229 insertions, 57 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ca3c92a0a14f..149539ade15e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -138,6 +138,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
138 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, 138 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
139 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, 139 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
140 [NL80211_ATTR_PID] = { .type = NLA_U32 }, 140 [NL80211_ATTR_PID] = { .type = NLA_U32 },
141 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
141}; 142};
142 143
143/* policy for the attributes */ 144/* policy for the attributes */
@@ -151,6 +152,26 @@ nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
151 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, 152 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
152}; 153};
153 154
155/* ifidx get helper */
156static int nl80211_get_ifidx(struct netlink_callback *cb)
157{
158 int res;
159
160 res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
161 nl80211_fam.attrbuf, nl80211_fam.maxattr,
162 nl80211_policy);
163 if (res)
164 return res;
165
166 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
167 return -EINVAL;
168
169 res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
170 if (!res)
171 return -EINVAL;
172 return res;
173}
174
154/* IE validation */ 175/* IE validation */
155static bool is_valid_ie_attr(const struct nlattr *attr) 176static bool is_valid_ie_attr(const struct nlattr *attr)
156{ 177{
@@ -540,7 +561,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
540 CMD(deauth, DEAUTHENTICATE); 561 CMD(deauth, DEAUTHENTICATE);
541 CMD(disassoc, DISASSOCIATE); 562 CMD(disassoc, DISASSOCIATE);
542 CMD(join_ibss, JOIN_IBSS); 563 CMD(join_ibss, JOIN_IBSS);
543 if (dev->wiphy.netnsok) { 564 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
544 i++; 565 i++;
545 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 566 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
546 } 567 }
@@ -947,6 +968,32 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
947 return 0; 968 return 0;
948} 969}
949 970
971static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
972 struct net_device *netdev, u8 use_4addr,
973 enum nl80211_iftype iftype)
974{
975 if (!use_4addr) {
976 if (netdev && netdev->br_port)
977 return -EBUSY;
978 return 0;
979 }
980
981 switch (iftype) {
982 case NL80211_IFTYPE_AP_VLAN:
983 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
984 return 0;
985 break;
986 case NL80211_IFTYPE_STATION:
987 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
988 return 0;
989 break;
990 default:
991 break;
992 }
993
994 return -EOPNOTSUPP;
995}
996
950static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) 997static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
951{ 998{
952 struct cfg80211_registered_device *rdev; 999 struct cfg80211_registered_device *rdev;
@@ -987,6 +1034,16 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
987 change = true; 1034 change = true;
988 } 1035 }
989 1036
1037 if (info->attrs[NL80211_ATTR_4ADDR]) {
1038 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1039 change = true;
1040 err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
1041 if (err)
1042 goto unlock;
1043 } else {
1044 params.use_4addr = -1;
1045 }
1046
990 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { 1047 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
991 if (ntype != NL80211_IFTYPE_MONITOR) { 1048 if (ntype != NL80211_IFTYPE_MONITOR) {
992 err = -EINVAL; 1049 err = -EINVAL;
@@ -1006,6 +1063,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
1006 else 1063 else
1007 err = 0; 1064 err = 0;
1008 1065
1066 if (!err && params.use_4addr != -1)
1067 dev->ieee80211_ptr->use_4addr = params.use_4addr;
1068
1009 unlock: 1069 unlock:
1010 dev_put(dev); 1070 dev_put(dev);
1011 cfg80211_unlock_rdev(rdev); 1071 cfg80211_unlock_rdev(rdev);
@@ -1053,6 +1113,13 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
1053 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 1113 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
1054 } 1114 }
1055 1115
1116 if (info->attrs[NL80211_ATTR_4ADDR]) {
1117 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1118 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
1119 if (err)
1120 goto unlock;
1121 }
1122
1056 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? 1123 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
1057 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, 1124 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
1058 &flags); 1125 &flags);
@@ -1264,7 +1331,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
1264 if (!err) 1331 if (!err)
1265 err = func(&rdev->wiphy, dev, key.idx); 1332 err = func(&rdev->wiphy, dev, key.idx);
1266 1333
1267#ifdef CONFIG_WIRELESS_EXT 1334#ifdef CONFIG_CFG80211_WEXT
1268 if (!err) { 1335 if (!err) {
1269 if (func == rdev->ops->set_default_key) 1336 if (func == rdev->ops->set_default_key)
1270 dev->ieee80211_ptr->wext.default_key = key.idx; 1337 dev->ieee80211_ptr->wext.default_key = key.idx;
@@ -1365,7 +1432,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
1365 if (!err) 1432 if (!err)
1366 err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); 1433 err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
1367 1434
1368#ifdef CONFIG_WIRELESS_EXT 1435#ifdef CONFIG_CFG80211_WEXT
1369 if (!err) { 1436 if (!err) {
1370 if (key.idx == dev->ieee80211_ptr->wext.default_key) 1437 if (key.idx == dev->ieee80211_ptr->wext.default_key)
1371 dev->ieee80211_ptr->wext.default_key = -1; 1438 dev->ieee80211_ptr->wext.default_key = -1;
@@ -1682,20 +1749,10 @@ static int nl80211_dump_station(struct sk_buff *skb,
1682 int sta_idx = cb->args[1]; 1749 int sta_idx = cb->args[1];
1683 int err; 1750 int err;
1684 1751
1685 if (!ifidx) { 1752 if (!ifidx)
1686 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, 1753 ifidx = nl80211_get_ifidx(cb);
1687 nl80211_fam.attrbuf, nl80211_fam.maxattr, 1754 if (ifidx < 0)
1688 nl80211_policy); 1755 return ifidx;
1689 if (err)
1690 return err;
1691
1692 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
1693 return -EINVAL;
1694
1695 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
1696 if (!ifidx)
1697 return -EINVAL;
1698 }
1699 1756
1700 rtnl_lock(); 1757 rtnl_lock();
1701 1758
@@ -1800,7 +1857,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
1800} 1857}
1801 1858
1802/* 1859/*
1803 * Get vlan interface making sure it is on the right wiphy. 1860 * Get vlan interface making sure it is running and on the right wiphy.
1804 */ 1861 */
1805static int get_vlan(struct genl_info *info, 1862static int get_vlan(struct genl_info *info,
1806 struct cfg80211_registered_device *rdev, 1863 struct cfg80211_registered_device *rdev,
@@ -1818,6 +1875,8 @@ static int get_vlan(struct genl_info *info,
1818 return -EINVAL; 1875 return -EINVAL;
1819 if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) 1876 if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
1820 return -EINVAL; 1877 return -EINVAL;
1878 if (!netif_running(*vlan))
1879 return -ENETDOWN;
1821 } 1880 }
1822 return 0; 1881 return 0;
1823} 1882}
@@ -2105,9 +2164,9 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
2105 if (pinfo->filled & MPATH_INFO_FRAME_QLEN) 2164 if (pinfo->filled & MPATH_INFO_FRAME_QLEN)
2106 NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, 2165 NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
2107 pinfo->frame_qlen); 2166 pinfo->frame_qlen);
2108 if (pinfo->filled & MPATH_INFO_DSN) 2167 if (pinfo->filled & MPATH_INFO_SN)
2109 NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, 2168 NLA_PUT_U32(msg, NL80211_MPATH_INFO_SN,
2110 pinfo->dsn); 2169 pinfo->sn);
2111 if (pinfo->filled & MPATH_INFO_METRIC) 2170 if (pinfo->filled & MPATH_INFO_METRIC)
2112 NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, 2171 NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC,
2113 pinfo->metric); 2172 pinfo->metric);
@@ -2145,20 +2204,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
2145 int path_idx = cb->args[1]; 2204 int path_idx = cb->args[1];
2146 int err; 2205 int err;
2147 2206
2148 if (!ifidx) { 2207 if (!ifidx)
2149 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, 2208 ifidx = nl80211_get_ifidx(cb);
2150 nl80211_fam.attrbuf, nl80211_fam.maxattr, 2209 if (ifidx < 0)
2151 nl80211_policy); 2210 return ifidx;
2152 if (err)
2153 return err;
2154
2155 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
2156 return -EINVAL;
2157
2158 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
2159 if (!ifidx)
2160 return -EINVAL;
2161 }
2162 2211
2163 rtnl_lock(); 2212 rtnl_lock();
2164 2213
@@ -2605,6 +2654,8 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
2605 cur_params.dot11MeshHWMPpreqMinInterval); 2654 cur_params.dot11MeshHWMPpreqMinInterval);
2606 NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, 2655 NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
2607 cur_params.dot11MeshHWMPnetDiameterTraversalTime); 2656 cur_params.dot11MeshHWMPnetDiameterTraversalTime);
2657 NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
2658 cur_params.dot11MeshHWMPRootMode);
2608 nla_nest_end(msg, pinfoattr); 2659 nla_nest_end(msg, pinfoattr);
2609 genlmsg_end(msg, hdr); 2660 genlmsg_end(msg, hdr);
2610 err = genlmsg_reply(msg, info); 2661 err = genlmsg_reply(msg, info);
@@ -2715,6 +2766,10 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
2715 dot11MeshHWMPnetDiameterTraversalTime, 2766 dot11MeshHWMPnetDiameterTraversalTime,
2716 mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, 2767 mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
2717 nla_get_u16); 2768 nla_get_u16);
2769 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
2770 dot11MeshHWMPRootMode, mask,
2771 NL80211_MESHCONF_HWMP_ROOTMODE,
2772 nla_get_u8);
2718 2773
2719 /* Apply changes */ 2774 /* Apply changes */
2720 err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); 2775 err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
@@ -2988,7 +3043,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2988 goto out; 3043 goto out;
2989 } 3044 }
2990 3045
2991 request->n_channels = n_channels;
2992 if (n_ssids) 3046 if (n_ssids)
2993 request->ssids = (void *)&request->channels[n_channels]; 3047 request->ssids = (void *)&request->channels[n_channels];
2994 request->n_ssids = n_ssids; 3048 request->n_ssids = n_ssids;
@@ -2999,32 +3053,53 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2999 request->ie = (void *)(request->channels + n_channels); 3053 request->ie = (void *)(request->channels + n_channels);
3000 } 3054 }
3001 3055
3056 i = 0;
3002 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { 3057 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
3003 /* user specified, bail out if channel not found */ 3058 /* user specified, bail out if channel not found */
3004 request->n_channels = n_channels;
3005 i = 0;
3006 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) { 3059 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
3007 request->channels[i] = ieee80211_get_channel(wiphy, nla_get_u32(attr)); 3060 struct ieee80211_channel *chan;
3008 if (!request->channels[i]) { 3061
3062 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
3063
3064 if (!chan) {
3009 err = -EINVAL; 3065 err = -EINVAL;
3010 goto out_free; 3066 goto out_free;
3011 } 3067 }
3068
3069 /* ignore disabled channels */
3070 if (chan->flags & IEEE80211_CHAN_DISABLED)
3071 continue;
3072
3073 request->channels[i] = chan;
3012 i++; 3074 i++;
3013 } 3075 }
3014 } else { 3076 } else {
3015 /* all channels */ 3077 /* all channels */
3016 i = 0;
3017 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 3078 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
3018 int j; 3079 int j;
3019 if (!wiphy->bands[band]) 3080 if (!wiphy->bands[band])
3020 continue; 3081 continue;
3021 for (j = 0; j < wiphy->bands[band]->n_channels; j++) { 3082 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
3022 request->channels[i] = &wiphy->bands[band]->channels[j]; 3083 struct ieee80211_channel *chan;
3084
3085 chan = &wiphy->bands[band]->channels[j];
3086
3087 if (chan->flags & IEEE80211_CHAN_DISABLED)
3088 continue;
3089
3090 request->channels[i] = chan;
3023 i++; 3091 i++;
3024 } 3092 }
3025 } 3093 }
3026 } 3094 }
3027 3095
3096 if (!i) {
3097 err = -EINVAL;
3098 goto out_free;
3099 }
3100
3101 request->n_channels = i;
3102
3028 i = 0; 3103 i = 0;
3029 if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { 3104 if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
3030 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { 3105 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
@@ -3105,6 +3180,8 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
3105 NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval); 3180 NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval);
3106 NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability); 3181 NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability);
3107 NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq); 3182 NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq);
3183 NLA_PUT_U32(msg, NL80211_BSS_SEEN_MS_AGO,
3184 jiffies_to_msecs(jiffies - intbss->ts));
3108 3185
3109 switch (rdev->wiphy.signal_type) { 3186 switch (rdev->wiphy.signal_type) {
3110 case CFG80211_SIGNAL_TYPE_MBM: 3187 case CFG80211_SIGNAL_TYPE_MBM:
@@ -3159,21 +3236,11 @@ static int nl80211_dump_scan(struct sk_buff *skb,
3159 int start = cb->args[1], idx = 0; 3236 int start = cb->args[1], idx = 0;
3160 int err; 3237 int err;
3161 3238
3162 if (!ifidx) { 3239 if (!ifidx)
3163 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, 3240 ifidx = nl80211_get_ifidx(cb);
3164 nl80211_fam.attrbuf, nl80211_fam.maxattr, 3241 if (ifidx < 0)
3165 nl80211_policy); 3242 return ifidx;
3166 if (err) 3243 cb->args[0] = ifidx;
3167 return err;
3168
3169 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
3170 return -EINVAL;
3171
3172 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
3173 if (!ifidx)
3174 return -EINVAL;
3175 cb->args[0] = ifidx;
3176 }
3177 3244
3178 dev = dev_get_by_index(sock_net(skb->sk), ifidx); 3245 dev = dev_get_by_index(sock_net(skb->sk), ifidx);
3179 if (!dev) 3246 if (!dev)
@@ -3216,6 +3283,106 @@ static int nl80211_dump_scan(struct sk_buff *skb,
3216 return err; 3283 return err;
3217} 3284}
3218 3285
3286static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
3287 int flags, struct net_device *dev,
3288 struct survey_info *survey)
3289{
3290 void *hdr;
3291 struct nlattr *infoattr;
3292
3293 /* Survey without a channel doesn't make sense */
3294 if (!survey->channel)
3295 return -EINVAL;
3296
3297 hdr = nl80211hdr_put(msg, pid, seq, flags,
3298 NL80211_CMD_NEW_SURVEY_RESULTS);
3299 if (!hdr)
3300 return -ENOMEM;
3301
3302 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
3303
3304 infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
3305 if (!infoattr)
3306 goto nla_put_failure;
3307
3308 NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY,
3309 survey->channel->center_freq);
3310 if (survey->filled & SURVEY_INFO_NOISE_DBM)
3311 NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE,
3312 survey->noise);
3313
3314 nla_nest_end(msg, infoattr);
3315
3316 return genlmsg_end(msg, hdr);
3317
3318 nla_put_failure:
3319 genlmsg_cancel(msg, hdr);
3320 return -EMSGSIZE;
3321}
3322
3323static int nl80211_dump_survey(struct sk_buff *skb,
3324 struct netlink_callback *cb)
3325{
3326 struct survey_info survey;
3327 struct cfg80211_registered_device *dev;
3328 struct net_device *netdev;
3329 int ifidx = cb->args[0];
3330 int survey_idx = cb->args[1];
3331 int res;
3332
3333 if (!ifidx)
3334 ifidx = nl80211_get_ifidx(cb);
3335 if (ifidx < 0)
3336 return ifidx;
3337 cb->args[0] = ifidx;
3338
3339 rtnl_lock();
3340
3341 netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
3342 if (!netdev) {
3343 res = -ENODEV;
3344 goto out_rtnl;
3345 }
3346
3347 dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
3348 if (IS_ERR(dev)) {
3349 res = PTR_ERR(dev);
3350 goto out_rtnl;
3351 }
3352
3353 if (!dev->ops->dump_survey) {
3354 res = -EOPNOTSUPP;
3355 goto out_err;
3356 }
3357
3358 while (1) {
3359 res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx,
3360 &survey);
3361 if (res == -ENOENT)
3362 break;
3363 if (res)
3364 goto out_err;
3365
3366 if (nl80211_send_survey(skb,
3367 NETLINK_CB(cb->skb).pid,
3368 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3369 netdev,
3370 &survey) < 0)
3371 goto out;
3372 survey_idx++;
3373 }
3374
3375 out:
3376 cb->args[1] = survey_idx;
3377 res = skb->len;
3378 out_err:
3379 cfg80211_unlock_rdev(dev);
3380 out_rtnl:
3381 rtnl_unlock();
3382
3383 return res;
3384}
3385
3219static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) 3386static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
3220{ 3387{
3221 return auth_type <= NL80211_AUTHTYPE_MAX; 3388 return auth_type <= NL80211_AUTHTYPE_MAX;
@@ -4293,6 +4460,11 @@ static struct genl_ops nl80211_ops[] = {
4293 .policy = nl80211_policy, 4460 .policy = nl80211_policy,
4294 .flags = GENL_ADMIN_PERM, 4461 .flags = GENL_ADMIN_PERM,
4295 }, 4462 },
4463 {
4464 .cmd = NL80211_CMD_GET_SURVEY,
4465 .policy = nl80211_policy,
4466 .dumpit = nl80211_dump_survey,
4467 },
4296}; 4468};
4297static struct genl_multicast_group nl80211_mlme_mcgrp = { 4469static struct genl_multicast_group nl80211_mlme_mcgrp = {
4298 .name = "mlme", 4470 .name = "mlme",