diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/nl80211.c | 166 | ||||
-rw-r--r-- | net/wireless/reg.c | 2 | ||||
-rw-r--r-- | net/wireless/util.c | 20 |
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 */ | 450 | static int nl80211_prepare_wdev_dump(struct sk_buff *skb, |
451 | static 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 | ||
470 | static 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 | ||
505 | static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) | 512 | static 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 | ||
5650 | static int nl80211_dump_scan(struct sk_buff *skb, | 5666 | static 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 | } |
1156 | EXPORT_SYMBOL(cfg80211_get_p2p_attr); | 1156 | EXPORT_SYMBOL(cfg80211_get_p2p_attr); |
1157 | 1157 | ||
1158 | bool 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 | } | ||
1176 | EXPORT_SYMBOL(ieee80211_operating_class_to_band); | ||
1177 | |||
1158 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 1178 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
1159 | u32 beacon_int) | 1179 | u32 beacon_int) |
1160 | { | 1180 | { |