aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c129
1 files changed, 59 insertions, 70 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1f0de6d74daa..de10e3c0e2a4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -302,8 +302,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
302 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, 302 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
303 [NL80211_ATTR_PID] = { .type = NLA_U32 }, 303 [NL80211_ATTR_PID] = { .type = NLA_U32 },
304 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, 304 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
305 [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, 305 [NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN },
306 .len = WLAN_PMKID_LEN },
307 [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, 306 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
308 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, 307 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
309 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, 308 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
@@ -359,6 +358,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
359 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, 358 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
360 [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, 359 [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
361 [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, 360 [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
361 [NL80211_ATTR_LOCAL_MESH_POWER_MODE] = {. type = NLA_U32 },
362 [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, 362 [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
363 [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, 363 [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
364 [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, 364 [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
@@ -492,21 +492,17 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
492{ 492{
493 int err; 493 int err;
494 494
495 rtnl_lock();
496
497 if (!cb->args[0]) { 495 if (!cb->args[0]) {
498 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, 496 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
499 nl80211_fam.attrbuf, nl80211_fam.maxattr, 497 nl80211_fam.attrbuf, nl80211_fam.maxattr,
500 nl80211_policy); 498 nl80211_policy);
501 if (err) 499 if (err)
502 goto out_unlock; 500 return err;
503 501
504 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), 502 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
505 nl80211_fam.attrbuf); 503 nl80211_fam.attrbuf);
506 if (IS_ERR(*wdev)) { 504 if (IS_ERR(*wdev))
507 err = PTR_ERR(*wdev); 505 return PTR_ERR(*wdev);
508 goto out_unlock;
509 }
510 *rdev = wiphy_to_rdev((*wdev)->wiphy); 506 *rdev = wiphy_to_rdev((*wdev)->wiphy);
511 /* 0 is the first index - add 1 to parse only once */ 507 /* 0 is the first index - add 1 to parse only once */
512 cb->args[0] = (*rdev)->wiphy_idx + 1; 508 cb->args[0] = (*rdev)->wiphy_idx + 1;
@@ -516,10 +512,8 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
516 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1); 512 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
517 struct wireless_dev *tmp; 513 struct wireless_dev *tmp;
518 514
519 if (!wiphy) { 515 if (!wiphy)
520 err = -ENODEV; 516 return -ENODEV;
521 goto out_unlock;
522 }
523 *rdev = wiphy_to_rdev(wiphy); 517 *rdev = wiphy_to_rdev(wiphy);
524 *wdev = NULL; 518 *wdev = NULL;
525 519
@@ -530,21 +524,11 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
530 } 524 }
531 } 525 }
532 526
533 if (!*wdev) { 527 if (!*wdev)
534 err = -ENODEV; 528 return -ENODEV;
535 goto out_unlock;
536 }
537 } 529 }
538 530
539 return 0; 531 return 0;
540 out_unlock:
541 rtnl_unlock();
542 return err;
543}
544
545static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev)
546{
547 rtnl_unlock();
548} 532}
549 533
550/* IE validation */ 534/* IE validation */
@@ -3884,9 +3868,10 @@ static int nl80211_dump_station(struct sk_buff *skb,
3884 int sta_idx = cb->args[2]; 3868 int sta_idx = cb->args[2];
3885 int err; 3869 int err;
3886 3870
3871 rtnl_lock();
3887 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); 3872 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
3888 if (err) 3873 if (err)
3889 return err; 3874 goto out_err;
3890 3875
3891 if (!wdev->netdev) { 3876 if (!wdev->netdev) {
3892 err = -EINVAL; 3877 err = -EINVAL;
@@ -3922,7 +3907,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
3922 cb->args[2] = sta_idx; 3907 cb->args[2] = sta_idx;
3923 err = skb->len; 3908 err = skb->len;
3924 out_err: 3909 out_err:
3925 nl80211_finish_wdev_dump(rdev); 3910 rtnl_unlock();
3926 3911
3927 return err; 3912 return err;
3928} 3913}
@@ -4639,9 +4624,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
4639 int path_idx = cb->args[2]; 4624 int path_idx = cb->args[2];
4640 int err; 4625 int err;
4641 4626
4627 rtnl_lock();
4642 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); 4628 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
4643 if (err) 4629 if (err)
4644 return err; 4630 goto out_err;
4645 4631
4646 if (!rdev->ops->dump_mpath) { 4632 if (!rdev->ops->dump_mpath) {
4647 err = -EOPNOTSUPP; 4633 err = -EOPNOTSUPP;
@@ -4675,7 +4661,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
4675 cb->args[2] = path_idx; 4661 cb->args[2] = path_idx;
4676 err = skb->len; 4662 err = skb->len;
4677 out_err: 4663 out_err:
4678 nl80211_finish_wdev_dump(rdev); 4664 rtnl_unlock();
4679 return err; 4665 return err;
4680} 4666}
4681 4667
@@ -4835,9 +4821,10 @@ static int nl80211_dump_mpp(struct sk_buff *skb,
4835 int path_idx = cb->args[2]; 4821 int path_idx = cb->args[2];
4836 int err; 4822 int err;
4837 4823
4824 rtnl_lock();
4838 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); 4825 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
4839 if (err) 4826 if (err)
4840 return err; 4827 goto out_err;
4841 4828
4842 if (!rdev->ops->dump_mpp) { 4829 if (!rdev->ops->dump_mpp) {
4843 err = -EOPNOTSUPP; 4830 err = -EOPNOTSUPP;
@@ -4870,7 +4857,7 @@ static int nl80211_dump_mpp(struct sk_buff *skb,
4870 cb->args[2] = path_idx; 4857 cb->args[2] = path_idx;
4871 err = skb->len; 4858 err = skb->len;
4872 out_err: 4859 out_err:
4873 nl80211_finish_wdev_dump(rdev); 4860 rtnl_unlock();
4874 return err; 4861 return err;
4875} 4862}
4876 4863
@@ -5718,6 +5705,10 @@ static int validate_scan_freqs(struct nlattr *freqs)
5718 struct nlattr *attr1, *attr2; 5705 struct nlattr *attr1, *attr2;
5719 int n_channels = 0, tmp1, tmp2; 5706 int n_channels = 0, tmp1, tmp2;
5720 5707
5708 nla_for_each_nested(attr1, freqs, tmp1)
5709 if (nla_len(attr1) != sizeof(u32))
5710 return 0;
5711
5721 nla_for_each_nested(attr1, freqs, tmp1) { 5712 nla_for_each_nested(attr1, freqs, tmp1) {
5722 n_channels++; 5713 n_channels++;
5723 /* 5714 /*
@@ -6806,9 +6797,12 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
6806 int start = cb->args[2], idx = 0; 6797 int start = cb->args[2], idx = 0;
6807 int err; 6798 int err;
6808 6799
6800 rtnl_lock();
6809 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); 6801 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
6810 if (err) 6802 if (err) {
6803 rtnl_unlock();
6811 return err; 6804 return err;
6805 }
6812 6806
6813 wdev_lock(wdev); 6807 wdev_lock(wdev);
6814 spin_lock_bh(&rdev->bss_lock); 6808 spin_lock_bh(&rdev->bss_lock);
@@ -6831,7 +6825,7 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
6831 wdev_unlock(wdev); 6825 wdev_unlock(wdev);
6832 6826
6833 cb->args[2] = idx; 6827 cb->args[2] = idx;
6834 nl80211_finish_wdev_dump(rdev); 6828 rtnl_unlock();
6835 6829
6836 return skb->len; 6830 return skb->len;
6837} 6831}
@@ -6915,9 +6909,10 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
6915 int res; 6909 int res;
6916 bool radio_stats; 6910 bool radio_stats;
6917 6911
6912 rtnl_lock();
6918 res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); 6913 res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
6919 if (res) 6914 if (res)
6920 return res; 6915 goto out_err;
6921 6916
6922 /* prepare_wdev_dump parsed the attributes */ 6917 /* prepare_wdev_dump parsed the attributes */
6923 radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS]; 6918 radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
@@ -6958,7 +6953,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
6958 cb->args[2] = survey_idx; 6953 cb->args[2] = survey_idx;
6959 res = skb->len; 6954 res = skb->len;
6960 out_err: 6955 out_err:
6961 nl80211_finish_wdev_dump(rdev); 6956 rtnl_unlock();
6962 return res; 6957 return res;
6963} 6958}
6964 6959
@@ -10158,17 +10153,13 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
10158 void *data = NULL; 10153 void *data = NULL;
10159 unsigned int data_len = 0; 10154 unsigned int data_len = 0;
10160 10155
10161 rtnl_lock();
10162
10163 if (cb->args[0]) { 10156 if (cb->args[0]) {
10164 /* subtract the 1 again here */ 10157 /* subtract the 1 again here */
10165 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1); 10158 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
10166 struct wireless_dev *tmp; 10159 struct wireless_dev *tmp;
10167 10160
10168 if (!wiphy) { 10161 if (!wiphy)
10169 err = -ENODEV; 10162 return -ENODEV;
10170 goto out_unlock;
10171 }
10172 *rdev = wiphy_to_rdev(wiphy); 10163 *rdev = wiphy_to_rdev(wiphy);
10173 *wdev = NULL; 10164 *wdev = NULL;
10174 10165
@@ -10189,13 +10180,11 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
10189 nl80211_fam.attrbuf, nl80211_fam.maxattr, 10180 nl80211_fam.attrbuf, nl80211_fam.maxattr,
10190 nl80211_policy); 10181 nl80211_policy);
10191 if (err) 10182 if (err)
10192 goto out_unlock; 10183 return err;
10193 10184
10194 if (!nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID] || 10185 if (!nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID] ||
10195 !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) { 10186 !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD])
10196 err = -EINVAL; 10187 return -EINVAL;
10197 goto out_unlock;
10198 }
10199 10188
10200 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), 10189 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
10201 nl80211_fam.attrbuf); 10190 nl80211_fam.attrbuf);
@@ -10204,10 +10193,8 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
10204 10193
10205 *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), 10194 *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
10206 nl80211_fam.attrbuf); 10195 nl80211_fam.attrbuf);
10207 if (IS_ERR(*rdev)) { 10196 if (IS_ERR(*rdev))
10208 err = PTR_ERR(*rdev); 10197 return PTR_ERR(*rdev);
10209 goto out_unlock;
10210 }
10211 10198
10212 vid = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID]); 10199 vid = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID]);
10213 subcmd = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]); 10200 subcmd = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
@@ -10220,19 +10207,15 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
10220 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd) 10207 if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
10221 continue; 10208 continue;
10222 10209
10223 if (!vcmd->dumpit) { 10210 if (!vcmd->dumpit)
10224 err = -EOPNOTSUPP; 10211 return -EOPNOTSUPP;
10225 goto out_unlock;
10226 }
10227 10212
10228 vcmd_idx = i; 10213 vcmd_idx = i;
10229 break; 10214 break;
10230 } 10215 }
10231 10216
10232 if (vcmd_idx < 0) { 10217 if (vcmd_idx < 0)
10233 err = -EOPNOTSUPP; 10218 return -EOPNOTSUPP;
10234 goto out_unlock;
10235 }
10236 10219
10237 if (nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]) { 10220 if (nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]) {
10238 data = nla_data(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]); 10221 data = nla_data(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
@@ -10249,9 +10232,6 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
10249 10232
10250 /* keep rtnl locked in successful case */ 10233 /* keep rtnl locked in successful case */
10251 return 0; 10234 return 0;
10252 out_unlock:
10253 rtnl_unlock();
10254 return err;
10255} 10235}
10256 10236
10257static int nl80211_vendor_cmd_dump(struct sk_buff *skb, 10237static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
@@ -10266,9 +10246,10 @@ static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
10266 int err; 10246 int err;
10267 struct nlattr *vendor_data; 10247 struct nlattr *vendor_data;
10268 10248
10249 rtnl_lock();
10269 err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev); 10250 err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
10270 if (err) 10251 if (err)
10271 return err; 10252 goto out;
10272 10253
10273 vcmd_idx = cb->args[2]; 10254 vcmd_idx = cb->args[2];
10274 data = (void *)cb->args[3]; 10255 data = (void *)cb->args[3];
@@ -10277,18 +10258,26 @@ static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
10277 10258
10278 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV | 10259 if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
10279 WIPHY_VENDOR_CMD_NEED_NETDEV)) { 10260 WIPHY_VENDOR_CMD_NEED_NETDEV)) {
10280 if (!wdev) 10261 if (!wdev) {
10281 return -EINVAL; 10262 err = -EINVAL;
10263 goto out;
10264 }
10282 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV && 10265 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
10283 !wdev->netdev) 10266 !wdev->netdev) {
10284 return -EINVAL; 10267 err = -EINVAL;
10268 goto out;
10269 }
10285 10270
10286 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) { 10271 if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
10287 if (wdev->netdev && 10272 if (wdev->netdev &&
10288 !netif_running(wdev->netdev)) 10273 !netif_running(wdev->netdev)) {
10289 return -ENETDOWN; 10274 err = -ENETDOWN;
10290 if (!wdev->netdev && !wdev->p2p_started) 10275 goto out;
10291 return -ENETDOWN; 10276 }
10277 if (!wdev->netdev && !wdev->p2p_started) {
10278 err = -ENETDOWN;
10279 goto out;
10280 }
10292 } 10281 }
10293 } 10282 }
10294 10283