diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-02-20 15:02:02 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-02-20 15:02:02 -0500 |
commit | 88daf80dcca19ff995cc263592426f734a9702f3 (patch) | |
tree | 7a52e25df74e52d00c3821032e719244e8a5526f /net/wireless | |
parent | 010d3c3989706d800ae72253773fa6537cc9f74c (diff) | |
parent | 35582ad9d342025653aaf28ed321bf5352488d7f (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/ap.c | 3 | ||||
-rw-r--r-- | net/wireless/chan.c | 23 | ||||
-rw-r--r-- | net/wireless/core.c | 2 | ||||
-rw-r--r-- | net/wireless/core.h | 7 | ||||
-rw-r--r-- | net/wireless/ibss.c | 19 | ||||
-rw-r--r-- | net/wireless/mesh.c | 6 | ||||
-rw-r--r-- | net/wireless/mlme.c | 2 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 229 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 2 | ||||
-rw-r--r-- | net/wireless/reg.c | 188 | ||||
-rw-r--r-- | net/wireless/reg.h | 2 | ||||
-rw-r--r-- | net/wireless/trace.h | 23 | ||||
-rw-r--r-- | net/wireless/util.c | 5 |
13 files changed, 399 insertions, 112 deletions
diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 11ee4ed04f73..68602be07cc1 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c | |||
@@ -27,9 +27,10 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | |||
27 | err = rdev_stop_ap(rdev, dev); | 27 | err = rdev_stop_ap(rdev, dev); |
28 | if (!err) { | 28 | if (!err) { |
29 | wdev->beacon_interval = 0; | 29 | wdev->beacon_interval = 0; |
30 | wdev->channel = NULL; | 30 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); |
31 | wdev->ssid_len = 0; | 31 | wdev->ssid_len = 0; |
32 | rdev_set_qos_map(rdev, dev, NULL); | 32 | rdev_set_qos_map(rdev, dev, NULL); |
33 | nl80211_send_ap_stopped(wdev); | ||
33 | } | 34 | } |
34 | 35 | ||
35 | return err; | 36 | return err; |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index a04b884f5d04..2d4268c5529d 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -642,7 +642,8 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, | |||
642 | void | 642 | void |
643 | cfg80211_get_chan_state(struct wireless_dev *wdev, | 643 | cfg80211_get_chan_state(struct wireless_dev *wdev, |
644 | struct ieee80211_channel **chan, | 644 | struct ieee80211_channel **chan, |
645 | enum cfg80211_chan_mode *chanmode) | 645 | enum cfg80211_chan_mode *chanmode, |
646 | u8 *radar_detect) | ||
646 | { | 647 | { |
647 | *chan = NULL; | 648 | *chan = NULL; |
648 | *chanmode = CHAN_MODE_UNDEFINED; | 649 | *chanmode = CHAN_MODE_UNDEFINED; |
@@ -660,6 +661,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
660 | !wdev->ibss_dfs_possible) | 661 | !wdev->ibss_dfs_possible) |
661 | ? CHAN_MODE_SHARED | 662 | ? CHAN_MODE_SHARED |
662 | : CHAN_MODE_EXCLUSIVE; | 663 | : CHAN_MODE_EXCLUSIVE; |
664 | |||
665 | /* consider worst-case - IBSS can try to return to the | ||
666 | * original user-specified channel as creator */ | ||
667 | if (wdev->ibss_dfs_possible) | ||
668 | *radar_detect |= BIT(wdev->chandef.width); | ||
663 | return; | 669 | return; |
664 | } | 670 | } |
665 | break; | 671 | break; |
@@ -674,17 +680,26 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
674 | case NL80211_IFTYPE_AP: | 680 | case NL80211_IFTYPE_AP: |
675 | case NL80211_IFTYPE_P2P_GO: | 681 | case NL80211_IFTYPE_P2P_GO: |
676 | if (wdev->cac_started) { | 682 | if (wdev->cac_started) { |
677 | *chan = wdev->channel; | 683 | *chan = wdev->chandef.chan; |
678 | *chanmode = CHAN_MODE_SHARED; | 684 | *chanmode = CHAN_MODE_SHARED; |
685 | *radar_detect |= BIT(wdev->chandef.width); | ||
679 | } else if (wdev->beacon_interval) { | 686 | } else if (wdev->beacon_interval) { |
680 | *chan = wdev->channel; | 687 | *chan = wdev->chandef.chan; |
681 | *chanmode = CHAN_MODE_SHARED; | 688 | *chanmode = CHAN_MODE_SHARED; |
689 | |||
690 | if (cfg80211_chandef_dfs_required(wdev->wiphy, | ||
691 | &wdev->chandef)) | ||
692 | *radar_detect |= BIT(wdev->chandef.width); | ||
682 | } | 693 | } |
683 | return; | 694 | return; |
684 | case NL80211_IFTYPE_MESH_POINT: | 695 | case NL80211_IFTYPE_MESH_POINT: |
685 | if (wdev->mesh_id_len) { | 696 | if (wdev->mesh_id_len) { |
686 | *chan = wdev->channel; | 697 | *chan = wdev->chandef.chan; |
687 | *chanmode = CHAN_MODE_SHARED; | 698 | *chanmode = CHAN_MODE_SHARED; |
699 | |||
700 | if (cfg80211_chandef_dfs_required(wdev->wiphy, | ||
701 | &wdev->chandef)) | ||
702 | *radar_detect |= BIT(wdev->chandef.width); | ||
688 | } | 703 | } |
689 | return; | 704 | return; |
690 | case NL80211_IFTYPE_MONITOR: | 705 | case NL80211_IFTYPE_MONITOR: |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 010892b81a06..76ae6a605abb 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -737,7 +737,7 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) | |||
737 | } | 737 | } |
738 | EXPORT_SYMBOL(cfg80211_unregister_wdev); | 738 | EXPORT_SYMBOL(cfg80211_unregister_wdev); |
739 | 739 | ||
740 | static struct device_type wiphy_type = { | 740 | static const struct device_type wiphy_type = { |
741 | .name = "wlan", | 741 | .name = "wlan", |
742 | }; | 742 | }; |
743 | 743 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index f1d193b557b6..40683004d523 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -211,6 +211,7 @@ struct cfg80211_event { | |||
211 | } dc; | 211 | } dc; |
212 | struct { | 212 | struct { |
213 | u8 bssid[ETH_ALEN]; | 213 | u8 bssid[ETH_ALEN]; |
214 | struct ieee80211_channel *channel; | ||
214 | } ij; | 215 | } ij; |
215 | }; | 216 | }; |
216 | }; | 217 | }; |
@@ -258,7 +259,8 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | |||
258 | struct net_device *dev, bool nowext); | 259 | struct net_device *dev, bool nowext); |
259 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 260 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, |
260 | struct net_device *dev, bool nowext); | 261 | struct net_device *dev, bool nowext); |
261 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); | 262 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, |
263 | struct ieee80211_channel *channel); | ||
262 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | 264 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, |
263 | struct wireless_dev *wdev); | 265 | struct wireless_dev *wdev); |
264 | 266 | ||
@@ -443,7 +445,8 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start) | |||
443 | void | 445 | void |
444 | cfg80211_get_chan_state(struct wireless_dev *wdev, | 446 | cfg80211_get_chan_state(struct wireless_dev *wdev, |
445 | struct ieee80211_channel **chan, | 447 | struct ieee80211_channel **chan, |
446 | enum cfg80211_chan_mode *chanmode); | 448 | enum cfg80211_chan_mode *chanmode, |
449 | u8 *radar_detect); | ||
447 | 450 | ||
448 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, | 451 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, |
449 | struct cfg80211_chan_def *chandef); | 452 | struct cfg80211_chan_def *chandef); |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index f911c5f9f903..1470b90e438f 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -14,7 +14,8 @@ | |||
14 | #include "rdev-ops.h" | 14 | #include "rdev-ops.h" |
15 | 15 | ||
16 | 16 | ||
17 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) | 17 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, |
18 | struct ieee80211_channel *channel) | ||
18 | { | 19 | { |
19 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 20 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
20 | struct cfg80211_bss *bss; | 21 | struct cfg80211_bss *bss; |
@@ -28,8 +29,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) | |||
28 | if (!wdev->ssid_len) | 29 | if (!wdev->ssid_len) |
29 | return; | 30 | return; |
30 | 31 | ||
31 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 32 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0, |
32 | wdev->ssid, wdev->ssid_len, | ||
33 | WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); | 33 | WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); |
34 | 34 | ||
35 | if (WARN_ON(!bss)) | 35 | if (WARN_ON(!bss)) |
@@ -54,21 +54,26 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) | |||
54 | #endif | 54 | #endif |
55 | } | 55 | } |
56 | 56 | ||
57 | void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) | 57 | void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, |
58 | struct ieee80211_channel *channel, gfp_t gfp) | ||
58 | { | 59 | { |
59 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 60 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
60 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 61 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
61 | struct cfg80211_event *ev; | 62 | struct cfg80211_event *ev; |
62 | unsigned long flags; | 63 | unsigned long flags; |
63 | 64 | ||
64 | trace_cfg80211_ibss_joined(dev, bssid); | 65 | trace_cfg80211_ibss_joined(dev, bssid, channel); |
66 | |||
67 | if (WARN_ON(!channel)) | ||
68 | return; | ||
65 | 69 | ||
66 | ev = kzalloc(sizeof(*ev), gfp); | 70 | ev = kzalloc(sizeof(*ev), gfp); |
67 | if (!ev) | 71 | if (!ev) |
68 | return; | 72 | return; |
69 | 73 | ||
70 | ev->type = EVENT_IBSS_JOINED; | 74 | ev->type = EVENT_IBSS_JOINED; |
71 | memcpy(ev->cr.bssid, bssid, ETH_ALEN); | 75 | memcpy(ev->ij.bssid, bssid, ETH_ALEN); |
76 | ev->ij.channel = channel; | ||
72 | 77 | ||
73 | spin_lock_irqsave(&wdev->event_lock, flags); | 78 | spin_lock_irqsave(&wdev->event_lock, flags); |
74 | list_add_tail(&ev->list, &wdev->event_list); | 79 | list_add_tail(&ev->list, &wdev->event_list); |
@@ -117,6 +122,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
117 | 122 | ||
118 | wdev->ibss_fixed = params->channel_fixed; | 123 | wdev->ibss_fixed = params->channel_fixed; |
119 | wdev->ibss_dfs_possible = params->userspace_handles_dfs; | 124 | wdev->ibss_dfs_possible = params->userspace_handles_dfs; |
125 | wdev->chandef = params->chandef; | ||
120 | #ifdef CONFIG_CFG80211_WEXT | 126 | #ifdef CONFIG_CFG80211_WEXT |
121 | wdev->wext.ibss.chandef = params->chandef; | 127 | wdev->wext.ibss.chandef = params->chandef; |
122 | #endif | 128 | #endif |
@@ -200,6 +206,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
200 | 206 | ||
201 | wdev->current_bss = NULL; | 207 | wdev->current_bss = NULL; |
202 | wdev->ssid_len = 0; | 208 | wdev->ssid_len = 0; |
209 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); | ||
203 | #ifdef CONFIG_CFG80211_WEXT | 210 | #ifdef CONFIG_CFG80211_WEXT |
204 | if (!nowext) | 211 | if (!nowext) |
205 | wdev->wext.ibss.ssid_len = 0; | 212 | wdev->wext.ibss.ssid_len = 0; |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 885862447b63..d42a3fcb2f67 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -195,7 +195,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
195 | if (!err) { | 195 | if (!err) { |
196 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); | 196 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); |
197 | wdev->mesh_id_len = setup->mesh_id_len; | 197 | wdev->mesh_id_len = setup->mesh_id_len; |
198 | wdev->channel = setup->chandef.chan; | 198 | wdev->chandef = setup->chandef; |
199 | } | 199 | } |
200 | 200 | ||
201 | return err; | 201 | return err; |
@@ -244,7 +244,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
244 | err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, | 244 | err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, |
245 | chandef->chan); | 245 | chandef->chan); |
246 | if (!err) | 246 | if (!err) |
247 | wdev->channel = chandef->chan; | 247 | wdev->chandef = *chandef; |
248 | 248 | ||
249 | return err; | 249 | return err; |
250 | } | 250 | } |
@@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | |||
276 | err = rdev_leave_mesh(rdev, dev); | 276 | err = rdev_leave_mesh(rdev, dev); |
277 | if (!err) { | 277 | if (!err) { |
278 | wdev->mesh_id_len = 0; | 278 | wdev->mesh_id_len = 0; |
279 | wdev->channel = NULL; | 279 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); |
280 | rdev_set_qos_map(rdev, dev, NULL); | 280 | rdev_set_qos_map(rdev, dev, NULL); |
281 | } | 281 | } |
282 | 282 | ||
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 52cca05044a8..d47c9d127b1e 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -772,7 +772,7 @@ void cfg80211_cac_event(struct net_device *netdev, | |||
772 | if (WARN_ON(!wdev->cac_started)) | 772 | if (WARN_ON(!wdev->cac_started)) |
773 | return; | 773 | return; |
774 | 774 | ||
775 | if (WARN_ON(!wdev->channel)) | 775 | if (WARN_ON(!wdev->chandef.chan)) |
776 | return; | 776 | return; |
777 | 777 | ||
778 | switch (event) { | 778 | switch (event) { |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4fe2e6e2bc76..8e6b6a2d35cb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -382,6 +382,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
382 | [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, | 382 | [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, |
383 | [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY, | 383 | [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY, |
384 | .len = IEEE80211_QOS_MAP_LEN_MAX }, | 384 | .len = IEEE80211_QOS_MAP_LEN_MAX }, |
385 | [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, | ||
386 | [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, | ||
385 | }; | 387 | }; |
386 | 388 | ||
387 | /* policy for the key attributes */ | 389 | /* policy for the key attributes */ |
@@ -855,6 +857,19 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
855 | return 0; | 857 | return 0; |
856 | } | 858 | } |
857 | 859 | ||
860 | static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy, | ||
861 | struct nlattr *tb) | ||
862 | { | ||
863 | struct ieee80211_channel *chan; | ||
864 | |||
865 | if (tb == NULL) | ||
866 | return NULL; | ||
867 | chan = ieee80211_get_channel(wiphy, nla_get_u32(tb)); | ||
868 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | ||
869 | return NULL; | ||
870 | return chan; | ||
871 | } | ||
872 | |||
858 | static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) | 873 | static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) |
859 | { | 874 | { |
860 | struct nlattr *nl_modes = nla_nest_start(msg, attr); | 875 | struct nlattr *nl_modes = nla_nest_start(msg, attr); |
@@ -1586,6 +1601,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1586 | (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) || | 1601 | (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) || |
1587 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ))) | 1602 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ))) |
1588 | goto nla_put_failure; | 1603 | goto nla_put_failure; |
1604 | |||
1605 | if (dev->wiphy.max_ap_assoc_sta && | ||
1606 | nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA, | ||
1607 | dev->wiphy.max_ap_assoc_sta)) | ||
1608 | goto nla_put_failure; | ||
1609 | |||
1589 | state->split_start++; | 1610 | state->split_start++; |
1590 | break; | 1611 | break; |
1591 | case 11: | 1612 | case 11: |
@@ -2035,10 +2056,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
2035 | nla_for_each_nested(nl_txq_params, | 2056 | nla_for_each_nested(nl_txq_params, |
2036 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], | 2057 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], |
2037 | rem_txq_params) { | 2058 | rem_txq_params) { |
2038 | nla_parse(tb, NL80211_TXQ_ATTR_MAX, | 2059 | result = nla_parse(tb, NL80211_TXQ_ATTR_MAX, |
2039 | nla_data(nl_txq_params), | 2060 | nla_data(nl_txq_params), |
2040 | nla_len(nl_txq_params), | 2061 | nla_len(nl_txq_params), |
2041 | txq_params_policy); | 2062 | txq_params_policy); |
2063 | if (result) | ||
2064 | return result; | ||
2042 | result = parse_txq_params(tb, &txq_params); | 2065 | result = parse_txq_params(tb, &txq_params); |
2043 | if (result) | 2066 | if (result) |
2044 | return result; | 2067 | return result; |
@@ -3259,7 +3282,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
3259 | if (!err) { | 3282 | if (!err) { |
3260 | wdev->preset_chandef = params.chandef; | 3283 | wdev->preset_chandef = params.chandef; |
3261 | wdev->beacon_interval = params.beacon_interval; | 3284 | wdev->beacon_interval = params.beacon_interval; |
3262 | wdev->channel = params.chandef.chan; | 3285 | wdev->chandef = params.chandef; |
3263 | wdev->ssid_len = params.ssid_len; | 3286 | wdev->ssid_len = params.ssid_len; |
3264 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); | 3287 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); |
3265 | } | 3288 | } |
@@ -3902,8 +3925,8 @@ static struct net_device *get_vlan(struct genl_info *info, | |||
3902 | return ERR_PTR(ret); | 3925 | return ERR_PTR(ret); |
3903 | } | 3926 | } |
3904 | 3927 | ||
3905 | static struct nla_policy | 3928 | static const struct nla_policy |
3906 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | 3929 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = { |
3907 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, | 3930 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, |
3908 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | 3931 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, |
3909 | }; | 3932 | }; |
@@ -4604,8 +4627,6 @@ static int parse_reg_rule(struct nlattr *tb[], | |||
4604 | return -EINVAL; | 4627 | return -EINVAL; |
4605 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) | 4628 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) |
4606 | return -EINVAL; | 4629 | return -EINVAL; |
4607 | if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) | ||
4608 | return -EINVAL; | ||
4609 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) | 4630 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) |
4610 | return -EINVAL; | 4631 | return -EINVAL; |
4611 | 4632 | ||
@@ -4615,8 +4636,9 @@ static int parse_reg_rule(struct nlattr *tb[], | |||
4615 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); | 4636 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); |
4616 | freq_range->end_freq_khz = | 4637 | freq_range->end_freq_khz = |
4617 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); | 4638 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); |
4618 | freq_range->max_bandwidth_khz = | 4639 | if (tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) |
4619 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); | 4640 | freq_range->max_bandwidth_khz = |
4641 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); | ||
4620 | 4642 | ||
4621 | power_rule->max_eirp = | 4643 | power_rule->max_eirp = |
4622 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); | 4644 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); |
@@ -5086,6 +5108,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
5086 | const struct ieee80211_reg_rule *reg_rule; | 5108 | const struct ieee80211_reg_rule *reg_rule; |
5087 | const struct ieee80211_freq_range *freq_range; | 5109 | const struct ieee80211_freq_range *freq_range; |
5088 | const struct ieee80211_power_rule *power_rule; | 5110 | const struct ieee80211_power_rule *power_rule; |
5111 | unsigned int max_bandwidth_khz; | ||
5089 | 5112 | ||
5090 | reg_rule = ®dom->reg_rules[i]; | 5113 | reg_rule = ®dom->reg_rules[i]; |
5091 | freq_range = ®_rule->freq_range; | 5114 | freq_range = ®_rule->freq_range; |
@@ -5095,6 +5118,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
5095 | if (!nl_reg_rule) | 5118 | if (!nl_reg_rule) |
5096 | goto nla_put_failure_rcu; | 5119 | goto nla_put_failure_rcu; |
5097 | 5120 | ||
5121 | max_bandwidth_khz = freq_range->max_bandwidth_khz; | ||
5122 | if (!max_bandwidth_khz) | ||
5123 | max_bandwidth_khz = reg_get_max_bandwidth(regdom, | ||
5124 | reg_rule); | ||
5125 | |||
5098 | if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS, | 5126 | if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS, |
5099 | reg_rule->flags) || | 5127 | reg_rule->flags) || |
5100 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START, | 5128 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START, |
@@ -5102,7 +5130,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
5102 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END, | 5130 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END, |
5103 | freq_range->end_freq_khz) || | 5131 | freq_range->end_freq_khz) || |
5104 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW, | 5132 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW, |
5105 | freq_range->max_bandwidth_khz) || | 5133 | max_bandwidth_khz) || |
5106 | nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, | 5134 | nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, |
5107 | power_rule->max_antenna_gain) || | 5135 | power_rule->max_antenna_gain) || |
5108 | nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, | 5136 | nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, |
@@ -5178,9 +5206,11 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
5178 | 5206 | ||
5179 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 5207 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
5180 | rem_reg_rules) { | 5208 | rem_reg_rules) { |
5181 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, | 5209 | r = nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, |
5182 | nla_data(nl_reg_rule), nla_len(nl_reg_rule), | 5210 | nla_data(nl_reg_rule), nla_len(nl_reg_rule), |
5183 | reg_rule_policy); | 5211 | reg_rule_policy); |
5212 | if (r) | ||
5213 | goto bad_reg; | ||
5184 | r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); | 5214 | r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); |
5185 | if (r) | 5215 | if (r) |
5186 | goto bad_reg; | 5216 | goto bad_reg; |
@@ -5443,6 +5473,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5443 | enum ieee80211_band band; | 5473 | enum ieee80211_band band; |
5444 | size_t ie_len; | 5474 | size_t ie_len; |
5445 | struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; | 5475 | struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; |
5476 | s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF; | ||
5446 | 5477 | ||
5447 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | 5478 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || |
5448 | !rdev->ops->sched_scan_start) | 5479 | !rdev->ops->sched_scan_start) |
@@ -5477,11 +5508,40 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5477 | if (n_ssids > wiphy->max_sched_scan_ssids) | 5508 | if (n_ssids > wiphy->max_sched_scan_ssids) |
5478 | return -EINVAL; | 5509 | return -EINVAL; |
5479 | 5510 | ||
5480 | if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) | 5511 | /* |
5512 | * First, count the number of 'real' matchsets. Due to an issue with | ||
5513 | * the old implementation, matchsets containing only the RSSI attribute | ||
5514 | * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default' | ||
5515 | * RSSI for all matchsets, rather than their own matchset for reporting | ||
5516 | * all APs with a strong RSSI. This is needed to be compatible with | ||
5517 | * older userspace that treated a matchset with only the RSSI as the | ||
5518 | * global RSSI for all other matchsets - if there are other matchsets. | ||
5519 | */ | ||
5520 | if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { | ||
5481 | nla_for_each_nested(attr, | 5521 | nla_for_each_nested(attr, |
5482 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], | 5522 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], |
5483 | tmp) | 5523 | tmp) { |
5484 | n_match_sets++; | 5524 | struct nlattr *rssi; |
5525 | |||
5526 | err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, | ||
5527 | nla_data(attr), nla_len(attr), | ||
5528 | nl80211_match_policy); | ||
5529 | if (err) | ||
5530 | return err; | ||
5531 | /* add other standalone attributes here */ | ||
5532 | if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) { | ||
5533 | n_match_sets++; | ||
5534 | continue; | ||
5535 | } | ||
5536 | rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; | ||
5537 | if (rssi) | ||
5538 | default_match_rssi = nla_get_s32(rssi); | ||
5539 | } | ||
5540 | } | ||
5541 | |||
5542 | /* However, if there's no other matchset, add the RSSI one */ | ||
5543 | if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF) | ||
5544 | n_match_sets = 1; | ||
5485 | 5545 | ||
5486 | if (n_match_sets > wiphy->max_match_sets) | 5546 | if (n_match_sets > wiphy->max_match_sets) |
5487 | return -EINVAL; | 5547 | return -EINVAL; |
@@ -5602,11 +5662,22 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5602 | tmp) { | 5662 | tmp) { |
5603 | struct nlattr *ssid, *rssi; | 5663 | struct nlattr *ssid, *rssi; |
5604 | 5664 | ||
5605 | nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, | 5665 | err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, |
5606 | nla_data(attr), nla_len(attr), | 5666 | nla_data(attr), nla_len(attr), |
5607 | nl80211_match_policy); | 5667 | nl80211_match_policy); |
5668 | if (err) | ||
5669 | goto out_free; | ||
5608 | ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; | 5670 | ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; |
5609 | if (ssid) { | 5671 | if (ssid) { |
5672 | if (WARN_ON(i >= n_match_sets)) { | ||
5673 | /* this indicates a programming error, | ||
5674 | * the loop above should have verified | ||
5675 | * things properly | ||
5676 | */ | ||
5677 | err = -EINVAL; | ||
5678 | goto out_free; | ||
5679 | } | ||
5680 | |||
5610 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { | 5681 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { |
5611 | err = -EINVAL; | 5682 | err = -EINVAL; |
5612 | goto out_free; | 5683 | goto out_free; |
@@ -5615,15 +5686,28 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5615 | nla_data(ssid), nla_len(ssid)); | 5686 | nla_data(ssid), nla_len(ssid)); |
5616 | request->match_sets[i].ssid.ssid_len = | 5687 | request->match_sets[i].ssid.ssid_len = |
5617 | nla_len(ssid); | 5688 | nla_len(ssid); |
5689 | /* special attribute - old implemenation w/a */ | ||
5690 | request->match_sets[i].rssi_thold = | ||
5691 | default_match_rssi; | ||
5692 | rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; | ||
5693 | if (rssi) | ||
5694 | request->match_sets[i].rssi_thold = | ||
5695 | nla_get_s32(rssi); | ||
5618 | } | 5696 | } |
5619 | rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; | ||
5620 | if (rssi) | ||
5621 | request->rssi_thold = nla_get_u32(rssi); | ||
5622 | else | ||
5623 | request->rssi_thold = | ||
5624 | NL80211_SCAN_RSSI_THOLD_OFF; | ||
5625 | i++; | 5697 | i++; |
5626 | } | 5698 | } |
5699 | |||
5700 | /* there was no other matchset, so the RSSI one is alone */ | ||
5701 | if (i == 0) | ||
5702 | request->match_sets[0].rssi_thold = default_match_rssi; | ||
5703 | |||
5704 | request->min_rssi_thold = INT_MAX; | ||
5705 | for (i = 0; i < n_match_sets; i++) | ||
5706 | request->min_rssi_thold = | ||
5707 | min(request->match_sets[i].rssi_thold, | ||
5708 | request->min_rssi_thold); | ||
5709 | } else { | ||
5710 | request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF; | ||
5627 | } | 5711 | } |
5628 | 5712 | ||
5629 | if (info->attrs[NL80211_ATTR_IE]) { | 5713 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -5719,7 +5803,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5719 | 5803 | ||
5720 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); | 5804 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); |
5721 | if (!err) { | 5805 | if (!err) { |
5722 | wdev->channel = chandef.chan; | 5806 | wdev->chandef = chandef; |
5723 | wdev->cac_started = true; | 5807 | wdev->cac_started = true; |
5724 | wdev->cac_start_time = jiffies; | 5808 | wdev->cac_start_time = jiffies; |
5725 | } | 5809 | } |
@@ -5751,10 +5835,15 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5751 | 5835 | ||
5752 | /* useless if AP is not running */ | 5836 | /* useless if AP is not running */ |
5753 | if (!wdev->beacon_interval) | 5837 | if (!wdev->beacon_interval) |
5754 | return -EINVAL; | 5838 | return -ENOTCONN; |
5755 | break; | 5839 | break; |
5756 | case NL80211_IFTYPE_ADHOC: | 5840 | case NL80211_IFTYPE_ADHOC: |
5841 | if (!wdev->ssid_len) | ||
5842 | return -ENOTCONN; | ||
5843 | break; | ||
5757 | case NL80211_IFTYPE_MESH_POINT: | 5844 | case NL80211_IFTYPE_MESH_POINT: |
5845 | if (!wdev->mesh_id_len) | ||
5846 | return -ENOTCONN; | ||
5758 | break; | 5847 | break; |
5759 | default: | 5848 | default: |
5760 | return -EOPNOTSUPP; | 5849 | return -EOPNOTSUPP; |
@@ -6192,9 +6281,9 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
6192 | return -EOPNOTSUPP; | 6281 | return -EOPNOTSUPP; |
6193 | 6282 | ||
6194 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 6283 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
6195 | chan = ieee80211_get_channel(&rdev->wiphy, | 6284 | chan = nl80211_get_valid_chan(&rdev->wiphy, |
6196 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 6285 | info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
6197 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) | 6286 | if (!chan) |
6198 | return -EINVAL; | 6287 | return -EINVAL; |
6199 | 6288 | ||
6200 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 6289 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
@@ -6347,9 +6436,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
6347 | 6436 | ||
6348 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 6437 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
6349 | 6438 | ||
6350 | chan = ieee80211_get_channel(&rdev->wiphy, | 6439 | chan = nl80211_get_valid_chan(&rdev->wiphy, |
6351 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 6440 | info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
6352 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) | 6441 | if (!chan) |
6353 | return -EINVAL; | 6442 | return -EINVAL; |
6354 | 6443 | ||
6355 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 6444 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
@@ -6985,6 +7074,9 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
6985 | 7074 | ||
6986 | if (info->attrs[NL80211_ATTR_MAC]) | 7075 | if (info->attrs[NL80211_ATTR_MAC]) |
6987 | connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 7076 | connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
7077 | else if (info->attrs[NL80211_ATTR_MAC_HINT]) | ||
7078 | connect.bssid_hint = | ||
7079 | nla_data(info->attrs[NL80211_ATTR_MAC_HINT]); | ||
6988 | connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 7080 | connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
6989 | connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 7081 | connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
6990 | 7082 | ||
@@ -7003,11 +7095,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
7003 | } | 7095 | } |
7004 | 7096 | ||
7005 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 7097 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
7006 | connect.channel = | 7098 | connect.channel = nl80211_get_valid_chan( |
7007 | ieee80211_get_channel(wiphy, | 7099 | wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
7008 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 7100 | if (!connect.channel) |
7009 | if (!connect.channel || | 7101 | return -EINVAL; |
7010 | connect.channel->flags & IEEE80211_CHAN_DISABLED) | 7102 | } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) { |
7103 | connect.channel_hint = nl80211_get_valid_chan( | ||
7104 | wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]); | ||
7105 | if (!connect.channel_hint) | ||
7011 | return -EINVAL; | 7106 | return -EINVAL; |
7012 | } | 7107 | } |
7013 | 7108 | ||
@@ -7421,6 +7516,7 @@ static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { | |||
7421 | [NL80211_TXRATE_HT] = { .type = NLA_BINARY, | 7516 | [NL80211_TXRATE_HT] = { .type = NLA_BINARY, |
7422 | .len = NL80211_MAX_SUPP_HT_RATES }, | 7517 | .len = NL80211_MAX_SUPP_HT_RATES }, |
7423 | [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)}, | 7518 | [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)}, |
7519 | [NL80211_TXRATE_GI] = { .type = NLA_U8 }, | ||
7424 | }; | 7520 | }; |
7425 | 7521 | ||
7426 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | 7522 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, |
@@ -7467,16 +7563,19 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
7467 | * directly to the enum ieee80211_band values used in cfg80211. | 7563 | * directly to the enum ieee80211_band values used in cfg80211. |
7468 | */ | 7564 | */ |
7469 | BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8); | 7565 | BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8); |
7470 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) | 7566 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) { |
7471 | { | ||
7472 | enum ieee80211_band band = nla_type(tx_rates); | 7567 | enum ieee80211_band band = nla_type(tx_rates); |
7568 | int err; | ||
7569 | |||
7473 | if (band < 0 || band >= IEEE80211_NUM_BANDS) | 7570 | if (band < 0 || band >= IEEE80211_NUM_BANDS) |
7474 | return -EINVAL; | 7571 | return -EINVAL; |
7475 | sband = rdev->wiphy.bands[band]; | 7572 | sband = rdev->wiphy.bands[band]; |
7476 | if (sband == NULL) | 7573 | if (sband == NULL) |
7477 | return -EINVAL; | 7574 | return -EINVAL; |
7478 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), | 7575 | err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), |
7479 | nla_len(tx_rates), nl80211_txattr_policy); | 7576 | nla_len(tx_rates), nl80211_txattr_policy); |
7577 | if (err) | ||
7578 | return err; | ||
7480 | if (tb[NL80211_TXRATE_LEGACY]) { | 7579 | if (tb[NL80211_TXRATE_LEGACY]) { |
7481 | mask.control[band].legacy = rateset_to_mask( | 7580 | mask.control[band].legacy = rateset_to_mask( |
7482 | sband, | 7581 | sband, |
@@ -7501,6 +7600,12 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
7501 | mask.control[band].vht_mcs)) | 7600 | mask.control[band].vht_mcs)) |
7502 | return -EINVAL; | 7601 | return -EINVAL; |
7503 | } | 7602 | } |
7603 | if (tb[NL80211_TXRATE_GI]) { | ||
7604 | mask.control[band].gi = | ||
7605 | nla_get_u8(tb[NL80211_TXRATE_GI]); | ||
7606 | if (mask.control[band].gi > NL80211_TXRATE_FORCE_LGI) | ||
7607 | return -EINVAL; | ||
7608 | } | ||
7504 | 7609 | ||
7505 | if (mask.control[band].legacy == 0) { | 7610 | if (mask.control[band].legacy == 0) { |
7506 | /* don't allow empty legacy rates if HT or VHT | 7611 | /* don't allow empty legacy rates if HT or VHT |
@@ -7777,8 +7882,8 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) | |||
7777 | return err; | 7882 | return err; |
7778 | } | 7883 | } |
7779 | 7884 | ||
7780 | static struct nla_policy | 7885 | static const struct nla_policy |
7781 | nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | 7886 | nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { |
7782 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, | 7887 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, |
7783 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, | 7888 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, |
7784 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, | 7889 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, |
@@ -11107,7 +11212,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, | |||
11107 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | 11212 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) |
11108 | return; | 11213 | return; |
11109 | 11214 | ||
11110 | wdev->channel = chandef->chan; | 11215 | wdev->chandef = *chandef; |
11216 | wdev->preset_chandef = *chandef; | ||
11111 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | 11217 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); |
11112 | } | 11218 | } |
11113 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); | 11219 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); |
@@ -11621,6 +11727,35 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp) | |||
11621 | } | 11727 | } |
11622 | EXPORT_SYMBOL(cfg80211_crit_proto_stopped); | 11728 | EXPORT_SYMBOL(cfg80211_crit_proto_stopped); |
11623 | 11729 | ||
11730 | void nl80211_send_ap_stopped(struct wireless_dev *wdev) | ||
11731 | { | ||
11732 | struct wiphy *wiphy = wdev->wiphy; | ||
11733 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
11734 | struct sk_buff *msg; | ||
11735 | void *hdr; | ||
11736 | |||
11737 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
11738 | if (!msg) | ||
11739 | return; | ||
11740 | |||
11741 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP); | ||
11742 | if (!hdr) | ||
11743 | goto out; | ||
11744 | |||
11745 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
11746 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) || | ||
11747 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
11748 | goto out; | ||
11749 | |||
11750 | genlmsg_end(msg, hdr); | ||
11751 | |||
11752 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0, | ||
11753 | NL80211_MCGRP_MLME, GFP_KERNEL); | ||
11754 | return; | ||
11755 | out: | ||
11756 | nlmsg_free(msg); | ||
11757 | } | ||
11758 | |||
11624 | /* initialisation/exit functions */ | 11759 | /* initialisation/exit functions */ |
11625 | 11760 | ||
11626 | int nl80211_init(void) | 11761 | int nl80211_init(void) |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 75799746d845..1e6df9630f42 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -74,6 +74,8 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, | |||
74 | enum nl80211_radar_event event, | 74 | enum nl80211_radar_event event, |
75 | struct net_device *netdev, gfp_t gfp); | 75 | struct net_device *netdev, gfp_t gfp); |
76 | 76 | ||
77 | void nl80211_send_ap_stopped(struct wireless_dev *wdev); | ||
78 | |||
77 | void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev); | 79 | void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev); |
78 | 80 | ||
79 | #endif /* __NET_WIRELESS_NL80211_H */ | 81 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 9b897fca7487..27c5253e7a61 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -91,7 +91,7 @@ static struct regulatory_request __rcu *last_request = | |||
91 | /* To trigger userspace events */ | 91 | /* To trigger userspace events */ |
92 | static struct platform_device *reg_pdev; | 92 | static struct platform_device *reg_pdev; |
93 | 93 | ||
94 | static struct device_type reg_device_type = { | 94 | static const struct device_type reg_device_type = { |
95 | .uevent = reg_device_uevent, | 95 | .uevent = reg_device_uevent, |
96 | }; | 96 | }; |
97 | 97 | ||
@@ -522,6 +522,77 @@ bool reg_is_valid_request(const char *alpha2) | |||
522 | return alpha2_equal(lr->alpha2, alpha2); | 522 | return alpha2_equal(lr->alpha2, alpha2); |
523 | } | 523 | } |
524 | 524 | ||
525 | static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy) | ||
526 | { | ||
527 | struct regulatory_request *lr = get_last_request(); | ||
528 | |||
529 | /* | ||
530 | * Follow the driver's regulatory domain, if present, unless a country | ||
531 | * IE has been processed or a user wants to help complaince further | ||
532 | */ | ||
533 | if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | ||
534 | lr->initiator != NL80211_REGDOM_SET_BY_USER && | ||
535 | wiphy->regd) | ||
536 | return get_wiphy_regdom(wiphy); | ||
537 | |||
538 | return get_cfg80211_regdom(); | ||
539 | } | ||
540 | |||
541 | unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | ||
542 | const struct ieee80211_reg_rule *rule) | ||
543 | { | ||
544 | const struct ieee80211_freq_range *freq_range = &rule->freq_range; | ||
545 | const struct ieee80211_freq_range *freq_range_tmp; | ||
546 | const struct ieee80211_reg_rule *tmp; | ||
547 | u32 start_freq, end_freq, idx, no; | ||
548 | |||
549 | for (idx = 0; idx < rd->n_reg_rules; idx++) | ||
550 | if (rule == &rd->reg_rules[idx]) | ||
551 | break; | ||
552 | |||
553 | if (idx == rd->n_reg_rules) | ||
554 | return 0; | ||
555 | |||
556 | /* get start_freq */ | ||
557 | no = idx; | ||
558 | |||
559 | while (no) { | ||
560 | tmp = &rd->reg_rules[--no]; | ||
561 | freq_range_tmp = &tmp->freq_range; | ||
562 | |||
563 | if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz) | ||
564 | break; | ||
565 | |||
566 | if (freq_range_tmp->max_bandwidth_khz) | ||
567 | break; | ||
568 | |||
569 | freq_range = freq_range_tmp; | ||
570 | } | ||
571 | |||
572 | start_freq = freq_range->start_freq_khz; | ||
573 | |||
574 | /* get end_freq */ | ||
575 | freq_range = &rule->freq_range; | ||
576 | no = idx; | ||
577 | |||
578 | while (no < rd->n_reg_rules - 1) { | ||
579 | tmp = &rd->reg_rules[++no]; | ||
580 | freq_range_tmp = &tmp->freq_range; | ||
581 | |||
582 | if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz) | ||
583 | break; | ||
584 | |||
585 | if (freq_range_tmp->max_bandwidth_khz) | ||
586 | break; | ||
587 | |||
588 | freq_range = freq_range_tmp; | ||
589 | } | ||
590 | |||
591 | end_freq = freq_range->end_freq_khz; | ||
592 | |||
593 | return end_freq - start_freq; | ||
594 | } | ||
595 | |||
525 | /* Sanity check on a regulatory rule */ | 596 | /* Sanity check on a regulatory rule */ |
526 | static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) | 597 | static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) |
527 | { | 598 | { |
@@ -630,7 +701,9 @@ reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1, | |||
630 | * Helper for regdom_intersect(), this does the real | 701 | * Helper for regdom_intersect(), this does the real |
631 | * mathematical intersection fun | 702 | * mathematical intersection fun |
632 | */ | 703 | */ |
633 | static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1, | 704 | static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, |
705 | const struct ieee80211_regdomain *rd2, | ||
706 | const struct ieee80211_reg_rule *rule1, | ||
634 | const struct ieee80211_reg_rule *rule2, | 707 | const struct ieee80211_reg_rule *rule2, |
635 | struct ieee80211_reg_rule *intersected_rule) | 708 | struct ieee80211_reg_rule *intersected_rule) |
636 | { | 709 | { |
@@ -638,7 +711,7 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1, | |||
638 | struct ieee80211_freq_range *freq_range; | 711 | struct ieee80211_freq_range *freq_range; |
639 | const struct ieee80211_power_rule *power_rule1, *power_rule2; | 712 | const struct ieee80211_power_rule *power_rule1, *power_rule2; |
640 | struct ieee80211_power_rule *power_rule; | 713 | struct ieee80211_power_rule *power_rule; |
641 | u32 freq_diff; | 714 | u32 freq_diff, max_bandwidth1, max_bandwidth2; |
642 | 715 | ||
643 | freq_range1 = &rule1->freq_range; | 716 | freq_range1 = &rule1->freq_range; |
644 | freq_range2 = &rule2->freq_range; | 717 | freq_range2 = &rule2->freq_range; |
@@ -652,8 +725,24 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1, | |||
652 | freq_range2->start_freq_khz); | 725 | freq_range2->start_freq_khz); |
653 | freq_range->end_freq_khz = min(freq_range1->end_freq_khz, | 726 | freq_range->end_freq_khz = min(freq_range1->end_freq_khz, |
654 | freq_range2->end_freq_khz); | 727 | freq_range2->end_freq_khz); |
655 | freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz, | 728 | |
656 | freq_range2->max_bandwidth_khz); | 729 | max_bandwidth1 = freq_range1->max_bandwidth_khz; |
730 | max_bandwidth2 = freq_range2->max_bandwidth_khz; | ||
731 | |||
732 | /* | ||
733 | * In case max_bandwidth1 == 0 and max_bandwith2 == 0 set | ||
734 | * output bandwidth as 0 (auto calculation). Next we will | ||
735 | * calculate this correctly in handle_channel function. | ||
736 | * In other case calculate output bandwidth here. | ||
737 | */ | ||
738 | if (max_bandwidth1 || max_bandwidth2) { | ||
739 | if (!max_bandwidth1) | ||
740 | max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1); | ||
741 | if (!max_bandwidth2) | ||
742 | max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2); | ||
743 | } | ||
744 | |||
745 | freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2); | ||
657 | 746 | ||
658 | freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; | 747 | freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; |
659 | if (freq_range->max_bandwidth_khz > freq_diff) | 748 | if (freq_range->max_bandwidth_khz > freq_diff) |
@@ -713,7 +802,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, | |||
713 | rule1 = &rd1->reg_rules[x]; | 802 | rule1 = &rd1->reg_rules[x]; |
714 | for (y = 0; y < rd2->n_reg_rules; y++) { | 803 | for (y = 0; y < rd2->n_reg_rules; y++) { |
715 | rule2 = &rd2->reg_rules[y]; | 804 | rule2 = &rd2->reg_rules[y]; |
716 | if (!reg_rules_intersect(rule1, rule2, &dummy_rule)) | 805 | if (!reg_rules_intersect(rd1, rd2, rule1, rule2, |
806 | &dummy_rule)) | ||
717 | num_rules++; | 807 | num_rules++; |
718 | } | 808 | } |
719 | } | 809 | } |
@@ -738,7 +828,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, | |||
738 | * a memcpy() | 828 | * a memcpy() |
739 | */ | 829 | */ |
740 | intersected_rule = &rd->reg_rules[rule_idx]; | 830 | intersected_rule = &rd->reg_rules[rule_idx]; |
741 | r = reg_rules_intersect(rule1, rule2, intersected_rule); | 831 | r = reg_rules_intersect(rd1, rd2, rule1, rule2, |
832 | intersected_rule); | ||
742 | /* | 833 | /* |
743 | * No need to memset here the intersected rule here as | 834 | * No need to memset here the intersected rule here as |
744 | * we're not using the stack anymore | 835 | * we're not using the stack anymore |
@@ -821,18 +912,8 @@ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy, | |||
821 | u32 center_freq) | 912 | u32 center_freq) |
822 | { | 913 | { |
823 | const struct ieee80211_regdomain *regd; | 914 | const struct ieee80211_regdomain *regd; |
824 | struct regulatory_request *lr = get_last_request(); | ||
825 | 915 | ||
826 | /* | 916 | regd = reg_get_regdomain(wiphy); |
827 | * Follow the driver's regulatory domain, if present, unless a country | ||
828 | * IE has been processed or a user wants to help complaince further | ||
829 | */ | ||
830 | if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | ||
831 | lr->initiator != NL80211_REGDOM_SET_BY_USER && | ||
832 | wiphy->regd) | ||
833 | regd = get_wiphy_regdom(wiphy); | ||
834 | else | ||
835 | regd = get_cfg80211_regdom(); | ||
836 | 917 | ||
837 | return freq_reg_info_regd(wiphy, center_freq, regd); | 918 | return freq_reg_info_regd(wiphy, center_freq, regd); |
838 | } | 919 | } |
@@ -903,6 +984,8 @@ static void handle_channel(struct wiphy *wiphy, | |||
903 | const struct ieee80211_freq_range *freq_range = NULL; | 984 | const struct ieee80211_freq_range *freq_range = NULL; |
904 | struct wiphy *request_wiphy = NULL; | 985 | struct wiphy *request_wiphy = NULL; |
905 | struct regulatory_request *lr = get_last_request(); | 986 | struct regulatory_request *lr = get_last_request(); |
987 | const struct ieee80211_regdomain *regd; | ||
988 | u32 max_bandwidth_khz; | ||
906 | 989 | ||
907 | request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); | 990 | request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); |
908 | 991 | ||
@@ -944,11 +1027,18 @@ static void handle_channel(struct wiphy *wiphy, | |||
944 | power_rule = ®_rule->power_rule; | 1027 | power_rule = ®_rule->power_rule; |
945 | freq_range = ®_rule->freq_range; | 1028 | freq_range = ®_rule->freq_range; |
946 | 1029 | ||
947 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) | 1030 | max_bandwidth_khz = freq_range->max_bandwidth_khz; |
1031 | /* Check if auto calculation requested */ | ||
1032 | if (!max_bandwidth_khz) { | ||
1033 | regd = reg_get_regdomain(wiphy); | ||
1034 | max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); | ||
1035 | } | ||
1036 | |||
1037 | if (max_bandwidth_khz < MHZ_TO_KHZ(40)) | ||
948 | bw_flags = IEEE80211_CHAN_NO_HT40; | 1038 | bw_flags = IEEE80211_CHAN_NO_HT40; |
949 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) | 1039 | if (max_bandwidth_khz < MHZ_TO_KHZ(80)) |
950 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; | 1040 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; |
951 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) | 1041 | if (max_bandwidth_khz < MHZ_TO_KHZ(160)) |
952 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; | 1042 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; |
953 | 1043 | ||
954 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && | 1044 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
@@ -1334,6 +1424,7 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1334 | const struct ieee80211_reg_rule *reg_rule = NULL; | 1424 | const struct ieee80211_reg_rule *reg_rule = NULL; |
1335 | const struct ieee80211_power_rule *power_rule = NULL; | 1425 | const struct ieee80211_power_rule *power_rule = NULL; |
1336 | const struct ieee80211_freq_range *freq_range = NULL; | 1426 | const struct ieee80211_freq_range *freq_range = NULL; |
1427 | u32 max_bandwidth_khz; | ||
1337 | 1428 | ||
1338 | reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), | 1429 | reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), |
1339 | regd); | 1430 | regd); |
@@ -1351,11 +1442,16 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1351 | power_rule = ®_rule->power_rule; | 1442 | power_rule = ®_rule->power_rule; |
1352 | freq_range = ®_rule->freq_range; | 1443 | freq_range = ®_rule->freq_range; |
1353 | 1444 | ||
1354 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) | 1445 | max_bandwidth_khz = freq_range->max_bandwidth_khz; |
1446 | /* Check if auto calculation requested */ | ||
1447 | if (!max_bandwidth_khz) | ||
1448 | max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); | ||
1449 | |||
1450 | if (max_bandwidth_khz < MHZ_TO_KHZ(40)) | ||
1355 | bw_flags = IEEE80211_CHAN_NO_HT40; | 1451 | bw_flags = IEEE80211_CHAN_NO_HT40; |
1356 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) | 1452 | if (max_bandwidth_khz < MHZ_TO_KHZ(80)) |
1357 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; | 1453 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; |
1358 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) | 1454 | if (max_bandwidth_khz < MHZ_TO_KHZ(160)) |
1359 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; | 1455 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; |
1360 | 1456 | ||
1361 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1457 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; |
@@ -1683,17 +1779,9 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1683 | struct wiphy *wiphy = NULL; | 1779 | struct wiphy *wiphy = NULL; |
1684 | enum reg_request_treatment treatment; | 1780 | enum reg_request_treatment treatment; |
1685 | 1781 | ||
1686 | if (WARN_ON(!reg_request->alpha2)) | ||
1687 | return; | ||
1688 | |||
1689 | if (reg_request->wiphy_idx != WIPHY_IDX_INVALID) | 1782 | if (reg_request->wiphy_idx != WIPHY_IDX_INVALID) |
1690 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); | 1783 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); |
1691 | 1784 | ||
1692 | if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) { | ||
1693 | kfree(reg_request); | ||
1694 | return; | ||
1695 | } | ||
1696 | |||
1697 | switch (reg_request->initiator) { | 1785 | switch (reg_request->initiator) { |
1698 | case NL80211_REGDOM_SET_BY_CORE: | 1786 | case NL80211_REGDOM_SET_BY_CORE: |
1699 | reg_process_hint_core(reg_request); | 1787 | reg_process_hint_core(reg_request); |
@@ -1703,23 +1791,33 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1703 | if (treatment == REG_REQ_OK || | 1791 | if (treatment == REG_REQ_OK || |
1704 | treatment == REG_REQ_ALREADY_SET) | 1792 | treatment == REG_REQ_ALREADY_SET) |
1705 | return; | 1793 | return; |
1706 | schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); | 1794 | queue_delayed_work(system_power_efficient_wq, |
1795 | ®_timeout, msecs_to_jiffies(3142)); | ||
1707 | return; | 1796 | return; |
1708 | case NL80211_REGDOM_SET_BY_DRIVER: | 1797 | case NL80211_REGDOM_SET_BY_DRIVER: |
1798 | if (!wiphy) | ||
1799 | goto out_free; | ||
1709 | treatment = reg_process_hint_driver(wiphy, reg_request); | 1800 | treatment = reg_process_hint_driver(wiphy, reg_request); |
1710 | break; | 1801 | break; |
1711 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | 1802 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: |
1803 | if (!wiphy) | ||
1804 | goto out_free; | ||
1712 | treatment = reg_process_hint_country_ie(wiphy, reg_request); | 1805 | treatment = reg_process_hint_country_ie(wiphy, reg_request); |
1713 | break; | 1806 | break; |
1714 | default: | 1807 | default: |
1715 | WARN(1, "invalid initiator %d\n", reg_request->initiator); | 1808 | WARN(1, "invalid initiator %d\n", reg_request->initiator); |
1716 | return; | 1809 | goto out_free; |
1717 | } | 1810 | } |
1718 | 1811 | ||
1719 | /* This is required so that the orig_* parameters are saved */ | 1812 | /* This is required so that the orig_* parameters are saved */ |
1720 | if (treatment == REG_REQ_ALREADY_SET && wiphy && | 1813 | if (treatment == REG_REQ_ALREADY_SET && wiphy && |
1721 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) | 1814 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) |
1722 | wiphy_update_regulatory(wiphy, reg_request->initiator); | 1815 | wiphy_update_regulatory(wiphy, reg_request->initiator); |
1816 | |||
1817 | return; | ||
1818 | |||
1819 | out_free: | ||
1820 | kfree(reg_request); | ||
1723 | } | 1821 | } |
1724 | 1822 | ||
1725 | /* | 1823 | /* |
@@ -2147,6 +2245,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
2147 | const struct ieee80211_reg_rule *reg_rule = NULL; | 2245 | const struct ieee80211_reg_rule *reg_rule = NULL; |
2148 | const struct ieee80211_freq_range *freq_range = NULL; | 2246 | const struct ieee80211_freq_range *freq_range = NULL; |
2149 | const struct ieee80211_power_rule *power_rule = NULL; | 2247 | const struct ieee80211_power_rule *power_rule = NULL; |
2248 | char bw[32]; | ||
2150 | 2249 | ||
2151 | pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); | 2250 | pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); |
2152 | 2251 | ||
@@ -2155,22 +2254,29 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
2155 | freq_range = ®_rule->freq_range; | 2254 | freq_range = ®_rule->freq_range; |
2156 | power_rule = ®_rule->power_rule; | 2255 | power_rule = ®_rule->power_rule; |
2157 | 2256 | ||
2257 | if (!freq_range->max_bandwidth_khz) | ||
2258 | snprintf(bw, 32, "%d KHz, AUTO", | ||
2259 | reg_get_max_bandwidth(rd, reg_rule)); | ||
2260 | else | ||
2261 | snprintf(bw, 32, "%d KHz", | ||
2262 | freq_range->max_bandwidth_khz); | ||
2263 | |||
2158 | /* | 2264 | /* |
2159 | * There may not be documentation for max antenna gain | 2265 | * There may not be documentation for max antenna gain |
2160 | * in certain regions | 2266 | * in certain regions |
2161 | */ | 2267 | */ |
2162 | if (power_rule->max_antenna_gain) | 2268 | if (power_rule->max_antenna_gain) |
2163 | pr_info(" (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n", | 2269 | pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n", |
2164 | freq_range->start_freq_khz, | 2270 | freq_range->start_freq_khz, |
2165 | freq_range->end_freq_khz, | 2271 | freq_range->end_freq_khz, |
2166 | freq_range->max_bandwidth_khz, | 2272 | bw, |
2167 | power_rule->max_antenna_gain, | 2273 | power_rule->max_antenna_gain, |
2168 | power_rule->max_eirp); | 2274 | power_rule->max_eirp); |
2169 | else | 2275 | else |
2170 | pr_info(" (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n", | 2276 | pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n", |
2171 | freq_range->start_freq_khz, | 2277 | freq_range->start_freq_khz, |
2172 | freq_range->end_freq_khz, | 2278 | freq_range->end_freq_khz, |
2173 | freq_range->max_bandwidth_khz, | 2279 | bw, |
2174 | power_rule->max_eirp); | 2280 | power_rule->max_eirp); |
2175 | } | 2281 | } |
2176 | } | 2282 | } |
@@ -2294,7 +2400,8 @@ static int reg_set_rd_driver(const struct ieee80211_regdomain *rd, | |||
2294 | 2400 | ||
2295 | request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx); | 2401 | request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx); |
2296 | if (!request_wiphy) { | 2402 | if (!request_wiphy) { |
2297 | schedule_delayed_work(®_timeout, 0); | 2403 | queue_delayed_work(system_power_efficient_wq, |
2404 | ®_timeout, 0); | ||
2298 | return -ENODEV; | 2405 | return -ENODEV; |
2299 | } | 2406 | } |
2300 | 2407 | ||
@@ -2354,7 +2461,8 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd, | |||
2354 | 2461 | ||
2355 | request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx); | 2462 | request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx); |
2356 | if (!request_wiphy) { | 2463 | if (!request_wiphy) { |
2357 | schedule_delayed_work(®_timeout, 0); | 2464 | queue_delayed_work(system_power_efficient_wq, |
2465 | ®_timeout, 0); | ||
2358 | return -ENODEV; | 2466 | return -ENODEV; |
2359 | } | 2467 | } |
2360 | 2468 | ||
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 02bd8f4b0921..18524617ab62 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -34,6 +34,8 @@ int __init regulatory_init(void); | |||
34 | void regulatory_exit(void); | 34 | void regulatory_exit(void); |
35 | 35 | ||
36 | int set_regdom(const struct ieee80211_regdomain *rd); | 36 | int set_regdom(const struct ieee80211_regdomain *rd); |
37 | unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | ||
38 | const struct ieee80211_reg_rule *rule); | ||
37 | 39 | ||
38 | bool reg_last_request_cell_base(void); | 40 | bool reg_last_request_cell_base(void); |
39 | 41 | ||
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index fbcc23edee54..5eaeed59db07 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -2278,11 +2278,6 @@ DECLARE_EVENT_CLASS(cfg80211_rx_evt, | |||
2278 | TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr)) | 2278 | TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr)) |
2279 | ); | 2279 | ); |
2280 | 2280 | ||
2281 | DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined, | ||
2282 | TP_PROTO(struct net_device *netdev, const u8 *addr), | ||
2283 | TP_ARGS(netdev, addr) | ||
2284 | ); | ||
2285 | |||
2286 | DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame, | 2281 | DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame, |
2287 | TP_PROTO(struct net_device *netdev, const u8 *addr), | 2282 | TP_PROTO(struct net_device *netdev, const u8 *addr), |
2288 | TP_ARGS(netdev, addr) | 2283 | TP_ARGS(netdev, addr) |
@@ -2293,6 +2288,24 @@ DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_unexpected_4addr_frame, | |||
2293 | TP_ARGS(netdev, addr) | 2288 | TP_ARGS(netdev, addr) |
2294 | ); | 2289 | ); |
2295 | 2290 | ||
2291 | TRACE_EVENT(cfg80211_ibss_joined, | ||
2292 | TP_PROTO(struct net_device *netdev, const u8 *bssid, | ||
2293 | struct ieee80211_channel *channel), | ||
2294 | TP_ARGS(netdev, bssid, channel), | ||
2295 | TP_STRUCT__entry( | ||
2296 | NETDEV_ENTRY | ||
2297 | MAC_ENTRY(bssid) | ||
2298 | CHAN_ENTRY | ||
2299 | ), | ||
2300 | TP_fast_assign( | ||
2301 | NETDEV_ASSIGN; | ||
2302 | MAC_ASSIGN(bssid, bssid); | ||
2303 | CHAN_ASSIGN(channel); | ||
2304 | ), | ||
2305 | TP_printk(NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", " CHAN_PR_FMT, | ||
2306 | NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) | ||
2307 | ); | ||
2308 | |||
2296 | TRACE_EVENT(cfg80211_probe_status, | 2309 | TRACE_EVENT(cfg80211_probe_status, |
2297 | TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie, | 2310 | TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie, |
2298 | bool acked), | 2311 | bool acked), |
diff --git a/net/wireless/util.c b/net/wireless/util.c index d39c37104ae2..780b4546c9c7 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -820,7 +820,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) | |||
820 | ev->dc.reason, true); | 820 | ev->dc.reason, true); |
821 | break; | 821 | break; |
822 | case EVENT_IBSS_JOINED: | 822 | case EVENT_IBSS_JOINED: |
823 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); | 823 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid, |
824 | ev->ij.channel); | ||
824 | break; | 825 | break; |
825 | } | 826 | } |
826 | wdev_unlock(wdev); | 827 | wdev_unlock(wdev); |
@@ -1356,7 +1357,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
1356 | */ | 1357 | */ |
1357 | mutex_lock_nested(&wdev_iter->mtx, 1); | 1358 | mutex_lock_nested(&wdev_iter->mtx, 1); |
1358 | __acquire(wdev_iter->mtx); | 1359 | __acquire(wdev_iter->mtx); |
1359 | cfg80211_get_chan_state(wdev_iter, &ch, &chmode); | 1360 | cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect); |
1360 | wdev_unlock(wdev_iter); | 1361 | wdev_unlock(wdev_iter); |
1361 | 1362 | ||
1362 | switch (chmode) { | 1363 | switch (chmode) { |