diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 155 |
1 files changed, 82 insertions, 73 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d038fa45ecd1..f45706adaf34 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -363,6 +363,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
363 | [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, }, | 363 | [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, }, |
364 | [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN }, | 364 | [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN }, |
365 | [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, | 365 | [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, |
366 | [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, | ||
367 | [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, | ||
366 | }; | 368 | }; |
367 | 369 | ||
368 | /* policy for the key attributes */ | 370 | /* policy for the key attributes */ |
@@ -1369,9 +1371,7 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, | |||
1369 | struct genl_info *info, | 1371 | struct genl_info *info, |
1370 | struct cfg80211_chan_def *chandef) | 1372 | struct cfg80211_chan_def *chandef) |
1371 | { | 1373 | { |
1372 | struct ieee80211_sta_ht_cap *ht_cap; | 1374 | u32 control_freq; |
1373 | struct ieee80211_sta_vht_cap *vht_cap; | ||
1374 | u32 control_freq, width; | ||
1375 | 1375 | ||
1376 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 1376 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
1377 | return -EINVAL; | 1377 | return -EINVAL; |
@@ -1417,67 +1417,13 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, | |||
1417 | info->attrs[NL80211_ATTR_CENTER_FREQ2]); | 1417 | info->attrs[NL80211_ATTR_CENTER_FREQ2]); |
1418 | } | 1418 | } |
1419 | 1419 | ||
1420 | ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap; | 1420 | if (!cfg80211_chandef_valid(chandef)) |
1421 | vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap; | ||
1422 | |||
1423 | if (!cfg80211_chan_def_valid(chandef)) | ||
1424 | return -EINVAL; | 1421 | return -EINVAL; |
1425 | 1422 | ||
1426 | switch (chandef->width) { | 1423 | if (!cfg80211_chandef_usable(&rdev->wiphy, chandef, |
1427 | case NL80211_CHAN_WIDTH_20: | 1424 | IEEE80211_CHAN_DISABLED)) |
1428 | if (!ht_cap->ht_supported) | ||
1429 | return -EINVAL; | ||
1430 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
1431 | width = 20; | ||
1432 | break; | ||
1433 | case NL80211_CHAN_WIDTH_40: | ||
1434 | width = 40; | ||
1435 | /* quick early regulatory check */ | ||
1436 | if (chandef->center_freq1 < control_freq && | ||
1437 | chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||
1438 | return -EINVAL; | ||
1439 | if (chandef->center_freq1 > control_freq && | ||
1440 | chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
1441 | return -EINVAL; | ||
1442 | if (!ht_cap->ht_supported) | ||
1443 | return -EINVAL; | ||
1444 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||
1445 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) | ||
1446 | return -EINVAL; | ||
1447 | break; | ||
1448 | case NL80211_CHAN_WIDTH_80: | ||
1449 | width = 80; | ||
1450 | if (!vht_cap->vht_supported) | ||
1451 | return -EINVAL; | ||
1452 | break; | ||
1453 | case NL80211_CHAN_WIDTH_80P80: | ||
1454 | width = 80; | ||
1455 | if (!vht_cap->vht_supported) | ||
1456 | return -EINVAL; | ||
1457 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) | ||
1458 | return -EINVAL; | ||
1459 | break; | ||
1460 | case NL80211_CHAN_WIDTH_160: | ||
1461 | width = 160; | ||
1462 | if (!vht_cap->vht_supported) | ||
1463 | return -EINVAL; | ||
1464 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) | ||
1465 | return -EINVAL; | ||
1466 | break; | ||
1467 | default: | ||
1468 | return -EINVAL; | ||
1469 | } | ||
1470 | |||
1471 | if (!cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq1, | ||
1472 | width, IEEE80211_CHAN_DISABLED)) | ||
1473 | return -EINVAL; | ||
1474 | if (chandef->center_freq2 && | ||
1475 | !cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq2, | ||
1476 | width, IEEE80211_CHAN_DISABLED)) | ||
1477 | return -EINVAL; | 1425 | return -EINVAL; |
1478 | 1426 | ||
1479 | /* TODO: missing regulatory check on bandwidth */ | ||
1480 | |||
1481 | return 0; | 1427 | return 0; |
1482 | } | 1428 | } |
1483 | 1429 | ||
@@ -1841,7 +1787,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev) | |||
1841 | static int nl80211_send_chandef(struct sk_buff *msg, | 1787 | static int nl80211_send_chandef(struct sk_buff *msg, |
1842 | struct cfg80211_chan_def *chandef) | 1788 | struct cfg80211_chan_def *chandef) |
1843 | { | 1789 | { |
1844 | WARN_ON(!cfg80211_chan_def_valid(chandef)); | 1790 | WARN_ON(!cfg80211_chandef_valid(chandef)); |
1845 | 1791 | ||
1846 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | 1792 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, |
1847 | chandef->chan->center_freq)) | 1793 | chandef->chan->center_freq)) |
@@ -2732,6 +2678,32 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2732 | info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); | 2678 | info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); |
2733 | } | 2679 | } |
2734 | 2680 | ||
2681 | if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) { | ||
2682 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
2683 | return -EINVAL; | ||
2684 | params.p2p_ctwindow = | ||
2685 | nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]); | ||
2686 | if (params.p2p_ctwindow > 127) | ||
2687 | return -EINVAL; | ||
2688 | if (params.p2p_ctwindow != 0 && | ||
2689 | !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) | ||
2690 | return -EINVAL; | ||
2691 | } | ||
2692 | |||
2693 | if (info->attrs[NL80211_ATTR_P2P_OPPPS]) { | ||
2694 | u8 tmp; | ||
2695 | |||
2696 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
2697 | return -EINVAL; | ||
2698 | tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]); | ||
2699 | if (tmp > 1) | ||
2700 | return -EINVAL; | ||
2701 | params.p2p_opp_ps = tmp; | ||
2702 | if (params.p2p_opp_ps != 0 && | ||
2703 | !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) | ||
2704 | return -EINVAL; | ||
2705 | } | ||
2706 | |||
2735 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 2707 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
2736 | err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); | 2708 | err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); |
2737 | if (err) | 2709 | if (err) |
@@ -3698,6 +3670,8 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
3698 | params.use_short_slot_time = -1; | 3670 | params.use_short_slot_time = -1; |
3699 | params.ap_isolate = -1; | 3671 | params.ap_isolate = -1; |
3700 | params.ht_opmode = -1; | 3672 | params.ht_opmode = -1; |
3673 | params.p2p_ctwindow = -1; | ||
3674 | params.p2p_opp_ps = -1; | ||
3701 | 3675 | ||
3702 | if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) | 3676 | if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) |
3703 | params.use_cts_prot = | 3677 | params.use_cts_prot = |
@@ -3720,6 +3694,32 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
3720 | params.ht_opmode = | 3694 | params.ht_opmode = |
3721 | nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]); | 3695 | nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]); |
3722 | 3696 | ||
3697 | if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) { | ||
3698 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
3699 | return -EINVAL; | ||
3700 | params.p2p_ctwindow = | ||
3701 | nla_get_s8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]); | ||
3702 | if (params.p2p_ctwindow < 0) | ||
3703 | return -EINVAL; | ||
3704 | if (params.p2p_ctwindow != 0 && | ||
3705 | !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) | ||
3706 | return -EINVAL; | ||
3707 | } | ||
3708 | |||
3709 | if (info->attrs[NL80211_ATTR_P2P_OPPPS]) { | ||
3710 | u8 tmp; | ||
3711 | |||
3712 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
3713 | return -EINVAL; | ||
3714 | tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]); | ||
3715 | if (tmp > 1) | ||
3716 | return -EINVAL; | ||
3717 | params.p2p_opp_ps = tmp; | ||
3718 | if (params.p2p_opp_ps && | ||
3719 | !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) | ||
3720 | return -EINVAL; | ||
3721 | } | ||
3722 | |||
3723 | if (!rdev->ops->change_bss) | 3723 | if (!rdev->ops->change_bss) |
3724 | return -EOPNOTSUPP; | 3724 | return -EOPNOTSUPP; |
3725 | 3725 | ||
@@ -4808,6 +4808,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | |||
4808 | struct cfg80211_internal_bss *intbss) | 4808 | struct cfg80211_internal_bss *intbss) |
4809 | { | 4809 | { |
4810 | struct cfg80211_bss *res = &intbss->pub; | 4810 | struct cfg80211_bss *res = &intbss->pub; |
4811 | const struct cfg80211_bss_ies *ies; | ||
4811 | void *hdr; | 4812 | void *hdr; |
4812 | struct nlattr *bss; | 4813 | struct nlattr *bss; |
4813 | 4814 | ||
@@ -4828,16 +4829,24 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | |||
4828 | if (!bss) | 4829 | if (!bss) |
4829 | goto nla_put_failure; | 4830 | goto nla_put_failure; |
4830 | if ((!is_zero_ether_addr(res->bssid) && | 4831 | if ((!is_zero_ether_addr(res->bssid) && |
4831 | nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)) || | 4832 | nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid))) |
4832 | (res->information_elements && res->len_information_elements && | 4833 | goto nla_put_failure; |
4833 | nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS, | 4834 | |
4834 | res->len_information_elements, | 4835 | rcu_read_lock(); |
4835 | res->information_elements)) || | 4836 | ies = rcu_dereference(res->ies); |
4836 | (res->beacon_ies && res->len_beacon_ies && | 4837 | if (ies && ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS, |
4837 | res->beacon_ies != res->information_elements && | 4838 | ies->len, ies->data)) { |
4838 | nla_put(msg, NL80211_BSS_BEACON_IES, | 4839 | rcu_read_unlock(); |
4839 | res->len_beacon_ies, res->beacon_ies))) | 4840 | goto nla_put_failure; |
4841 | } | ||
4842 | ies = rcu_dereference(res->beacon_ies); | ||
4843 | if (ies && ies->len && nla_put(msg, NL80211_BSS_BEACON_IES, | ||
4844 | ies->len, ies->data)) { | ||
4845 | rcu_read_unlock(); | ||
4840 | goto nla_put_failure; | 4846 | goto nla_put_failure; |
4847 | } | ||
4848 | rcu_read_unlock(); | ||
4849 | |||
4841 | if (res->tsf && | 4850 | if (res->tsf && |
4842 | nla_put_u64(msg, NL80211_BSS_TSF, res->tsf)) | 4851 | nla_put_u64(msg, NL80211_BSS_TSF, res->tsf)) |
4843 | goto nla_put_failure; | 4852 | goto nla_put_failure; |
@@ -5502,6 +5511,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
5502 | return -EINVAL; | 5511 | return -EINVAL; |
5503 | if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && | 5512 | if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && |
5504 | !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) | 5513 | !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) |
5514 | return -EINVAL; | ||
5505 | 5515 | ||
5506 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | 5516 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; |
5507 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; | 5517 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; |
@@ -6529,14 +6539,13 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | |||
6529 | }; | 6539 | }; |
6530 | 6540 | ||
6531 | static int nl80211_set_cqm_txe(struct genl_info *info, | 6541 | static int nl80211_set_cqm_txe(struct genl_info *info, |
6532 | u32 rate, u32 pkts, u32 intvl) | 6542 | u32 rate, u32 pkts, u32 intvl) |
6533 | { | 6543 | { |
6534 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6544 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6535 | struct wireless_dev *wdev; | 6545 | struct wireless_dev *wdev; |
6536 | struct net_device *dev = info->user_ptr[1]; | 6546 | struct net_device *dev = info->user_ptr[1]; |
6537 | 6547 | ||
6538 | if ((rate < 0 || rate > 100) || | 6548 | if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL) |
6539 | (intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL)) | ||
6540 | return -EINVAL; | 6549 | return -EINVAL; |
6541 | 6550 | ||
6542 | wdev = dev->ieee80211_ptr; | 6551 | wdev = dev->ieee80211_ptr; |