aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/nl80211.c166
-rw-r--r--net/wireless/reg.c2
-rw-r--r--net/wireless/util.c20
3 files changed, 112 insertions, 76 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 671b69a3c136..212d2aa7a1c5 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -447,62 +447,69 @@ nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
447 [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, 447 [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
448}; 448};
449 449
450/* ifidx get helper */ 450static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
451static int nl80211_get_ifidx(struct netlink_callback *cb) 451 struct netlink_callback *cb,
452 struct cfg80211_registered_device **rdev,
453 struct wireless_dev **wdev)
452{ 454{
453 int res; 455 int err;
454
455 res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
456 nl80211_fam.attrbuf, nl80211_fam.maxattr,
457 nl80211_policy);
458 if (res)
459 return res;
460
461 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
462 return -EINVAL;
463 456
464 res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); 457 rtnl_lock();
465 if (!res) 458 mutex_lock(&cfg80211_mutex);
466 return -EINVAL;
467 return res;
468}
469 459
470static int nl80211_prepare_netdev_dump(struct sk_buff *skb, 460 if (!cb->args[0]) {
471 struct netlink_callback *cb, 461 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
472 struct cfg80211_registered_device **rdev, 462 nl80211_fam.attrbuf, nl80211_fam.maxattr,
473 struct net_device **dev) 463 nl80211_policy);
474{ 464 if (err)
475 int ifidx = cb->args[0]; 465 goto out_unlock;
476 int err;
477 466
478 if (!ifidx) 467 *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
479 ifidx = nl80211_get_ifidx(cb); 468 nl80211_fam.attrbuf);
480 if (ifidx < 0) 469 if (IS_ERR(*wdev)) {
481 return ifidx; 470 err = PTR_ERR(*wdev);
471 goto out_unlock;
472 }
473 *rdev = wiphy_to_dev((*wdev)->wiphy);
474 cb->args[0] = (*rdev)->wiphy_idx;
475 cb->args[1] = (*wdev)->identifier;
476 } else {
477 struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0]);
478 struct wireless_dev *tmp;
482 479
483 cb->args[0] = ifidx; 480 if (!wiphy) {
481 err = -ENODEV;
482 goto out_unlock;
483 }
484 *rdev = wiphy_to_dev(wiphy);
485 *wdev = NULL;
484 486
485 rtnl_lock(); 487 mutex_lock(&(*rdev)->devlist_mtx);
488 list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
489 if (tmp->identifier == cb->args[1]) {
490 *wdev = tmp;
491 break;
492 }
493 }
494 mutex_unlock(&(*rdev)->devlist_mtx);
486 495
487 *dev = __dev_get_by_index(sock_net(skb->sk), ifidx); 496 if (!*wdev) {
488 if (!*dev) { 497 err = -ENODEV;
489 err = -ENODEV; 498 goto out_unlock;
490 goto out_rtnl; 499 }
491 } 500 }
492 501
493 *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); 502 cfg80211_lock_rdev(*rdev);
494 if (IS_ERR(*rdev)) {
495 err = PTR_ERR(*rdev);
496 goto out_rtnl;
497 }
498 503
504 mutex_unlock(&cfg80211_mutex);
499 return 0; 505 return 0;
500 out_rtnl: 506 out_unlock:
507 mutex_unlock(&cfg80211_mutex);
501 rtnl_unlock(); 508 rtnl_unlock();
502 return err; 509 return err;
503} 510}
504 511
505static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) 512static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev)
506{ 513{
507 cfg80211_unlock_rdev(rdev); 514 cfg80211_unlock_rdev(rdev);
508 rtnl_unlock(); 515 rtnl_unlock();
@@ -3525,15 +3532,20 @@ static int nl80211_dump_station(struct sk_buff *skb,
3525{ 3532{
3526 struct station_info sinfo; 3533 struct station_info sinfo;
3527 struct cfg80211_registered_device *dev; 3534 struct cfg80211_registered_device *dev;
3528 struct net_device *netdev; 3535 struct wireless_dev *wdev;
3529 u8 mac_addr[ETH_ALEN]; 3536 u8 mac_addr[ETH_ALEN];
3530 int sta_idx = cb->args[1]; 3537 int sta_idx = cb->args[2];
3531 int err; 3538 int err;
3532 3539
3533 err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); 3540 err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
3534 if (err) 3541 if (err)
3535 return err; 3542 return err;
3536 3543
3544 if (!wdev->netdev) {
3545 err = -EINVAL;
3546 goto out_err;
3547 }
3548
3537 if (!dev->ops->dump_station) { 3549 if (!dev->ops->dump_station) {
3538 err = -EOPNOTSUPP; 3550 err = -EOPNOTSUPP;
3539 goto out_err; 3551 goto out_err;
@@ -3541,7 +3553,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
3541 3553
3542 while (1) { 3554 while (1) {
3543 memset(&sinfo, 0, sizeof(sinfo)); 3555 memset(&sinfo, 0, sizeof(sinfo));
3544 err = rdev_dump_station(dev, netdev, sta_idx, 3556 err = rdev_dump_station(dev, wdev->netdev, sta_idx,
3545 mac_addr, &sinfo); 3557 mac_addr, &sinfo);
3546 if (err == -ENOENT) 3558 if (err == -ENOENT)
3547 break; 3559 break;
@@ -3551,7 +3563,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
3551 if (nl80211_send_station(skb, 3563 if (nl80211_send_station(skb,
3552 NETLINK_CB(cb->skb).portid, 3564 NETLINK_CB(cb->skb).portid,
3553 cb->nlh->nlmsg_seq, NLM_F_MULTI, 3565 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3554 dev, netdev, mac_addr, 3566 dev, wdev->netdev, mac_addr,
3555 &sinfo) < 0) 3567 &sinfo) < 0)
3556 goto out; 3568 goto out;
3557 3569
@@ -3560,10 +3572,10 @@ static int nl80211_dump_station(struct sk_buff *skb,
3560 3572
3561 3573
3562 out: 3574 out:
3563 cb->args[1] = sta_idx; 3575 cb->args[2] = sta_idx;
3564 err = skb->len; 3576 err = skb->len;
3565 out_err: 3577 out_err:
3566 nl80211_finish_netdev_dump(dev); 3578 nl80211_finish_wdev_dump(dev);
3567 3579
3568 return err; 3580 return err;
3569} 3581}
@@ -4167,13 +4179,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
4167{ 4179{
4168 struct mpath_info pinfo; 4180 struct mpath_info pinfo;
4169 struct cfg80211_registered_device *dev; 4181 struct cfg80211_registered_device *dev;
4170 struct net_device *netdev; 4182 struct wireless_dev *wdev;
4171 u8 dst[ETH_ALEN]; 4183 u8 dst[ETH_ALEN];
4172 u8 next_hop[ETH_ALEN]; 4184 u8 next_hop[ETH_ALEN];
4173 int path_idx = cb->args[1]; 4185 int path_idx = cb->args[2];
4174 int err; 4186 int err;
4175 4187
4176 err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); 4188 err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
4177 if (err) 4189 if (err)
4178 return err; 4190 return err;
4179 4191
@@ -4182,14 +4194,14 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
4182 goto out_err; 4194 goto out_err;
4183 } 4195 }
4184 4196
4185 if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { 4197 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
4186 err = -EOPNOTSUPP; 4198 err = -EOPNOTSUPP;
4187 goto out_err; 4199 goto out_err;
4188 } 4200 }
4189 4201
4190 while (1) { 4202 while (1) {
4191 err = rdev_dump_mpath(dev, netdev, path_idx, dst, next_hop, 4203 err = rdev_dump_mpath(dev, wdev->netdev, path_idx, dst,
4192 &pinfo); 4204 next_hop, &pinfo);
4193 if (err == -ENOENT) 4205 if (err == -ENOENT)
4194 break; 4206 break;
4195 if (err) 4207 if (err)
@@ -4197,7 +4209,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
4197 4209
4198 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid, 4210 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
4199 cb->nlh->nlmsg_seq, NLM_F_MULTI, 4211 cb->nlh->nlmsg_seq, NLM_F_MULTI,
4200 netdev, dst, next_hop, 4212 wdev->netdev, dst, next_hop,
4201 &pinfo) < 0) 4213 &pinfo) < 0)
4202 goto out; 4214 goto out;
4203 4215
@@ -4206,10 +4218,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
4206 4218
4207 4219
4208 out: 4220 out:
4209 cb->args[1] = path_idx; 4221 cb->args[2] = path_idx;
4210 err = skb->len; 4222 err = skb->len;
4211 out_err: 4223 out_err:
4212 nl80211_finish_netdev_dump(dev); 4224 nl80211_finish_wdev_dump(dev);
4213 return err; 4225 return err;
4214} 4226}
4215 4227
@@ -5565,9 +5577,13 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
5565 5577
5566 genl_dump_check_consistent(cb, hdr, &nl80211_fam); 5578 genl_dump_check_consistent(cb, hdr, &nl80211_fam);
5567 5579
5568 if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation) || 5580 if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
5581 goto nla_put_failure;
5582 if (wdev->netdev &&
5569 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex)) 5583 nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
5570 goto nla_put_failure; 5584 goto nla_put_failure;
5585 if (nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
5586 goto nla_put_failure;
5571 5587
5572 bss = nla_nest_start(msg, NL80211_ATTR_BSS); 5588 bss = nla_nest_start(msg, NL80211_ATTR_BSS);
5573 if (!bss) 5589 if (!bss)
@@ -5647,22 +5663,18 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
5647 return -EMSGSIZE; 5663 return -EMSGSIZE;
5648} 5664}
5649 5665
5650static int nl80211_dump_scan(struct sk_buff *skb, 5666static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
5651 struct netlink_callback *cb)
5652{ 5667{
5653 struct cfg80211_registered_device *rdev; 5668 struct cfg80211_registered_device *rdev;
5654 struct net_device *dev;
5655 struct cfg80211_internal_bss *scan; 5669 struct cfg80211_internal_bss *scan;
5656 struct wireless_dev *wdev; 5670 struct wireless_dev *wdev;
5657 int start = cb->args[1], idx = 0; 5671 int start = cb->args[2], idx = 0;
5658 int err; 5672 int err;
5659 5673
5660 err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev); 5674 err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
5661 if (err) 5675 if (err)
5662 return err; 5676 return err;
5663 5677
5664 wdev = dev->ieee80211_ptr;
5665
5666 wdev_lock(wdev); 5678 wdev_lock(wdev);
5667 spin_lock_bh(&rdev->bss_lock); 5679 spin_lock_bh(&rdev->bss_lock);
5668 cfg80211_bss_expire(rdev); 5680 cfg80211_bss_expire(rdev);
@@ -5683,8 +5695,8 @@ static int nl80211_dump_scan(struct sk_buff *skb,
5683 spin_unlock_bh(&rdev->bss_lock); 5695 spin_unlock_bh(&rdev->bss_lock);
5684 wdev_unlock(wdev); 5696 wdev_unlock(wdev);
5685 5697
5686 cb->args[1] = idx; 5698 cb->args[2] = idx;
5687 nl80211_finish_netdev_dump(rdev); 5699 nl80211_finish_wdev_dump(rdev);
5688 5700
5689 return skb->len; 5701 return skb->len;
5690} 5702}
@@ -5753,14 +5765,19 @@ static int nl80211_dump_survey(struct sk_buff *skb,
5753{ 5765{
5754 struct survey_info survey; 5766 struct survey_info survey;
5755 struct cfg80211_registered_device *dev; 5767 struct cfg80211_registered_device *dev;
5756 struct net_device *netdev; 5768 struct wireless_dev *wdev;
5757 int survey_idx = cb->args[1]; 5769 int survey_idx = cb->args[2];
5758 int res; 5770 int res;
5759 5771
5760 res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); 5772 res = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
5761 if (res) 5773 if (res)
5762 return res; 5774 return res;
5763 5775
5776 if (!wdev->netdev) {
5777 res = -EINVAL;
5778 goto out_err;
5779 }
5780
5764 if (!dev->ops->dump_survey) { 5781 if (!dev->ops->dump_survey) {
5765 res = -EOPNOTSUPP; 5782 res = -EOPNOTSUPP;
5766 goto out_err; 5783 goto out_err;
@@ -5769,7 +5786,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
5769 while (1) { 5786 while (1) {
5770 struct ieee80211_channel *chan; 5787 struct ieee80211_channel *chan;
5771 5788
5772 res = rdev_dump_survey(dev, netdev, survey_idx, &survey); 5789 res = rdev_dump_survey(dev, wdev->netdev, survey_idx, &survey);
5773 if (res == -ENOENT) 5790 if (res == -ENOENT)
5774 break; 5791 break;
5775 if (res) 5792 if (res)
@@ -5791,17 +5808,16 @@ static int nl80211_dump_survey(struct sk_buff *skb,
5791 if (nl80211_send_survey(skb, 5808 if (nl80211_send_survey(skb,
5792 NETLINK_CB(cb->skb).portid, 5809 NETLINK_CB(cb->skb).portid,
5793 cb->nlh->nlmsg_seq, NLM_F_MULTI, 5810 cb->nlh->nlmsg_seq, NLM_F_MULTI,
5794 netdev, 5811 wdev->netdev, &survey) < 0)
5795 &survey) < 0)
5796 goto out; 5812 goto out;
5797 survey_idx++; 5813 survey_idx++;
5798 } 5814 }
5799 5815
5800 out: 5816 out:
5801 cb->args[1] = survey_idx; 5817 cb->args[2] = survey_idx;
5802 res = skb->len; 5818 res = skb->len;
5803 out_err: 5819 out_err:
5804 nl80211_finish_netdev_dump(dev); 5820 nl80211_finish_wdev_dump(dev);
5805 return res; 5821 return res;
5806} 5822}
5807 5823
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index e6df52dc8c69..cc35fbaa4578 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -855,7 +855,7 @@ static void handle_channel(struct wiphy *wiphy,
855 return; 855 return;
856 856
857 REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); 857 REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq);
858 chan->flags = IEEE80211_CHAN_DISABLED; 858 chan->flags |= IEEE80211_CHAN_DISABLED;
859 return; 859 return;
860 } 860 }
861 861
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 37a56ee1e1ed..3d8a1334f4a9 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1155,6 +1155,26 @@ int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
1155} 1155}
1156EXPORT_SYMBOL(cfg80211_get_p2p_attr); 1156EXPORT_SYMBOL(cfg80211_get_p2p_attr);
1157 1157
1158bool ieee80211_operating_class_to_band(u8 operating_class,
1159 enum ieee80211_band *band)
1160{
1161 switch (operating_class) {
1162 case 112:
1163 case 115 ... 127:
1164 *band = IEEE80211_BAND_5GHZ;
1165 return true;
1166 case 81:
1167 case 82:
1168 case 83:
1169 case 84:
1170 *band = IEEE80211_BAND_2GHZ;
1171 return true;
1172 }
1173
1174 return false;
1175}
1176EXPORT_SYMBOL(ieee80211_operating_class_to_band);
1177
1158int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, 1178int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
1159 u32 beacon_int) 1179 u32 beacon_int)
1160{ 1180{