diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/Kconfig | 35 | ||||
-rw-r--r-- | net/wireless/Makefile | 2 | ||||
-rw-r--r-- | net/wireless/ap.c | 46 | ||||
-rw-r--r-- | net/wireless/chan.c | 107 | ||||
-rw-r--r-- | net/wireless/core.c | 134 | ||||
-rw-r--r-- | net/wireless/core.h | 106 | ||||
-rw-r--r-- | net/wireless/ibss.c | 11 | ||||
-rw-r--r-- | net/wireless/mesh.c | 121 | ||||
-rw-r--r-- | net/wireless/mlme.c | 64 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 1009 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 21 | ||||
-rw-r--r-- | net/wireless/reg.c | 137 | ||||
-rw-r--r-- | net/wireless/reg.h | 8 | ||||
-rw-r--r-- | net/wireless/scan.c | 24 | ||||
-rw-r--r-- | net/wireless/sme.c | 10 | ||||
-rw-r--r-- | net/wireless/util.c | 171 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 23 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 10 |
18 files changed, 1511 insertions, 528 deletions
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 2e4444fedbe0..fe4adb12b3ef 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -74,6 +74,27 @@ config CFG80211_REG_DEBUG | |||
74 | 74 | ||
75 | If unsure, say N. | 75 | If unsure, say N. |
76 | 76 | ||
77 | config CFG80211_CERTIFICATION_ONUS | ||
78 | bool "cfg80211 certification onus" | ||
79 | depends on CFG80211 && EXPERT | ||
80 | default n | ||
81 | ---help--- | ||
82 | You should disable this option unless you are both capable | ||
83 | and willing to ensure your system will remain regulatory | ||
84 | compliant with the features available under this option. | ||
85 | Some options may still be under heavy development and | ||
86 | for whatever reason regulatory compliance has not or | ||
87 | cannot yet be verified. Regulatory verification may at | ||
88 | times only be possible until you have the final system | ||
89 | in place. | ||
90 | |||
91 | This option should only be enabled by system integrators | ||
92 | or distributions that have done work necessary to ensure | ||
93 | regulatory certification on the system with the enabled | ||
94 | features. Alternatively you can enable this option if | ||
95 | you are a wireless researcher and are working in a controlled | ||
96 | and approved environment by your local regulatory agency. | ||
97 | |||
77 | config CFG80211_DEFAULT_PS | 98 | config CFG80211_DEFAULT_PS |
78 | bool "enable powersave by default" | 99 | bool "enable powersave by default" |
79 | depends on CFG80211 | 100 | depends on CFG80211 |
@@ -114,24 +135,10 @@ config CFG80211_WEXT | |||
114 | bool "cfg80211 wireless extensions compatibility" | 135 | bool "cfg80211 wireless extensions compatibility" |
115 | depends on CFG80211 | 136 | depends on CFG80211 |
116 | select WEXT_CORE | 137 | select WEXT_CORE |
117 | default y | ||
118 | help | 138 | help |
119 | Enable this option if you need old userspace for wireless | 139 | Enable this option if you need old userspace for wireless |
120 | extensions with cfg80211-based drivers. | 140 | extensions with cfg80211-based drivers. |
121 | 141 | ||
122 | config WIRELESS_EXT_SYSFS | ||
123 | bool "Wireless extensions sysfs files" | ||
124 | depends on WEXT_CORE && SYSFS | ||
125 | help | ||
126 | This option enables the deprecated wireless statistics | ||
127 | files in /sys/class/net/*/wireless/. The same information | ||
128 | is available via the ioctls as well. | ||
129 | |||
130 | Say N. If you know you have ancient tools requiring it, | ||
131 | like very old versions of hal (prior to 0.5.12 release), | ||
132 | say Y and update the tools as soon as possible as this | ||
133 | option will be removed soon. | ||
134 | |||
135 | config LIB80211 | 142 | config LIB80211 |
136 | tristate "Common routines for IEEE802.11 drivers" | 143 | tristate "Common routines for IEEE802.11 drivers" |
137 | default n | 144 | default n |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 55a28ab21db9..0f7e0d621ab0 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o | |||
10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o | 10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o |
11 | 11 | ||
12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o | 12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o | 13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o |
14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o | 15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o |
16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o | 16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o |
diff --git a/net/wireless/ap.c b/net/wireless/ap.c new file mode 100644 index 000000000000..fcc60d8dbefa --- /dev/null +++ b/net/wireless/ap.c | |||
@@ -0,0 +1,46 @@ | |||
1 | #include <linux/ieee80211.h> | ||
2 | #include <linux/export.h> | ||
3 | #include <net/cfg80211.h> | ||
4 | #include "nl80211.h" | ||
5 | #include "core.h" | ||
6 | |||
7 | |||
8 | static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
9 | struct net_device *dev) | ||
10 | { | ||
11 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
12 | int err; | ||
13 | |||
14 | ASSERT_WDEV_LOCK(wdev); | ||
15 | |||
16 | if (!rdev->ops->stop_ap) | ||
17 | return -EOPNOTSUPP; | ||
18 | |||
19 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
20 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
21 | return -EOPNOTSUPP; | ||
22 | |||
23 | if (!wdev->beacon_interval) | ||
24 | return -ENOENT; | ||
25 | |||
26 | err = rdev->ops->stop_ap(&rdev->wiphy, dev); | ||
27 | if (!err) { | ||
28 | wdev->beacon_interval = 0; | ||
29 | wdev->channel = NULL; | ||
30 | } | ||
31 | |||
32 | return err; | ||
33 | } | ||
34 | |||
35 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
36 | struct net_device *dev) | ||
37 | { | ||
38 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
39 | int err; | ||
40 | |||
41 | wdev_lock(wdev); | ||
42 | err = __cfg80211_stop_ap(rdev, dev); | ||
43 | wdev_unlock(wdev); | ||
44 | |||
45 | return err; | ||
46 | } | ||
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 884801ac4dd0..d355f67d0cdd 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -60,7 +60,7 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, | |||
60 | diff = -20; | 60 | diff = -20; |
61 | break; | 61 | break; |
62 | default: | 62 | default: |
63 | return false; | 63 | return true; |
64 | } | 64 | } |
65 | 65 | ||
66 | sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); | 66 | sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); |
@@ -78,60 +78,75 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, | |||
78 | } | 78 | } |
79 | EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan); | 79 | EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan); |
80 | 80 | ||
81 | int cfg80211_set_freq(struct cfg80211_registered_device *rdev, | 81 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, |
82 | struct wireless_dev *wdev, int freq, | 82 | int freq, enum nl80211_channel_type chantype) |
83 | enum nl80211_channel_type channel_type) | ||
84 | { | 83 | { |
85 | struct ieee80211_channel *chan; | 84 | struct ieee80211_channel *chan; |
86 | int result; | ||
87 | |||
88 | if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR) | ||
89 | wdev = NULL; | ||
90 | 85 | ||
91 | if (wdev) { | 86 | if (!rdev->ops->set_monitor_channel) |
92 | ASSERT_WDEV_LOCK(wdev); | ||
93 | |||
94 | if (!netif_running(wdev->netdev)) | ||
95 | return -ENETDOWN; | ||
96 | } | ||
97 | |||
98 | if (!rdev->ops->set_channel) | ||
99 | return -EOPNOTSUPP; | 87 | return -EOPNOTSUPP; |
88 | if (!cfg80211_has_monitors_only(rdev)) | ||
89 | return -EBUSY; | ||
100 | 90 | ||
101 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | 91 | chan = rdev_freq_to_chan(rdev, freq, chantype); |
102 | if (!chan) | 92 | if (!chan) |
103 | return -EINVAL; | 93 | return -EINVAL; |
104 | 94 | ||
105 | /* Both channels should be able to initiate communication */ | 95 | return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); |
106 | if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC || | 96 | } |
107 | wdev->iftype == NL80211_IFTYPE_AP || | 97 | |
108 | wdev->iftype == NL80211_IFTYPE_AP_VLAN || | 98 | void |
109 | wdev->iftype == NL80211_IFTYPE_MESH_POINT || | 99 | cfg80211_get_chan_state(struct wireless_dev *wdev, |
110 | wdev->iftype == NL80211_IFTYPE_P2P_GO)) { | 100 | struct ieee80211_channel **chan, |
111 | switch (channel_type) { | 101 | enum cfg80211_chan_mode *chanmode) |
112 | case NL80211_CHAN_HT40PLUS: | 102 | { |
113 | case NL80211_CHAN_HT40MINUS: | 103 | *chan = NULL; |
114 | if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan, | 104 | *chanmode = CHAN_MODE_UNDEFINED; |
115 | channel_type)) { | 105 | |
116 | printk(KERN_DEBUG | 106 | ASSERT_WDEV_LOCK(wdev); |
117 | "cfg80211: Secondary channel not " | 107 | |
118 | "allowed to initiate communication\n"); | 108 | if (!netif_running(wdev->netdev)) |
119 | return -EINVAL; | 109 | return; |
120 | } | 110 | |
121 | break; | 111 | switch (wdev->iftype) { |
122 | default: | 112 | case NL80211_IFTYPE_ADHOC: |
123 | break; | 113 | if (wdev->current_bss) { |
114 | *chan = wdev->current_bss->pub.channel; | ||
115 | *chanmode = wdev->ibss_fixed | ||
116 | ? CHAN_MODE_SHARED | ||
117 | : CHAN_MODE_EXCLUSIVE; | ||
118 | return; | ||
119 | } | ||
120 | case NL80211_IFTYPE_STATION: | ||
121 | case NL80211_IFTYPE_P2P_CLIENT: | ||
122 | if (wdev->current_bss) { | ||
123 | *chan = wdev->current_bss->pub.channel; | ||
124 | *chanmode = CHAN_MODE_SHARED; | ||
125 | return; | ||
126 | } | ||
127 | break; | ||
128 | case NL80211_IFTYPE_AP: | ||
129 | case NL80211_IFTYPE_P2P_GO: | ||
130 | if (wdev->beacon_interval) { | ||
131 | *chan = wdev->channel; | ||
132 | *chanmode = CHAN_MODE_SHARED; | ||
124 | } | 133 | } |
134 | return; | ||
135 | case NL80211_IFTYPE_MESH_POINT: | ||
136 | if (wdev->mesh_id_len) { | ||
137 | *chan = wdev->channel; | ||
138 | *chanmode = CHAN_MODE_SHARED; | ||
139 | } | ||
140 | return; | ||
141 | case NL80211_IFTYPE_MONITOR: | ||
142 | case NL80211_IFTYPE_AP_VLAN: | ||
143 | case NL80211_IFTYPE_WDS: | ||
144 | /* these interface types don't really have a channel */ | ||
145 | return; | ||
146 | case NL80211_IFTYPE_UNSPECIFIED: | ||
147 | case NUM_NL80211_IFTYPES: | ||
148 | WARN_ON(1); | ||
125 | } | 149 | } |
126 | 150 | ||
127 | result = rdev->ops->set_channel(&rdev->wiphy, | 151 | return; |
128 | wdev ? wdev->netdev : NULL, | ||
129 | chan, channel_type); | ||
130 | if (result) | ||
131 | return result; | ||
132 | |||
133 | if (wdev) | ||
134 | wdev->channel = chan; | ||
135 | |||
136 | return 0; | ||
137 | } | 152 | } |
diff --git a/net/wireless/core.c b/net/wireless/core.c index a87d43552974..31b40cc4a9c3 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -96,69 +96,6 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | |||
96 | return &rdev->wiphy; | 96 | return &rdev->wiphy; |
97 | } | 97 | } |
98 | 98 | ||
99 | /* requires cfg80211_mutex to be held! */ | ||
100 | struct cfg80211_registered_device * | ||
101 | __cfg80211_rdev_from_info(struct genl_info *info) | ||
102 | { | ||
103 | int ifindex; | ||
104 | struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL; | ||
105 | struct net_device *dev; | ||
106 | int err = -EINVAL; | ||
107 | |||
108 | assert_cfg80211_lock(); | ||
109 | |||
110 | if (info->attrs[NL80211_ATTR_WIPHY]) { | ||
111 | bywiphyidx = cfg80211_rdev_by_wiphy_idx( | ||
112 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); | ||
113 | err = -ENODEV; | ||
114 | } | ||
115 | |||
116 | if (info->attrs[NL80211_ATTR_IFINDEX]) { | ||
117 | ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); | ||
118 | dev = dev_get_by_index(genl_info_net(info), ifindex); | ||
119 | if (dev) { | ||
120 | if (dev->ieee80211_ptr) | ||
121 | byifidx = | ||
122 | wiphy_to_dev(dev->ieee80211_ptr->wiphy); | ||
123 | dev_put(dev); | ||
124 | } | ||
125 | err = -ENODEV; | ||
126 | } | ||
127 | |||
128 | if (bywiphyidx && byifidx) { | ||
129 | if (bywiphyidx != byifidx) | ||
130 | return ERR_PTR(-EINVAL); | ||
131 | else | ||
132 | return bywiphyidx; /* == byifidx */ | ||
133 | } | ||
134 | if (bywiphyidx) | ||
135 | return bywiphyidx; | ||
136 | |||
137 | if (byifidx) | ||
138 | return byifidx; | ||
139 | |||
140 | return ERR_PTR(err); | ||
141 | } | ||
142 | |||
143 | struct cfg80211_registered_device * | ||
144 | cfg80211_get_dev_from_info(struct genl_info *info) | ||
145 | { | ||
146 | struct cfg80211_registered_device *rdev; | ||
147 | |||
148 | mutex_lock(&cfg80211_mutex); | ||
149 | rdev = __cfg80211_rdev_from_info(info); | ||
150 | |||
151 | /* if it is not an error we grab the lock on | ||
152 | * it to assure it won't be going away while | ||
153 | * we operate on it */ | ||
154 | if (!IS_ERR(rdev)) | ||
155 | mutex_lock(&rdev->mtx); | ||
156 | |||
157 | mutex_unlock(&cfg80211_mutex); | ||
158 | |||
159 | return rdev; | ||
160 | } | ||
161 | |||
162 | struct cfg80211_registered_device * | 99 | struct cfg80211_registered_device * |
163 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) | 100 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) |
164 | { | 101 | { |
@@ -239,7 +176,9 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | |||
239 | if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) | 176 | if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) |
240 | return -EOPNOTSUPP; | 177 | return -EOPNOTSUPP; |
241 | 178 | ||
242 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 179 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
180 | if (!wdev->netdev) | ||
181 | continue; | ||
243 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; | 182 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; |
244 | err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); | 183 | err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); |
245 | if (err) | 184 | if (err) |
@@ -251,8 +190,10 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | |||
251 | /* failed -- clean up to old netns */ | 190 | /* failed -- clean up to old netns */ |
252 | net = wiphy_net(&rdev->wiphy); | 191 | net = wiphy_net(&rdev->wiphy); |
253 | 192 | ||
254 | list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list, | 193 | list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list, |
255 | list) { | 194 | list) { |
195 | if (!wdev->netdev) | ||
196 | continue; | ||
256 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; | 197 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; |
257 | err = dev_change_net_namespace(wdev->netdev, net, | 198 | err = dev_change_net_namespace(wdev->netdev, net, |
258 | "wlan%d"); | 199 | "wlan%d"); |
@@ -289,8 +230,9 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
289 | rtnl_lock(); | 230 | rtnl_lock(); |
290 | mutex_lock(&rdev->devlist_mtx); | 231 | mutex_lock(&rdev->devlist_mtx); |
291 | 232 | ||
292 | list_for_each_entry(wdev, &rdev->netdev_list, list) | 233 | list_for_each_entry(wdev, &rdev->wdev_list, list) |
293 | dev_close(wdev->netdev); | 234 | if (wdev->netdev) |
235 | dev_close(wdev->netdev); | ||
294 | 236 | ||
295 | mutex_unlock(&rdev->devlist_mtx); | 237 | mutex_unlock(&rdev->devlist_mtx); |
296 | rtnl_unlock(); | 238 | rtnl_unlock(); |
@@ -367,7 +309,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
367 | mutex_init(&rdev->mtx); | 309 | mutex_init(&rdev->mtx); |
368 | mutex_init(&rdev->devlist_mtx); | 310 | mutex_init(&rdev->devlist_mtx); |
369 | mutex_init(&rdev->sched_scan_mtx); | 311 | mutex_init(&rdev->sched_scan_mtx); |
370 | INIT_LIST_HEAD(&rdev->netdev_list); | 312 | INIT_LIST_HEAD(&rdev->wdev_list); |
371 | spin_lock_init(&rdev->bss_lock); | 313 | spin_lock_init(&rdev->bss_lock); |
372 | INIT_LIST_HEAD(&rdev->bss_list); | 314 | INIT_LIST_HEAD(&rdev->bss_list); |
373 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 315 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
@@ -436,6 +378,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) | |||
436 | if (WARN_ON(!c->num_different_channels)) | 378 | if (WARN_ON(!c->num_different_channels)) |
437 | return -EINVAL; | 379 | return -EINVAL; |
438 | 380 | ||
381 | /* | ||
382 | * Put a sane limit on maximum number of different | ||
383 | * channels to simplify channel accounting code. | ||
384 | */ | ||
385 | if (WARN_ON(c->num_different_channels > | ||
386 | CFG80211_MAX_NUM_DIFFERENT_CHANNELS)) | ||
387 | return -EINVAL; | ||
388 | |||
439 | if (WARN_ON(!c->n_limits)) | 389 | if (WARN_ON(!c->n_limits)) |
440 | return -EINVAL; | 390 | return -EINVAL; |
441 | 391 | ||
@@ -484,9 +434,11 @@ int wiphy_register(struct wiphy *wiphy) | |||
484 | int i; | 434 | int i; |
485 | u16 ifmodes = wiphy->interface_modes; | 435 | u16 ifmodes = wiphy->interface_modes; |
486 | 436 | ||
437 | #ifdef CONFIG_PM | ||
487 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | 438 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && |
488 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | 439 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) |
489 | return -EINVAL; | 440 | return -EINVAL; |
441 | #endif | ||
490 | 442 | ||
491 | if (WARN_ON(wiphy->ap_sme_capa && | 443 | if (WARN_ON(wiphy->ap_sme_capa && |
492 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) | 444 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) |
@@ -521,8 +473,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
521 | continue; | 473 | continue; |
522 | 474 | ||
523 | sband->band = band; | 475 | sband->band = band; |
524 | 476 | if (WARN_ON(!sband->n_channels)) | |
525 | if (WARN_ON(!sband->n_channels || !sband->n_bitrates)) | 477 | return -EINVAL; |
478 | /* | ||
479 | * on 60gHz band, there are no legacy rates, so | ||
480 | * n_bitrates is 0 | ||
481 | */ | ||
482 | if (WARN_ON(band != IEEE80211_BAND_60GHZ && | ||
483 | !sband->n_bitrates)) | ||
526 | return -EINVAL; | 484 | return -EINVAL; |
527 | 485 | ||
528 | /* | 486 | /* |
@@ -563,12 +521,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
563 | return -EINVAL; | 521 | return -EINVAL; |
564 | } | 522 | } |
565 | 523 | ||
524 | #ifdef CONFIG_PM | ||
566 | if (rdev->wiphy.wowlan.n_patterns) { | 525 | if (rdev->wiphy.wowlan.n_patterns) { |
567 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || | 526 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || |
568 | rdev->wiphy.wowlan.pattern_min_len > | 527 | rdev->wiphy.wowlan.pattern_min_len > |
569 | rdev->wiphy.wowlan.pattern_max_len)) | 528 | rdev->wiphy.wowlan.pattern_max_len)) |
570 | return -EINVAL; | 529 | return -EINVAL; |
571 | } | 530 | } |
531 | #endif | ||
572 | 532 | ||
573 | /* check and set up bitrates */ | 533 | /* check and set up bitrates */ |
574 | ieee80211_set_bitrate_flags(wiphy); | 534 | ieee80211_set_bitrate_flags(wiphy); |
@@ -582,7 +542,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
582 | } | 542 | } |
583 | 543 | ||
584 | /* set up regulatory info */ | 544 | /* set up regulatory info */ |
585 | regulatory_update(wiphy, NL80211_REGDOM_SET_BY_CORE); | 545 | wiphy_regulatory_register(wiphy); |
586 | 546 | ||
587 | list_add_rcu(&rdev->list, &cfg80211_rdev_list); | 547 | list_add_rcu(&rdev->list, &cfg80211_rdev_list); |
588 | cfg80211_rdev_list_generation++; | 548 | cfg80211_rdev_list_generation++; |
@@ -667,7 +627,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
667 | __count == 0; })); | 627 | __count == 0; })); |
668 | 628 | ||
669 | mutex_lock(&rdev->devlist_mtx); | 629 | mutex_lock(&rdev->devlist_mtx); |
670 | BUG_ON(!list_empty(&rdev->netdev_list)); | 630 | BUG_ON(!list_empty(&rdev->wdev_list)); |
671 | mutex_unlock(&rdev->devlist_mtx); | 631 | mutex_unlock(&rdev->devlist_mtx); |
672 | 632 | ||
673 | /* | 633 | /* |
@@ -692,9 +652,11 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
692 | /* nothing */ | 652 | /* nothing */ |
693 | cfg80211_unlock_rdev(rdev); | 653 | cfg80211_unlock_rdev(rdev); |
694 | 654 | ||
695 | /* If this device got a regulatory hint tell core its | 655 | /* |
696 | * free to listen now to a new shiny device regulatory hint */ | 656 | * If this device got a regulatory hint tell core its |
697 | reg_device_remove(wiphy); | 657 | * free to listen now to a new shiny device regulatory hint |
658 | */ | ||
659 | wiphy_regulatory_deregister(wiphy); | ||
698 | 660 | ||
699 | cfg80211_rdev_list_generation++; | 661 | cfg80211_rdev_list_generation++; |
700 | device_del(&rdev->wiphy.dev); | 662 | device_del(&rdev->wiphy.dev); |
@@ -748,7 +710,7 @@ static void wdev_cleanup_work(struct work_struct *work) | |||
748 | 710 | ||
749 | cfg80211_lock_rdev(rdev); | 711 | cfg80211_lock_rdev(rdev); |
750 | 712 | ||
751 | if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { | 713 | if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { |
752 | rdev->scan_req->aborted = true; | 714 | rdev->scan_req->aborted = true; |
753 | ___cfg80211_scan_done(rdev, true); | 715 | ___cfg80211_scan_done(rdev, true); |
754 | } | 716 | } |
@@ -776,6 +738,16 @@ static struct device_type wiphy_type = { | |||
776 | .name = "wlan", | 738 | .name = "wlan", |
777 | }; | 739 | }; |
778 | 740 | ||
741 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||
742 | enum nl80211_iftype iftype, int num) | ||
743 | { | ||
744 | ASSERT_RTNL(); | ||
745 | |||
746 | rdev->num_running_ifaces += num; | ||
747 | if (iftype == NL80211_IFTYPE_MONITOR) | ||
748 | rdev->num_running_monitor_ifaces += num; | ||
749 | } | ||
750 | |||
779 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 751 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
780 | unsigned long state, | 752 | unsigned long state, |
781 | void *ndev) | 753 | void *ndev) |
@@ -810,7 +782,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
810 | spin_lock_init(&wdev->mgmt_registrations_lock); | 782 | spin_lock_init(&wdev->mgmt_registrations_lock); |
811 | 783 | ||
812 | mutex_lock(&rdev->devlist_mtx); | 784 | mutex_lock(&rdev->devlist_mtx); |
813 | list_add_rcu(&wdev->list, &rdev->netdev_list); | 785 | wdev->identifier = ++rdev->wdev_id; |
786 | list_add_rcu(&wdev->list, &rdev->wdev_list); | ||
814 | rdev->devlist_generation++; | 787 | rdev->devlist_generation++; |
815 | /* can only change netns with wiphy */ | 788 | /* can only change netns with wiphy */ |
816 | dev->features |= NETIF_F_NETNS_LOCAL; | 789 | dev->features |= NETIF_F_NETNS_LOCAL; |
@@ -869,12 +842,16 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
869 | case NL80211_IFTYPE_MESH_POINT: | 842 | case NL80211_IFTYPE_MESH_POINT: |
870 | cfg80211_leave_mesh(rdev, dev); | 843 | cfg80211_leave_mesh(rdev, dev); |
871 | break; | 844 | break; |
845 | case NL80211_IFTYPE_AP: | ||
846 | cfg80211_stop_ap(rdev, dev); | ||
847 | break; | ||
872 | default: | 848 | default: |
873 | break; | 849 | break; |
874 | } | 850 | } |
875 | wdev->beacon_interval = 0; | 851 | wdev->beacon_interval = 0; |
876 | break; | 852 | break; |
877 | case NETDEV_DOWN: | 853 | case NETDEV_DOWN: |
854 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | ||
878 | dev_hold(dev); | 855 | dev_hold(dev); |
879 | queue_work(cfg80211_wq, &wdev->cleanup_work); | 856 | queue_work(cfg80211_wq, &wdev->cleanup_work); |
880 | break; | 857 | break; |
@@ -891,6 +868,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
891 | mutex_unlock(&rdev->devlist_mtx); | 868 | mutex_unlock(&rdev->devlist_mtx); |
892 | dev_put(dev); | 869 | dev_put(dev); |
893 | } | 870 | } |
871 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); | ||
894 | cfg80211_lock_rdev(rdev); | 872 | cfg80211_lock_rdev(rdev); |
895 | mutex_lock(&rdev->devlist_mtx); | 873 | mutex_lock(&rdev->devlist_mtx); |
896 | wdev_lock(wdev); | 874 | wdev_lock(wdev); |
@@ -980,7 +958,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
980 | return notifier_from_errno(-EOPNOTSUPP); | 958 | return notifier_from_errno(-EOPNOTSUPP); |
981 | if (rfkill_blocked(rdev->rfkill)) | 959 | if (rfkill_blocked(rdev->rfkill)) |
982 | return notifier_from_errno(-ERFKILL); | 960 | return notifier_from_errno(-ERFKILL); |
961 | mutex_lock(&rdev->devlist_mtx); | ||
983 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | 962 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); |
963 | mutex_unlock(&rdev->devlist_mtx); | ||
984 | if (ret) | 964 | if (ret) |
985 | return notifier_from_errno(ret); | 965 | return notifier_from_errno(ret); |
986 | break; | 966 | break; |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 8523f3878677..5206c6844fd7 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/debugfs.h> | 13 | #include <linux/debugfs.h> |
14 | #include <linux/rfkill.h> | 14 | #include <linux/rfkill.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
16 | #include <linux/rtnetlink.h> | ||
16 | #include <net/genetlink.h> | 17 | #include <net/genetlink.h> |
17 | #include <net/cfg80211.h> | 18 | #include <net/cfg80211.h> |
18 | #include "reg.h" | 19 | #include "reg.h" |
@@ -46,16 +47,20 @@ struct cfg80211_registered_device { | |||
46 | /* wiphy index, internal only */ | 47 | /* wiphy index, internal only */ |
47 | int wiphy_idx; | 48 | int wiphy_idx; |
48 | 49 | ||
49 | /* associate netdev list */ | 50 | /* associated wireless interfaces */ |
50 | struct mutex devlist_mtx; | 51 | struct mutex devlist_mtx; |
51 | /* protected by devlist_mtx or RCU */ | 52 | /* protected by devlist_mtx or RCU */ |
52 | struct list_head netdev_list; | 53 | struct list_head wdev_list; |
53 | int devlist_generation; | 54 | int devlist_generation, wdev_id; |
54 | int opencount; /* also protected by devlist_mtx */ | 55 | int opencount; /* also protected by devlist_mtx */ |
55 | wait_queue_head_t dev_wait; | 56 | wait_queue_head_t dev_wait; |
56 | 57 | ||
57 | u32 ap_beacons_nlpid; | 58 | u32 ap_beacons_nlpid; |
58 | 59 | ||
60 | /* protected by RTNL only */ | ||
61 | int num_running_ifaces; | ||
62 | int num_running_monitor_ifaces; | ||
63 | |||
59 | /* BSSes/scanning */ | 64 | /* BSSes/scanning */ |
60 | spinlock_t bss_lock; | 65 | spinlock_t bss_lock; |
61 | struct list_head bss_list; | 66 | struct list_head bss_list; |
@@ -159,32 +164,6 @@ static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) | |||
159 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx); | 164 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx); |
160 | int get_wiphy_idx(struct wiphy *wiphy); | 165 | int get_wiphy_idx(struct wiphy *wiphy); |
161 | 166 | ||
162 | struct cfg80211_registered_device * | ||
163 | __cfg80211_rdev_from_info(struct genl_info *info); | ||
164 | |||
165 | /* | ||
166 | * This function returns a pointer to the driver | ||
167 | * that the genl_info item that is passed refers to. | ||
168 | * If successful, it returns non-NULL and also locks | ||
169 | * the driver's mutex! | ||
170 | * | ||
171 | * This means that you need to call cfg80211_unlock_rdev() | ||
172 | * before being allowed to acquire &cfg80211_mutex! | ||
173 | * | ||
174 | * This is necessary because we need to lock the global | ||
175 | * mutex to get an item off the list safely, and then | ||
176 | * we lock the rdev mutex so it doesn't go away under us. | ||
177 | * | ||
178 | * We don't want to keep cfg80211_mutex locked | ||
179 | * for all the time in order to allow requests on | ||
180 | * other interfaces to go through at the same time. | ||
181 | * | ||
182 | * The result of this can be a PTR_ERR and hence must | ||
183 | * be checked with IS_ERR() for errors. | ||
184 | */ | ||
185 | extern struct cfg80211_registered_device * | ||
186 | cfg80211_get_dev_from_info(struct genl_info *info); | ||
187 | |||
188 | /* requires cfg80211_rdev_mutex to be held! */ | 167 | /* requires cfg80211_rdev_mutex to be held! */ |
189 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); | 168 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); |
190 | 169 | ||
@@ -223,6 +202,14 @@ static inline void wdev_unlock(struct wireless_dev *wdev) | |||
223 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) | 202 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) |
224 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) | 203 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) |
225 | 204 | ||
205 | static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev) | ||
206 | { | ||
207 | ASSERT_RTNL(); | ||
208 | |||
209 | return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces && | ||
210 | rdev->num_running_ifaces > 0; | ||
211 | } | ||
212 | |||
226 | enum cfg80211_event_type { | 213 | enum cfg80211_event_type { |
227 | EVENT_CONNECT_RESULT, | 214 | EVENT_CONNECT_RESULT, |
228 | EVENT_ROAMED, | 215 | EVENT_ROAMED, |
@@ -267,6 +254,12 @@ struct cfg80211_cached_keys { | |||
267 | int def, defmgmt; | 254 | int def, defmgmt; |
268 | }; | 255 | }; |
269 | 256 | ||
257 | enum cfg80211_chan_mode { | ||
258 | CHAN_MODE_UNDEFINED, | ||
259 | CHAN_MODE_SHARED, | ||
260 | CHAN_MODE_EXCLUSIVE, | ||
261 | }; | ||
262 | |||
270 | 263 | ||
271 | /* free object */ | 264 | /* free object */ |
272 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); | 265 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); |
@@ -303,14 +296,21 @@ extern const struct mesh_config default_mesh_config; | |||
303 | extern const struct mesh_setup default_mesh_setup; | 296 | extern const struct mesh_setup default_mesh_setup; |
304 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 297 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, |
305 | struct net_device *dev, | 298 | struct net_device *dev, |
306 | const struct mesh_setup *setup, | 299 | struct mesh_setup *setup, |
307 | const struct mesh_config *conf); | 300 | const struct mesh_config *conf); |
308 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 301 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, |
309 | struct net_device *dev, | 302 | struct net_device *dev, |
310 | const struct mesh_setup *setup, | 303 | struct mesh_setup *setup, |
311 | const struct mesh_config *conf); | 304 | const struct mesh_config *conf); |
312 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | 305 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, |
313 | struct net_device *dev); | 306 | struct net_device *dev); |
307 | int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | ||
308 | struct wireless_dev *wdev, int freq, | ||
309 | enum nl80211_channel_type channel_type); | ||
310 | |||
311 | /* AP */ | ||
312 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
313 | struct net_device *dev); | ||
314 | 314 | ||
315 | /* MLME */ | 315 | /* MLME */ |
316 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 316 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
@@ -369,7 +369,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, | |||
369 | void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); | 369 | void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); |
370 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); | 370 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); |
371 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | 371 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
372 | struct net_device *dev, | 372 | struct wireless_dev *wdev, |
373 | struct ieee80211_channel *chan, bool offchan, | 373 | struct ieee80211_channel *chan, bool offchan, |
374 | enum nl80211_channel_type channel_type, | 374 | enum nl80211_channel_type channel_type, |
375 | bool channel_type_valid, unsigned int wait, | 375 | bool channel_type_valid, unsigned int wait, |
@@ -427,9 +427,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
427 | u32 *flags, struct vif_params *params); | 427 | u32 *flags, struct vif_params *params); |
428 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); | 428 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); |
429 | 429 | ||
430 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 430 | int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, |
431 | struct wireless_dev *wdev, | 431 | struct wireless_dev *wdev, |
432 | enum nl80211_iftype iftype); | 432 | enum nl80211_iftype iftype, |
433 | struct ieee80211_channel *chan, | ||
434 | enum cfg80211_chan_mode chanmode); | ||
435 | |||
436 | static inline int | ||
437 | cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | ||
438 | struct wireless_dev *wdev, | ||
439 | enum nl80211_iftype iftype) | ||
440 | { | ||
441 | return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL, | ||
442 | CHAN_MODE_UNDEFINED); | ||
443 | } | ||
433 | 444 | ||
434 | static inline int | 445 | static inline int |
435 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | 446 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, |
@@ -438,12 +449,26 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | |||
438 | return cfg80211_can_change_interface(rdev, NULL, iftype); | 449 | return cfg80211_can_change_interface(rdev, NULL, iftype); |
439 | } | 450 | } |
440 | 451 | ||
452 | static inline int | ||
453 | cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, | ||
454 | struct wireless_dev *wdev, | ||
455 | struct ieee80211_channel *chan, | ||
456 | enum cfg80211_chan_mode chanmode) | ||
457 | { | ||
458 | return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
459 | chan, chanmode); | ||
460 | } | ||
461 | |||
462 | void | ||
463 | cfg80211_get_chan_state(struct wireless_dev *wdev, | ||
464 | struct ieee80211_channel **chan, | ||
465 | enum cfg80211_chan_mode *chanmode); | ||
466 | |||
441 | struct ieee80211_channel * | 467 | struct ieee80211_channel * |
442 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | 468 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, |
443 | int freq, enum nl80211_channel_type channel_type); | 469 | int freq, enum nl80211_channel_type channel_type); |
444 | int cfg80211_set_freq(struct cfg80211_registered_device *rdev, | 470 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, |
445 | struct wireless_dev *wdev, int freq, | 471 | int freq, enum nl80211_channel_type chantype); |
446 | enum nl80211_channel_type channel_type); | ||
447 | 472 | ||
448 | int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | 473 | int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, |
449 | const u8 *rates, unsigned int n_rates, | 474 | const u8 *rates, unsigned int n_rates, |
@@ -452,6 +477,11 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | |||
452 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 477 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
453 | u32 beacon_int); | 478 | u32 beacon_int); |
454 | 479 | ||
480 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||
481 | enum nl80211_iftype iftype, int num); | ||
482 | |||
483 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 | ||
484 | |||
455 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 485 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
456 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) | 486 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) |
457 | #else | 487 | #else |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 89baa3328411..ca5672f6ee2f 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -113,10 +113,21 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
113 | kfree(wdev->connect_keys); | 113 | kfree(wdev->connect_keys); |
114 | wdev->connect_keys = connkeys; | 114 | wdev->connect_keys = connkeys; |
115 | 115 | ||
116 | wdev->ibss_fixed = params->channel_fixed; | ||
116 | #ifdef CONFIG_CFG80211_WEXT | 117 | #ifdef CONFIG_CFG80211_WEXT |
117 | wdev->wext.ibss.channel = params->channel; | 118 | wdev->wext.ibss.channel = params->channel; |
118 | #endif | 119 | #endif |
119 | wdev->sme_state = CFG80211_SME_CONNECTING; | 120 | wdev->sme_state = CFG80211_SME_CONNECTING; |
121 | |||
122 | err = cfg80211_can_use_chan(rdev, wdev, params->channel, | ||
123 | params->channel_fixed | ||
124 | ? CHAN_MODE_SHARED | ||
125 | : CHAN_MODE_EXCLUSIVE); | ||
126 | if (err) { | ||
127 | wdev->connect_keys = NULL; | ||
128 | return err; | ||
129 | } | ||
130 | |||
120 | err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); | 131 | err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); |
121 | if (err) { | 132 | if (err) { |
122 | wdev->connect_keys = NULL; | 133 | wdev->connect_keys = NULL; |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 2749cb86b462..c384e77ff77a 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -14,6 +14,9 @@ | |||
14 | 14 | ||
15 | #define MESH_PATH_TIMEOUT 5000 | 15 | #define MESH_PATH_TIMEOUT 5000 |
16 | #define MESH_RANN_INTERVAL 5000 | 16 | #define MESH_RANN_INTERVAL 5000 |
17 | #define MESH_PATH_TO_ROOT_TIMEOUT 6000 | ||
18 | #define MESH_ROOT_INTERVAL 5000 | ||
19 | #define MESH_ROOT_CONFIRMATION_INTERVAL 2000 | ||
17 | 20 | ||
18 | /* | 21 | /* |
19 | * Minimum interval between two consecutive PREQs originated by the same | 22 | * Minimum interval between two consecutive PREQs originated by the same |
@@ -62,9 +65,15 @@ const struct mesh_config default_mesh_config = { | |||
62 | .dot11MeshForwarding = true, | 65 | .dot11MeshForwarding = true, |
63 | .rssi_threshold = MESH_RSSI_THRESHOLD, | 66 | .rssi_threshold = MESH_RSSI_THRESHOLD, |
64 | .ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED, | 67 | .ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED, |
68 | .dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT, | ||
69 | .dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL, | ||
70 | .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL, | ||
65 | }; | 71 | }; |
66 | 72 | ||
67 | const struct mesh_setup default_mesh_setup = { | 73 | const struct mesh_setup default_mesh_setup = { |
74 | /* cfg80211_join_mesh() will pick a channel if needed */ | ||
75 | .channel = NULL, | ||
76 | .channel_type = NL80211_CHAN_NO_HT, | ||
68 | .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, | 77 | .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, |
69 | .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, | 78 | .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, |
70 | .path_metric = IEEE80211_PATH_METRIC_AIRTIME, | 79 | .path_metric = IEEE80211_PATH_METRIC_AIRTIME, |
@@ -75,7 +84,7 @@ const struct mesh_setup default_mesh_setup = { | |||
75 | 84 | ||
76 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 85 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, |
77 | struct net_device *dev, | 86 | struct net_device *dev, |
78 | const struct mesh_setup *setup, | 87 | struct mesh_setup *setup, |
79 | const struct mesh_config *conf) | 88 | const struct mesh_config *conf) |
80 | { | 89 | { |
81 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 90 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
@@ -101,10 +110,61 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
101 | if (!rdev->ops->join_mesh) | 110 | if (!rdev->ops->join_mesh) |
102 | return -EOPNOTSUPP; | 111 | return -EOPNOTSUPP; |
103 | 112 | ||
113 | if (!setup->channel) { | ||
114 | /* if no channel explicitly given, use preset channel */ | ||
115 | setup->channel = wdev->preset_chan; | ||
116 | setup->channel_type = wdev->preset_chantype; | ||
117 | } | ||
118 | |||
119 | if (!setup->channel) { | ||
120 | /* if we don't have that either, use the first usable channel */ | ||
121 | enum ieee80211_band band; | ||
122 | |||
123 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
124 | struct ieee80211_supported_band *sband; | ||
125 | struct ieee80211_channel *chan; | ||
126 | int i; | ||
127 | |||
128 | sband = rdev->wiphy.bands[band]; | ||
129 | if (!sband) | ||
130 | continue; | ||
131 | |||
132 | for (i = 0; i < sband->n_channels; i++) { | ||
133 | chan = &sband->channels[i]; | ||
134 | if (chan->flags & (IEEE80211_CHAN_NO_IBSS | | ||
135 | IEEE80211_CHAN_PASSIVE_SCAN | | ||
136 | IEEE80211_CHAN_DISABLED | | ||
137 | IEEE80211_CHAN_RADAR)) | ||
138 | continue; | ||
139 | setup->channel = chan; | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | if (setup->channel) | ||
144 | break; | ||
145 | } | ||
146 | |||
147 | /* no usable channel ... */ | ||
148 | if (!setup->channel) | ||
149 | return -EINVAL; | ||
150 | |||
151 | setup->channel_type = NL80211_CHAN_NO_HT; | ||
152 | } | ||
153 | |||
154 | if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel, | ||
155 | setup->channel_type)) | ||
156 | return -EINVAL; | ||
157 | |||
158 | err = cfg80211_can_use_chan(rdev, wdev, setup->channel, | ||
159 | CHAN_MODE_SHARED); | ||
160 | if (err) | ||
161 | return err; | ||
162 | |||
104 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); | 163 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); |
105 | if (!err) { | 164 | if (!err) { |
106 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); | 165 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); |
107 | wdev->mesh_id_len = setup->mesh_id_len; | 166 | wdev->mesh_id_len = setup->mesh_id_len; |
167 | wdev->channel = setup->channel; | ||
108 | } | 168 | } |
109 | 169 | ||
110 | return err; | 170 | return err; |
@@ -112,19 +172,71 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
112 | 172 | ||
113 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 173 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, |
114 | struct net_device *dev, | 174 | struct net_device *dev, |
115 | const struct mesh_setup *setup, | 175 | struct mesh_setup *setup, |
116 | const struct mesh_config *conf) | 176 | const struct mesh_config *conf) |
117 | { | 177 | { |
118 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 178 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
119 | int err; | 179 | int err; |
120 | 180 | ||
181 | mutex_lock(&rdev->devlist_mtx); | ||
121 | wdev_lock(wdev); | 182 | wdev_lock(wdev); |
122 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); | 183 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); |
123 | wdev_unlock(wdev); | 184 | wdev_unlock(wdev); |
185 | mutex_unlock(&rdev->devlist_mtx); | ||
124 | 186 | ||
125 | return err; | 187 | return err; |
126 | } | 188 | } |
127 | 189 | ||
190 | int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | ||
191 | struct wireless_dev *wdev, int freq, | ||
192 | enum nl80211_channel_type channel_type) | ||
193 | { | ||
194 | struct ieee80211_channel *channel; | ||
195 | int err; | ||
196 | |||
197 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | ||
198 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | ||
199 | channel, | ||
200 | channel_type)) { | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * Workaround for libertas (only!), it puts the interface | ||
206 | * into mesh mode but doesn't implement join_mesh. Instead, | ||
207 | * it is configured via sysfs and then joins the mesh when | ||
208 | * you set the channel. Note that the libertas mesh isn't | ||
209 | * compatible with 802.11 mesh. | ||
210 | */ | ||
211 | if (rdev->ops->libertas_set_mesh_channel) { | ||
212 | if (channel_type != NL80211_CHAN_NO_HT) | ||
213 | return -EINVAL; | ||
214 | |||
215 | if (!netif_running(wdev->netdev)) | ||
216 | return -ENETDOWN; | ||
217 | |||
218 | err = cfg80211_can_use_chan(rdev, wdev, channel, | ||
219 | CHAN_MODE_SHARED); | ||
220 | if (err) | ||
221 | return err; | ||
222 | |||
223 | err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, | ||
224 | wdev->netdev, | ||
225 | channel); | ||
226 | if (!err) | ||
227 | wdev->channel = channel; | ||
228 | |||
229 | return err; | ||
230 | } | ||
231 | |||
232 | if (wdev->mesh_id_len) | ||
233 | return -EBUSY; | ||
234 | |||
235 | wdev->preset_chan = channel; | ||
236 | wdev->preset_chantype = channel_type; | ||
237 | return 0; | ||
238 | } | ||
239 | |||
128 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, | 240 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, |
129 | const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp) | 241 | const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp) |
130 | { | 242 | { |
@@ -156,8 +268,11 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | |||
156 | return -ENOTCONN; | 268 | return -ENOTCONN; |
157 | 269 | ||
158 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); | 270 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); |
159 | if (!err) | 271 | if (!err) { |
160 | wdev->mesh_id_len = 0; | 272 | wdev->mesh_id_len = 0; |
273 | wdev->channel = NULL; | ||
274 | } | ||
275 | |||
161 | return err; | 276 | return err; |
162 | } | 277 | } |
163 | 278 | ||
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index eb90988bbd36..1cdb1d5e6b0f 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -302,8 +302,14 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
302 | if (!req.bss) | 302 | if (!req.bss) |
303 | return -ENOENT; | 303 | return -ENOENT; |
304 | 304 | ||
305 | err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, | ||
306 | CHAN_MODE_SHARED); | ||
307 | if (err) | ||
308 | goto out; | ||
309 | |||
305 | err = rdev->ops->auth(&rdev->wiphy, dev, &req); | 310 | err = rdev->ops->auth(&rdev->wiphy, dev, &req); |
306 | 311 | ||
312 | out: | ||
307 | cfg80211_put_bss(req.bss); | 313 | cfg80211_put_bss(req.bss); |
308 | return err; | 314 | return err; |
309 | } | 315 | } |
@@ -317,11 +323,13 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
317 | { | 323 | { |
318 | int err; | 324 | int err; |
319 | 325 | ||
326 | mutex_lock(&rdev->devlist_mtx); | ||
320 | wdev_lock(dev->ieee80211_ptr); | 327 | wdev_lock(dev->ieee80211_ptr); |
321 | err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | 328 | err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
322 | ssid, ssid_len, ie, ie_len, | 329 | ssid, ssid_len, ie, ie_len, |
323 | key, key_len, key_idx); | 330 | key, key_len, key_idx); |
324 | wdev_unlock(dev->ieee80211_ptr); | 331 | wdev_unlock(dev->ieee80211_ptr); |
332 | mutex_unlock(&rdev->devlist_mtx); | ||
325 | 333 | ||
326 | return err; | 334 | return err; |
327 | } | 335 | } |
@@ -397,8 +405,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
397 | return -ENOENT; | 405 | return -ENOENT; |
398 | } | 406 | } |
399 | 407 | ||
408 | err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, | ||
409 | CHAN_MODE_SHARED); | ||
410 | if (err) | ||
411 | goto out; | ||
412 | |||
400 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); | 413 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); |
401 | 414 | ||
415 | out: | ||
402 | if (err) { | 416 | if (err) { |
403 | if (was_connected) | 417 | if (was_connected) |
404 | wdev->sme_state = CFG80211_SME_CONNECTED; | 418 | wdev->sme_state = CFG80211_SME_CONNECTED; |
@@ -421,11 +435,13 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
421 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 435 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
422 | int err; | 436 | int err; |
423 | 437 | ||
438 | mutex_lock(&rdev->devlist_mtx); | ||
424 | wdev_lock(wdev); | 439 | wdev_lock(wdev); |
425 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 440 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
426 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, | 441 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, |
427 | assoc_flags, ht_capa, ht_capa_mask); | 442 | assoc_flags, ht_capa, ht_capa_mask); |
428 | wdev_unlock(wdev); | 443 | wdev_unlock(wdev); |
444 | mutex_unlock(&rdev->devlist_mtx); | ||
429 | 445 | ||
430 | return err; | 446 | return err; |
431 | } | 447 | } |
@@ -551,29 +567,28 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
551 | } | 567 | } |
552 | } | 568 | } |
553 | 569 | ||
554 | void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, | 570 | void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, |
555 | struct ieee80211_channel *chan, | 571 | struct ieee80211_channel *chan, |
556 | enum nl80211_channel_type channel_type, | 572 | enum nl80211_channel_type channel_type, |
557 | unsigned int duration, gfp_t gfp) | 573 | unsigned int duration, gfp_t gfp) |
558 | { | 574 | { |
559 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | 575 | struct wiphy *wiphy = wdev->wiphy; |
560 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 576 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
561 | 577 | ||
562 | nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type, | 578 | nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type, |
563 | duration, gfp); | 579 | duration, gfp); |
564 | } | 580 | } |
565 | EXPORT_SYMBOL(cfg80211_ready_on_channel); | 581 | EXPORT_SYMBOL(cfg80211_ready_on_channel); |
566 | 582 | ||
567 | void cfg80211_remain_on_channel_expired(struct net_device *dev, | 583 | void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, |
568 | u64 cookie, | ||
569 | struct ieee80211_channel *chan, | 584 | struct ieee80211_channel *chan, |
570 | enum nl80211_channel_type channel_type, | 585 | enum nl80211_channel_type channel_type, |
571 | gfp_t gfp) | 586 | gfp_t gfp) |
572 | { | 587 | { |
573 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | 588 | struct wiphy *wiphy = wdev->wiphy; |
574 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 589 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
575 | 590 | ||
576 | nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan, | 591 | nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, |
577 | channel_type, gfp); | 592 | channel_type, gfp); |
578 | } | 593 | } |
579 | EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); | 594 | EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); |
@@ -662,8 +677,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, | |||
662 | list_add(&nreg->list, &wdev->mgmt_registrations); | 677 | list_add(&nreg->list, &wdev->mgmt_registrations); |
663 | 678 | ||
664 | if (rdev->ops->mgmt_frame_register) | 679 | if (rdev->ops->mgmt_frame_register) |
665 | rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, | 680 | rdev->ops->mgmt_frame_register(wiphy, wdev, frame_type, true); |
666 | frame_type, true); | ||
667 | 681 | ||
668 | out: | 682 | out: |
669 | spin_unlock_bh(&wdev->mgmt_registrations_lock); | 683 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
@@ -686,7 +700,7 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid) | |||
686 | if (rdev->ops->mgmt_frame_register) { | 700 | if (rdev->ops->mgmt_frame_register) { |
687 | u16 frame_type = le16_to_cpu(reg->frame_type); | 701 | u16 frame_type = le16_to_cpu(reg->frame_type); |
688 | 702 | ||
689 | rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, | 703 | rdev->ops->mgmt_frame_register(wiphy, wdev, |
690 | frame_type, false); | 704 | frame_type, false); |
691 | } | 705 | } |
692 | 706 | ||
@@ -715,14 +729,14 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) | |||
715 | } | 729 | } |
716 | 730 | ||
717 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | 731 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
718 | struct net_device *dev, | 732 | struct wireless_dev *wdev, |
719 | struct ieee80211_channel *chan, bool offchan, | 733 | struct ieee80211_channel *chan, bool offchan, |
720 | enum nl80211_channel_type channel_type, | 734 | enum nl80211_channel_type channel_type, |
721 | bool channel_type_valid, unsigned int wait, | 735 | bool channel_type_valid, unsigned int wait, |
722 | const u8 *buf, size_t len, bool no_cck, | 736 | const u8 *buf, size_t len, bool no_cck, |
723 | bool dont_wait_for_ack, u64 *cookie) | 737 | bool dont_wait_for_ack, u64 *cookie) |
724 | { | 738 | { |
725 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 739 | struct net_device *dev = wdev->netdev; |
726 | const struct ieee80211_mgmt *mgmt; | 740 | const struct ieee80211_mgmt *mgmt; |
727 | u16 stype; | 741 | u16 stype; |
728 | 742 | ||
@@ -809,16 +823,15 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
809 | return -EINVAL; | 823 | return -EINVAL; |
810 | 824 | ||
811 | /* Transmit the Action frame as requested by user space */ | 825 | /* Transmit the Action frame as requested by user space */ |
812 | return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan, | 826 | return rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, |
813 | channel_type, channel_type_valid, | 827 | channel_type, channel_type_valid, |
814 | wait, buf, len, no_cck, dont_wait_for_ack, | 828 | wait, buf, len, no_cck, dont_wait_for_ack, |
815 | cookie); | 829 | cookie); |
816 | } | 830 | } |
817 | 831 | ||
818 | bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, | 832 | bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, |
819 | const u8 *buf, size_t len, gfp_t gfp) | 833 | const u8 *buf, size_t len, gfp_t gfp) |
820 | { | 834 | { |
821 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
822 | struct wiphy *wiphy = wdev->wiphy; | 835 | struct wiphy *wiphy = wdev->wiphy; |
823 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 836 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
824 | struct cfg80211_mgmt_registration *reg; | 837 | struct cfg80211_mgmt_registration *reg; |
@@ -855,7 +868,7 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, | |||
855 | /* found match! */ | 868 | /* found match! */ |
856 | 869 | ||
857 | /* Indicate the received Action frame to user space */ | 870 | /* Indicate the received Action frame to user space */ |
858 | if (nl80211_send_mgmt(rdev, dev, reg->nlpid, | 871 | if (nl80211_send_mgmt(rdev, wdev, reg->nlpid, |
859 | freq, sig_mbm, | 872 | freq, sig_mbm, |
860 | buf, len, gfp)) | 873 | buf, len, gfp)) |
861 | continue; | 874 | continue; |
@@ -870,15 +883,14 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, | |||
870 | } | 883 | } |
871 | EXPORT_SYMBOL(cfg80211_rx_mgmt); | 884 | EXPORT_SYMBOL(cfg80211_rx_mgmt); |
872 | 885 | ||
873 | void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, | 886 | void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, |
874 | const u8 *buf, size_t len, bool ack, gfp_t gfp) | 887 | const u8 *buf, size_t len, bool ack, gfp_t gfp) |
875 | { | 888 | { |
876 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
877 | struct wiphy *wiphy = wdev->wiphy; | 889 | struct wiphy *wiphy = wdev->wiphy; |
878 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 890 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
879 | 891 | ||
880 | /* Indicate TX status of the Action frame to user space */ | 892 | /* Indicate TX status of the Action frame to user space */ |
881 | nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp); | 893 | nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp); |
882 | } | 894 | } |
883 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); | 895 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); |
884 | 896 | ||
@@ -907,6 +919,19 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, | |||
907 | } | 919 | } |
908 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); | 920 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); |
909 | 921 | ||
922 | void cfg80211_cqm_txe_notify(struct net_device *dev, | ||
923 | const u8 *peer, u32 num_packets, | ||
924 | u32 rate, u32 intvl, gfp_t gfp) | ||
925 | { | ||
926 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
927 | struct wiphy *wiphy = wdev->wiphy; | ||
928 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
929 | |||
930 | nl80211_send_cqm_txe_notify(rdev, dev, peer, num_packets, | ||
931 | rate, intvl, gfp); | ||
932 | } | ||
933 | EXPORT_SYMBOL(cfg80211_cqm_txe_notify); | ||
934 | |||
910 | void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, | 935 | void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, |
911 | const u8 *replay_ctr, gfp_t gfp) | 936 | const u8 *replay_ctr, gfp_t gfp) |
912 | { | 937 | { |
@@ -948,7 +973,6 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, | |||
948 | goto out; | 973 | goto out; |
949 | 974 | ||
950 | wdev->channel = chan; | 975 | wdev->channel = chan; |
951 | |||
952 | nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); | 976 | nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); |
953 | out: | 977 | out: |
954 | wdev_unlock(wdev); | 978 | wdev_unlock(wdev); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 206465dc0cab..97026f3b215a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -46,28 +46,175 @@ static struct genl_family nl80211_fam = { | |||
46 | .post_doit = nl80211_post_doit, | 46 | .post_doit = nl80211_post_doit, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | /* internal helper: get rdev and dev */ | 49 | /* returns ERR_PTR values */ |
50 | static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs, | 50 | static struct wireless_dev * |
51 | struct cfg80211_registered_device **rdev, | 51 | __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) |
52 | struct net_device **dev) | ||
53 | { | 52 | { |
54 | int ifindex; | 53 | struct cfg80211_registered_device *rdev; |
54 | struct wireless_dev *result = NULL; | ||
55 | bool have_ifidx = attrs[NL80211_ATTR_IFINDEX]; | ||
56 | bool have_wdev_id = attrs[NL80211_ATTR_WDEV]; | ||
57 | u64 wdev_id; | ||
58 | int wiphy_idx = -1; | ||
59 | int ifidx = -1; | ||
55 | 60 | ||
56 | if (!attrs[NL80211_ATTR_IFINDEX]) | 61 | assert_cfg80211_lock(); |
57 | return -EINVAL; | ||
58 | 62 | ||
59 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | 63 | if (!have_ifidx && !have_wdev_id) |
60 | *dev = dev_get_by_index(netns, ifindex); | 64 | return ERR_PTR(-EINVAL); |
61 | if (!*dev) | ||
62 | return -ENODEV; | ||
63 | 65 | ||
64 | *rdev = cfg80211_get_dev_from_ifindex(netns, ifindex); | 66 | if (have_ifidx) |
65 | if (IS_ERR(*rdev)) { | 67 | ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); |
66 | dev_put(*dev); | 68 | if (have_wdev_id) { |
67 | return PTR_ERR(*rdev); | 69 | wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]); |
70 | wiphy_idx = wdev_id >> 32; | ||
68 | } | 71 | } |
69 | 72 | ||
70 | return 0; | 73 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
74 | struct wireless_dev *wdev; | ||
75 | |||
76 | if (wiphy_net(&rdev->wiphy) != netns) | ||
77 | continue; | ||
78 | |||
79 | if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) | ||
80 | continue; | ||
81 | |||
82 | mutex_lock(&rdev->devlist_mtx); | ||
83 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | ||
84 | if (have_ifidx && wdev->netdev && | ||
85 | wdev->netdev->ifindex == ifidx) { | ||
86 | result = wdev; | ||
87 | break; | ||
88 | } | ||
89 | if (have_wdev_id && wdev->identifier == (u32)wdev_id) { | ||
90 | result = wdev; | ||
91 | break; | ||
92 | } | ||
93 | } | ||
94 | mutex_unlock(&rdev->devlist_mtx); | ||
95 | |||
96 | if (result) | ||
97 | break; | ||
98 | } | ||
99 | |||
100 | if (result) | ||
101 | return result; | ||
102 | return ERR_PTR(-ENODEV); | ||
103 | } | ||
104 | |||
105 | static struct cfg80211_registered_device * | ||
106 | __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | ||
107 | { | ||
108 | struct cfg80211_registered_device *rdev = NULL, *tmp; | ||
109 | struct net_device *netdev; | ||
110 | |||
111 | assert_cfg80211_lock(); | ||
112 | |||
113 | if (!attrs[NL80211_ATTR_WIPHY] && | ||
114 | !attrs[NL80211_ATTR_IFINDEX] && | ||
115 | !attrs[NL80211_ATTR_WDEV]) | ||
116 | return ERR_PTR(-EINVAL); | ||
117 | |||
118 | if (attrs[NL80211_ATTR_WIPHY]) | ||
119 | rdev = cfg80211_rdev_by_wiphy_idx( | ||
120 | nla_get_u32(attrs[NL80211_ATTR_WIPHY])); | ||
121 | |||
122 | if (attrs[NL80211_ATTR_WDEV]) { | ||
123 | u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]); | ||
124 | struct wireless_dev *wdev; | ||
125 | bool found = false; | ||
126 | |||
127 | tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); | ||
128 | if (tmp) { | ||
129 | /* make sure wdev exists */ | ||
130 | mutex_lock(&tmp->devlist_mtx); | ||
131 | list_for_each_entry(wdev, &tmp->wdev_list, list) { | ||
132 | if (wdev->identifier != (u32)wdev_id) | ||
133 | continue; | ||
134 | found = true; | ||
135 | break; | ||
136 | } | ||
137 | mutex_unlock(&tmp->devlist_mtx); | ||
138 | |||
139 | if (!found) | ||
140 | tmp = NULL; | ||
141 | |||
142 | if (rdev && tmp != rdev) | ||
143 | return ERR_PTR(-EINVAL); | ||
144 | rdev = tmp; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | if (attrs[NL80211_ATTR_IFINDEX]) { | ||
149 | int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | ||
150 | netdev = dev_get_by_index(netns, ifindex); | ||
151 | if (netdev) { | ||
152 | if (netdev->ieee80211_ptr) | ||
153 | tmp = wiphy_to_dev( | ||
154 | netdev->ieee80211_ptr->wiphy); | ||
155 | else | ||
156 | tmp = NULL; | ||
157 | |||
158 | dev_put(netdev); | ||
159 | |||
160 | /* not wireless device -- return error */ | ||
161 | if (!tmp) | ||
162 | return ERR_PTR(-EINVAL); | ||
163 | |||
164 | /* mismatch -- return error */ | ||
165 | if (rdev && tmp != rdev) | ||
166 | return ERR_PTR(-EINVAL); | ||
167 | |||
168 | rdev = tmp; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | if (!rdev) | ||
173 | return ERR_PTR(-ENODEV); | ||
174 | |||
175 | if (netns != wiphy_net(&rdev->wiphy)) | ||
176 | return ERR_PTR(-ENODEV); | ||
177 | |||
178 | return rdev; | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * This function returns a pointer to the driver | ||
183 | * that the genl_info item that is passed refers to. | ||
184 | * If successful, it returns non-NULL and also locks | ||
185 | * the driver's mutex! | ||
186 | * | ||
187 | * This means that you need to call cfg80211_unlock_rdev() | ||
188 | * before being allowed to acquire &cfg80211_mutex! | ||
189 | * | ||
190 | * This is necessary because we need to lock the global | ||
191 | * mutex to get an item off the list safely, and then | ||
192 | * we lock the rdev mutex so it doesn't go away under us. | ||
193 | * | ||
194 | * We don't want to keep cfg80211_mutex locked | ||
195 | * for all the time in order to allow requests on | ||
196 | * other interfaces to go through at the same time. | ||
197 | * | ||
198 | * The result of this can be a PTR_ERR and hence must | ||
199 | * be checked with IS_ERR() for errors. | ||
200 | */ | ||
201 | static struct cfg80211_registered_device * | ||
202 | cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) | ||
203 | { | ||
204 | struct cfg80211_registered_device *rdev; | ||
205 | |||
206 | mutex_lock(&cfg80211_mutex); | ||
207 | rdev = __cfg80211_rdev_from_attrs(netns, info->attrs); | ||
208 | |||
209 | /* if it is not an error we grab the lock on | ||
210 | * it to assure it won't be going away while | ||
211 | * we operate on it */ | ||
212 | if (!IS_ERR(rdev)) | ||
213 | mutex_lock(&rdev->mtx); | ||
214 | |||
215 | mutex_unlock(&cfg80211_mutex); | ||
216 | |||
217 | return rdev; | ||
71 | } | 218 | } |
72 | 219 | ||
73 | /* policy for the attributes */ | 220 | /* policy for the attributes */ |
@@ -115,7 +262,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
115 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, | 262 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, |
116 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, | 263 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, |
117 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, | 264 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, |
118 | .len = IEEE80211_MAX_MESH_ID_LEN }, | 265 | .len = IEEE80211_MAX_MESH_ID_LEN }, |
119 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, | 266 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, |
120 | 267 | ||
121 | [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, | 268 | [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, |
@@ -206,6 +353,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
206 | [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, | 353 | [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, |
207 | [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, | 354 | [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, |
208 | [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, | 355 | [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, |
356 | [NL80211_ATTR_WDEV] = { .type = NLA_U64 }, | ||
357 | [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 }, | ||
209 | }; | 358 | }; |
210 | 359 | ||
211 | /* policy for the key attributes */ | 360 | /* policy for the key attributes */ |
@@ -250,8 +399,9 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { | |||
250 | 399 | ||
251 | static const struct nla_policy | 400 | static const struct nla_policy |
252 | nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { | 401 | nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { |
253 | [NL80211_ATTR_SCHED_SCAN_MATCH_SSID] = { .type = NLA_BINARY, | 402 | [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY, |
254 | .len = IEEE80211_MAX_SSID_LEN }, | 403 | .len = IEEE80211_MAX_SSID_LEN }, |
404 | [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, | ||
255 | }; | 405 | }; |
256 | 406 | ||
257 | /* ifidx get helper */ | 407 | /* ifidx get helper */ |
@@ -832,6 +982,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
832 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) | 982 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) |
833 | goto nla_put_failure; | 983 | goto nla_put_failure; |
834 | 984 | ||
985 | /* add VHT info */ | ||
986 | if (dev->wiphy.bands[band]->vht_cap.vht_supported && | ||
987 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, | ||
988 | sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), | ||
989 | &dev->wiphy.bands[band]->vht_cap.vht_mcs) || | ||
990 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, | ||
991 | dev->wiphy.bands[band]->vht_cap.cap))) | ||
992 | goto nla_put_failure; | ||
993 | |||
835 | /* add frequencies */ | 994 | /* add frequencies */ |
836 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | 995 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); |
837 | if (!nl_freqs) | 996 | if (!nl_freqs) |
@@ -921,7 +1080,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
921 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) | 1080 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) |
922 | goto nla_put_failure; | 1081 | goto nla_put_failure; |
923 | } | 1082 | } |
924 | CMD(set_channel, SET_CHANNEL); | 1083 | if (dev->ops->set_monitor_channel || dev->ops->start_ap || |
1084 | dev->ops->join_mesh) { | ||
1085 | i++; | ||
1086 | if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) | ||
1087 | goto nla_put_failure; | ||
1088 | } | ||
925 | CMD(set_wds_peer, SET_WDS_PEER); | 1089 | CMD(set_wds_peer, SET_WDS_PEER); |
926 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 1090 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { |
927 | CMD(tdls_mgmt, TDLS_MGMT); | 1091 | CMD(tdls_mgmt, TDLS_MGMT); |
@@ -1018,6 +1182,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1018 | nla_nest_end(msg, nl_ifs); | 1182 | nla_nest_end(msg, nl_ifs); |
1019 | } | 1183 | } |
1020 | 1184 | ||
1185 | #ifdef CONFIG_PM | ||
1021 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | 1186 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { |
1022 | struct nlattr *nl_wowlan; | 1187 | struct nlattr *nl_wowlan; |
1023 | 1188 | ||
@@ -1058,6 +1223,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1058 | 1223 | ||
1059 | nla_nest_end(msg, nl_wowlan); | 1224 | nla_nest_end(msg, nl_wowlan); |
1060 | } | 1225 | } |
1226 | #endif | ||
1061 | 1227 | ||
1062 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1228 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, |
1063 | dev->wiphy.software_iftypes)) | 1229 | dev->wiphy.software_iftypes)) |
@@ -1162,18 +1328,22 @@ static int parse_txq_params(struct nlattr *tb[], | |||
1162 | static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) | 1328 | static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) |
1163 | { | 1329 | { |
1164 | /* | 1330 | /* |
1165 | * You can only set the channel explicitly for AP, mesh | 1331 | * You can only set the channel explicitly for WDS interfaces, |
1166 | * and WDS type interfaces; all others have their channel | 1332 | * all others have their channel managed via their respective |
1167 | * managed via their respective "establish a connection" | 1333 | * "establish a connection" command (connect, join, ...) |
1168 | * command (connect, join, ...) | 1334 | * |
1335 | * For AP/GO and mesh mode, the channel can be set with the | ||
1336 | * channel userspace API, but is only stored and passed to the | ||
1337 | * low-level driver when the AP starts or the mesh is joined. | ||
1338 | * This is for backward compatibility, userspace can also give | ||
1339 | * the channel in the start-ap or join-mesh commands instead. | ||
1169 | * | 1340 | * |
1170 | * Monitors are special as they are normally slaved to | 1341 | * Monitors are special as they are normally slaved to |
1171 | * whatever else is going on, so they behave as though | 1342 | * whatever else is going on, so they have their own special |
1172 | * you tried setting the wiphy channel itself. | 1343 | * operation to set the monitor channel if possible. |
1173 | */ | 1344 | */ |
1174 | return !wdev || | 1345 | return !wdev || |
1175 | wdev->iftype == NL80211_IFTYPE_AP || | 1346 | wdev->iftype == NL80211_IFTYPE_AP || |
1176 | wdev->iftype == NL80211_IFTYPE_WDS || | ||
1177 | wdev->iftype == NL80211_IFTYPE_MESH_POINT || | 1347 | wdev->iftype == NL80211_IFTYPE_MESH_POINT || |
1178 | wdev->iftype == NL80211_IFTYPE_MONITOR || | 1348 | wdev->iftype == NL80211_IFTYPE_MONITOR || |
1179 | wdev->iftype == NL80211_IFTYPE_P2P_GO; | 1349 | wdev->iftype == NL80211_IFTYPE_P2P_GO; |
@@ -1204,9 +1374,14 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1204 | struct wireless_dev *wdev, | 1374 | struct wireless_dev *wdev, |
1205 | struct genl_info *info) | 1375 | struct genl_info *info) |
1206 | { | 1376 | { |
1377 | struct ieee80211_channel *channel; | ||
1207 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 1378 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
1208 | u32 freq; | 1379 | u32 freq; |
1209 | int result; | 1380 | int result; |
1381 | enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR; | ||
1382 | |||
1383 | if (wdev) | ||
1384 | iftype = wdev->iftype; | ||
1210 | 1385 | ||
1211 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 1386 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
1212 | return -EINVAL; | 1387 | return -EINVAL; |
@@ -1221,12 +1396,32 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1221 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 1396 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
1222 | 1397 | ||
1223 | mutex_lock(&rdev->devlist_mtx); | 1398 | mutex_lock(&rdev->devlist_mtx); |
1224 | if (wdev) { | 1399 | switch (iftype) { |
1225 | wdev_lock(wdev); | 1400 | case NL80211_IFTYPE_AP: |
1226 | result = cfg80211_set_freq(rdev, wdev, freq, channel_type); | 1401 | case NL80211_IFTYPE_P2P_GO: |
1227 | wdev_unlock(wdev); | 1402 | if (wdev->beacon_interval) { |
1228 | } else { | 1403 | result = -EBUSY; |
1229 | result = cfg80211_set_freq(rdev, NULL, freq, channel_type); | 1404 | break; |
1405 | } | ||
1406 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | ||
1407 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | ||
1408 | channel, | ||
1409 | channel_type)) { | ||
1410 | result = -EINVAL; | ||
1411 | break; | ||
1412 | } | ||
1413 | wdev->preset_chan = channel; | ||
1414 | wdev->preset_chantype = channel_type; | ||
1415 | result = 0; | ||
1416 | break; | ||
1417 | case NL80211_IFTYPE_MESH_POINT: | ||
1418 | result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type); | ||
1419 | break; | ||
1420 | case NL80211_IFTYPE_MONITOR: | ||
1421 | result = cfg80211_set_monitor_channel(rdev, freq, channel_type); | ||
1422 | break; | ||
1423 | default: | ||
1424 | result = -EINVAL; | ||
1230 | } | 1425 | } |
1231 | mutex_unlock(&rdev->devlist_mtx); | 1426 | mutex_unlock(&rdev->devlist_mtx); |
1232 | 1427 | ||
@@ -1300,7 +1495,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1300 | } | 1495 | } |
1301 | 1496 | ||
1302 | if (!netdev) { | 1497 | if (!netdev) { |
1303 | rdev = __cfg80211_rdev_from_info(info); | 1498 | rdev = __cfg80211_rdev_from_attrs(genl_info_net(info), |
1499 | info->attrs); | ||
1304 | if (IS_ERR(rdev)) { | 1500 | if (IS_ERR(rdev)) { |
1305 | mutex_unlock(&cfg80211_mutex); | 1501 | mutex_unlock(&cfg80211_mutex); |
1306 | return PTR_ERR(rdev); | 1502 | return PTR_ERR(rdev); |
@@ -1310,8 +1506,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1310 | result = 0; | 1506 | result = 0; |
1311 | 1507 | ||
1312 | mutex_lock(&rdev->mtx); | 1508 | mutex_lock(&rdev->mtx); |
1313 | } else if (netif_running(netdev) && | 1509 | } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr)) |
1314 | nl80211_can_set_dev_channel(netdev->ieee80211_ptr)) | ||
1315 | wdev = netdev->ieee80211_ptr; | 1510 | wdev = netdev->ieee80211_ptr; |
1316 | else | 1511 | else |
1317 | wdev = NULL; | 1512 | wdev = NULL; |
@@ -1534,22 +1729,32 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1534 | return result; | 1729 | return result; |
1535 | } | 1730 | } |
1536 | 1731 | ||
1732 | static inline u64 wdev_id(struct wireless_dev *wdev) | ||
1733 | { | ||
1734 | return (u64)wdev->identifier | | ||
1735 | ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32); | ||
1736 | } | ||
1537 | 1737 | ||
1538 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 1738 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
1539 | struct cfg80211_registered_device *rdev, | 1739 | struct cfg80211_registered_device *rdev, |
1540 | struct net_device *dev) | 1740 | struct wireless_dev *wdev) |
1541 | { | 1741 | { |
1742 | struct net_device *dev = wdev->netdev; | ||
1542 | void *hdr; | 1743 | void *hdr; |
1543 | 1744 | ||
1544 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); | 1745 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); |
1545 | if (!hdr) | 1746 | if (!hdr) |
1546 | return -1; | 1747 | return -1; |
1547 | 1748 | ||
1548 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | 1749 | if (dev && |
1549 | nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 1750 | (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
1550 | nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || | 1751 | nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || |
1551 | nla_put_u32(msg, NL80211_ATTR_IFTYPE, | 1752 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dev->dev_addr))) |
1552 | dev->ieee80211_ptr->iftype) || | 1753 | goto nla_put_failure; |
1754 | |||
1755 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
1756 | nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) || | ||
1757 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || | ||
1553 | nla_put_u32(msg, NL80211_ATTR_GENERATION, | 1758 | nla_put_u32(msg, NL80211_ATTR_GENERATION, |
1554 | rdev->devlist_generation ^ | 1759 | rdev->devlist_generation ^ |
1555 | (cfg80211_rdev_list_generation << 2))) | 1760 | (cfg80211_rdev_list_generation << 2))) |
@@ -1559,12 +1764,13 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1559 | struct ieee80211_channel *chan; | 1764 | struct ieee80211_channel *chan; |
1560 | enum nl80211_channel_type channel_type; | 1765 | enum nl80211_channel_type channel_type; |
1561 | 1766 | ||
1562 | chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type); | 1767 | chan = rdev->ops->get_channel(&rdev->wiphy, wdev, |
1768 | &channel_type); | ||
1563 | if (chan && | 1769 | if (chan && |
1564 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | 1770 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, |
1565 | chan->center_freq) || | 1771 | chan->center_freq) || |
1566 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | 1772 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, |
1567 | channel_type))) | 1773 | channel_type))) |
1568 | goto nla_put_failure; | 1774 | goto nla_put_failure; |
1569 | } | 1775 | } |
1570 | 1776 | ||
@@ -1595,14 +1801,14 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
1595 | if_idx = 0; | 1801 | if_idx = 0; |
1596 | 1802 | ||
1597 | mutex_lock(&rdev->devlist_mtx); | 1803 | mutex_lock(&rdev->devlist_mtx); |
1598 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 1804 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
1599 | if (if_idx < if_start) { | 1805 | if (if_idx < if_start) { |
1600 | if_idx++; | 1806 | if_idx++; |
1601 | continue; | 1807 | continue; |
1602 | } | 1808 | } |
1603 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 1809 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
1604 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1810 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
1605 | rdev, wdev->netdev) < 0) { | 1811 | rdev, wdev) < 0) { |
1606 | mutex_unlock(&rdev->devlist_mtx); | 1812 | mutex_unlock(&rdev->devlist_mtx); |
1607 | goto out; | 1813 | goto out; |
1608 | } | 1814 | } |
@@ -1625,14 +1831,14 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
1625 | { | 1831 | { |
1626 | struct sk_buff *msg; | 1832 | struct sk_buff *msg; |
1627 | struct cfg80211_registered_device *dev = info->user_ptr[0]; | 1833 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1628 | struct net_device *netdev = info->user_ptr[1]; | 1834 | struct wireless_dev *wdev = info->user_ptr[1]; |
1629 | 1835 | ||
1630 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1836 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1631 | if (!msg) | 1837 | if (!msg) |
1632 | return -ENOMEM; | 1838 | return -ENOMEM; |
1633 | 1839 | ||
1634 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, | 1840 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
1635 | dev, netdev) < 0) { | 1841 | dev, wdev) < 0) { |
1636 | nlmsg_free(msg); | 1842 | nlmsg_free(msg); |
1637 | return -ENOBUFS; | 1843 | return -ENOBUFS; |
1638 | } | 1844 | } |
@@ -1772,7 +1978,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1772 | { | 1978 | { |
1773 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 1979 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1774 | struct vif_params params; | 1980 | struct vif_params params; |
1775 | struct net_device *dev; | 1981 | struct wireless_dev *wdev; |
1982 | struct sk_buff *msg; | ||
1776 | int err; | 1983 | int err; |
1777 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 1984 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
1778 | u32 flags; | 1985 | u32 flags; |
@@ -1799,19 +2006,23 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1799 | return err; | 2006 | return err; |
1800 | } | 2007 | } |
1801 | 2008 | ||
2009 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2010 | if (!msg) | ||
2011 | return -ENOMEM; | ||
2012 | |||
1802 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 2013 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
1803 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 2014 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
1804 | &flags); | 2015 | &flags); |
1805 | dev = rdev->ops->add_virtual_intf(&rdev->wiphy, | 2016 | wdev = rdev->ops->add_virtual_intf(&rdev->wiphy, |
1806 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 2017 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
1807 | type, err ? NULL : &flags, ¶ms); | 2018 | type, err ? NULL : &flags, ¶ms); |
1808 | if (IS_ERR(dev)) | 2019 | if (IS_ERR(wdev)) { |
1809 | return PTR_ERR(dev); | 2020 | nlmsg_free(msg); |
2021 | return PTR_ERR(wdev); | ||
2022 | } | ||
1810 | 2023 | ||
1811 | if (type == NL80211_IFTYPE_MESH_POINT && | 2024 | if (type == NL80211_IFTYPE_MESH_POINT && |
1812 | info->attrs[NL80211_ATTR_MESH_ID]) { | 2025 | info->attrs[NL80211_ATTR_MESH_ID]) { |
1813 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1814 | |||
1815 | wdev_lock(wdev); | 2026 | wdev_lock(wdev); |
1816 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != | 2027 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != |
1817 | IEEE80211_MAX_MESH_ID_LEN); | 2028 | IEEE80211_MAX_MESH_ID_LEN); |
@@ -1822,18 +2033,34 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1822 | wdev_unlock(wdev); | 2033 | wdev_unlock(wdev); |
1823 | } | 2034 | } |
1824 | 2035 | ||
1825 | return 0; | 2036 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
2037 | rdev, wdev) < 0) { | ||
2038 | nlmsg_free(msg); | ||
2039 | return -ENOBUFS; | ||
2040 | } | ||
2041 | |||
2042 | return genlmsg_reply(msg, info); | ||
1826 | } | 2043 | } |
1827 | 2044 | ||
1828 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 2045 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
1829 | { | 2046 | { |
1830 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2047 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1831 | struct net_device *dev = info->user_ptr[1]; | 2048 | struct wireless_dev *wdev = info->user_ptr[1]; |
1832 | 2049 | ||
1833 | if (!rdev->ops->del_virtual_intf) | 2050 | if (!rdev->ops->del_virtual_intf) |
1834 | return -EOPNOTSUPP; | 2051 | return -EOPNOTSUPP; |
1835 | 2052 | ||
1836 | return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); | 2053 | /* |
2054 | * If we remove a wireless device without a netdev then clear | ||
2055 | * user_ptr[1] so that nl80211_post_doit won't dereference it | ||
2056 | * to check if it needs to do dev_put(). Otherwise it crashes | ||
2057 | * since the wdev has been freed, unlike with a netdev where | ||
2058 | * we need the dev_put() for the netdev to really be freed. | ||
2059 | */ | ||
2060 | if (!wdev->netdev) | ||
2061 | info->user_ptr[1] = NULL; | ||
2062 | |||
2063 | return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev); | ||
1837 | } | 2064 | } |
1838 | 2065 | ||
1839 | static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) | 2066 | static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) |
@@ -2213,6 +2440,33 @@ static int nl80211_parse_beacon(struct genl_info *info, | |||
2213 | return 0; | 2440 | return 0; |
2214 | } | 2441 | } |
2215 | 2442 | ||
2443 | static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, | ||
2444 | struct cfg80211_ap_settings *params) | ||
2445 | { | ||
2446 | struct wireless_dev *wdev; | ||
2447 | bool ret = false; | ||
2448 | |||
2449 | mutex_lock(&rdev->devlist_mtx); | ||
2450 | |||
2451 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | ||
2452 | if (wdev->iftype != NL80211_IFTYPE_AP && | ||
2453 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | ||
2454 | continue; | ||
2455 | |||
2456 | if (!wdev->preset_chan) | ||
2457 | continue; | ||
2458 | |||
2459 | params->channel = wdev->preset_chan; | ||
2460 | params->channel_type = wdev->preset_chantype; | ||
2461 | ret = true; | ||
2462 | break; | ||
2463 | } | ||
2464 | |||
2465 | mutex_unlock(&rdev->devlist_mtx); | ||
2466 | |||
2467 | return ret; | ||
2468 | } | ||
2469 | |||
2216 | static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | 2470 | static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) |
2217 | { | 2471 | { |
2218 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2472 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -2299,9 +2553,44 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2299 | info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); | 2553 | info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); |
2300 | } | 2554 | } |
2301 | 2555 | ||
2556 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
2557 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
2558 | |||
2559 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | ||
2560 | !nl80211_valid_channel_type(info, &channel_type)) | ||
2561 | return -EINVAL; | ||
2562 | |||
2563 | params.channel = rdev_freq_to_chan(rdev, | ||
2564 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), | ||
2565 | channel_type); | ||
2566 | if (!params.channel) | ||
2567 | return -EINVAL; | ||
2568 | params.channel_type = channel_type; | ||
2569 | } else if (wdev->preset_chan) { | ||
2570 | params.channel = wdev->preset_chan; | ||
2571 | params.channel_type = wdev->preset_chantype; | ||
2572 | } else if (!nl80211_get_ap_channel(rdev, ¶ms)) | ||
2573 | return -EINVAL; | ||
2574 | |||
2575 | if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel, | ||
2576 | params.channel_type)) | ||
2577 | return -EINVAL; | ||
2578 | |||
2579 | mutex_lock(&rdev->devlist_mtx); | ||
2580 | err = cfg80211_can_use_chan(rdev, wdev, params.channel, | ||
2581 | CHAN_MODE_SHARED); | ||
2582 | mutex_unlock(&rdev->devlist_mtx); | ||
2583 | |||
2584 | if (err) | ||
2585 | return err; | ||
2586 | |||
2302 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); | 2587 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); |
2303 | if (!err) | 2588 | if (!err) { |
2589 | wdev->preset_chan = params.channel; | ||
2590 | wdev->preset_chantype = params.channel_type; | ||
2304 | wdev->beacon_interval = params.beacon_interval; | 2591 | wdev->beacon_interval = params.beacon_interval; |
2592 | wdev->channel = params.channel; | ||
2593 | } | ||
2305 | return err; | 2594 | return err; |
2306 | } | 2595 | } |
2307 | 2596 | ||
@@ -2334,23 +2623,8 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) | |||
2334 | { | 2623 | { |
2335 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2624 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2336 | struct net_device *dev = info->user_ptr[1]; | 2625 | struct net_device *dev = info->user_ptr[1]; |
2337 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2338 | int err; | ||
2339 | 2626 | ||
2340 | if (!rdev->ops->stop_ap) | 2627 | return cfg80211_stop_ap(rdev, dev); |
2341 | return -EOPNOTSUPP; | ||
2342 | |||
2343 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
2344 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
2345 | return -EOPNOTSUPP; | ||
2346 | |||
2347 | if (!wdev->beacon_interval) | ||
2348 | return -ENOENT; | ||
2349 | |||
2350 | err = rdev->ops->stop_ap(&rdev->wiphy, dev); | ||
2351 | if (!err) | ||
2352 | wdev->beacon_interval = 0; | ||
2353 | return err; | ||
2354 | } | 2628 | } |
2355 | 2629 | ||
2356 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 2630 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -2442,7 +2716,8 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2442 | int attr) | 2716 | int attr) |
2443 | { | 2717 | { |
2444 | struct nlattr *rate; | 2718 | struct nlattr *rate; |
2445 | u16 bitrate; | 2719 | u32 bitrate; |
2720 | u16 bitrate_compat; | ||
2446 | 2721 | ||
2447 | rate = nla_nest_start(msg, attr); | 2722 | rate = nla_nest_start(msg, attr); |
2448 | if (!rate) | 2723 | if (!rate) |
@@ -2450,8 +2725,12 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2450 | 2725 | ||
2451 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ | 2726 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ |
2452 | bitrate = cfg80211_calculate_bitrate(info); | 2727 | bitrate = cfg80211_calculate_bitrate(info); |
2728 | /* report 16-bit bitrate only if we can */ | ||
2729 | bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; | ||
2453 | if ((bitrate > 0 && | 2730 | if ((bitrate > 0 && |
2454 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate)) || | 2731 | nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) || |
2732 | (bitrate_compat > 0 && | ||
2733 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) || | ||
2455 | ((info->flags & RATE_INFO_FLAGS_MCS) && | 2734 | ((info->flags & RATE_INFO_FLAGS_MCS) && |
2456 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || | 2735 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || |
2457 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && | 2736 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && |
@@ -3304,6 +3583,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3304 | { | 3583 | { |
3305 | int r; | 3584 | int r; |
3306 | char *data = NULL; | 3585 | char *data = NULL; |
3586 | enum nl80211_user_reg_hint_type user_reg_hint_type; | ||
3307 | 3587 | ||
3308 | /* | 3588 | /* |
3309 | * You should only get this when cfg80211 hasn't yet initialized | 3589 | * You should only get this when cfg80211 hasn't yet initialized |
@@ -3323,7 +3603,21 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3323 | 3603 | ||
3324 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 3604 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
3325 | 3605 | ||
3326 | r = regulatory_hint_user(data); | 3606 | if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]) |
3607 | user_reg_hint_type = | ||
3608 | nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]); | ||
3609 | else | ||
3610 | user_reg_hint_type = NL80211_USER_REG_HINT_USER; | ||
3611 | |||
3612 | switch (user_reg_hint_type) { | ||
3613 | case NL80211_USER_REG_HINT_USER: | ||
3614 | case NL80211_USER_REG_HINT_CELL_BASE: | ||
3615 | break; | ||
3616 | default: | ||
3617 | return -EINVAL; | ||
3618 | } | ||
3619 | |||
3620 | r = regulatory_hint_user(data, user_reg_hint_type); | ||
3327 | 3621 | ||
3328 | return r; | 3622 | return r; |
3329 | } | 3623 | } |
@@ -3413,7 +3707,13 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, | |||
3413 | nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD, | 3707 | nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD, |
3414 | cur_params.rssi_threshold) || | 3708 | cur_params.rssi_threshold) || |
3415 | nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE, | 3709 | nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE, |
3416 | cur_params.ht_opmode)) | 3710 | cur_params.ht_opmode) || |
3711 | nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, | ||
3712 | cur_params.dot11MeshHWMPactivePathToRootTimeout) || | ||
3713 | nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL, | ||
3714 | cur_params.dot11MeshHWMProotInterval) || | ||
3715 | nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, | ||
3716 | cur_params.dot11MeshHWMPconfirmationInterval)) | ||
3417 | goto nla_put_failure; | 3717 | goto nla_put_failure; |
3418 | nla_nest_end(msg, pinfoattr); | 3718 | nla_nest_end(msg, pinfoattr); |
3419 | genlmsg_end(msg, hdr); | 3719 | genlmsg_end(msg, hdr); |
@@ -3436,7 +3736,6 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
3436 | [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 }, | 3736 | [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 }, |
3437 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, | 3737 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, |
3438 | [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 }, | 3738 | [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 }, |
3439 | |||
3440 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, | 3739 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, |
3441 | [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, | 3740 | [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, |
3442 | [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, | 3741 | [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, |
@@ -3448,8 +3747,11 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
3448 | [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, | 3747 | [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, |
3449 | [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, | 3748 | [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, |
3450 | [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 }, | 3749 | [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 }, |
3451 | [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32}, | 3750 | [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 }, |
3452 | [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16}, | 3751 | [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 }, |
3752 | [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 }, | ||
3753 | [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 }, | ||
3754 | [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 }, | ||
3453 | }; | 3755 | }; |
3454 | 3756 | ||
3455 | static const struct nla_policy | 3757 | static const struct nla_policy |
@@ -3459,7 +3761,7 @@ static const struct nla_policy | |||
3459 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, | 3761 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, |
3460 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, | 3762 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, |
3461 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, | 3763 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, |
3462 | .len = IEEE80211_MAX_DATA_LEN }, | 3764 | .len = IEEE80211_MAX_DATA_LEN }, |
3463 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, | 3765 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, |
3464 | }; | 3766 | }; |
3465 | 3767 | ||
@@ -3492,63 +3794,82 @@ do {\ | |||
3492 | 3794 | ||
3493 | /* Fill in the params struct */ | 3795 | /* Fill in the params struct */ |
3494 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, | 3796 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, |
3495 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); | 3797 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, |
3798 | nla_get_u16); | ||
3496 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, | 3799 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, |
3497 | mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16); | 3800 | mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, |
3801 | nla_get_u16); | ||
3498 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, | 3802 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, |
3499 | mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16); | 3803 | mask, NL80211_MESHCONF_HOLDING_TIMEOUT, |
3804 | nla_get_u16); | ||
3500 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, | 3805 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, |
3501 | mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16); | 3806 | mask, NL80211_MESHCONF_MAX_PEER_LINKS, |
3807 | nla_get_u16); | ||
3502 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, | 3808 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, |
3503 | mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); | 3809 | mask, NL80211_MESHCONF_MAX_RETRIES, |
3810 | nla_get_u8); | ||
3504 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, | 3811 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, |
3505 | mask, NL80211_MESHCONF_TTL, nla_get_u8); | 3812 | mask, NL80211_MESHCONF_TTL, nla_get_u8); |
3506 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, | 3813 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, |
3507 | mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8); | 3814 | mask, NL80211_MESHCONF_ELEMENT_TTL, |
3815 | nla_get_u8); | ||
3508 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, | 3816 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, |
3509 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); | 3817 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, |
3510 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, | 3818 | nla_get_u8); |
3511 | mask, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, | 3819 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, mask, |
3512 | nla_get_u32); | 3820 | NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, |
3821 | nla_get_u32); | ||
3513 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, | 3822 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, |
3514 | mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, | 3823 | mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, |
3515 | nla_get_u8); | 3824 | nla_get_u8); |
3516 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, | 3825 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, |
3517 | mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32); | 3826 | mask, NL80211_MESHCONF_PATH_REFRESH_TIME, |
3827 | nla_get_u32); | ||
3518 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, | 3828 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, |
3519 | mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, | 3829 | mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, |
3520 | nla_get_u16); | 3830 | nla_get_u16); |
3521 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, | 3831 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, mask, |
3522 | mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, | 3832 | NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, |
3523 | nla_get_u32); | 3833 | nla_get_u32); |
3524 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, | 3834 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, |
3525 | mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, | 3835 | mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, |
3526 | nla_get_u16); | 3836 | nla_get_u16); |
3527 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, | 3837 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, |
3528 | mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, | 3838 | mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, |
3529 | nla_get_u16); | 3839 | nla_get_u16); |
3530 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | 3840 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, |
3531 | dot11MeshHWMPnetDiameterTraversalTime, | 3841 | dot11MeshHWMPnetDiameterTraversalTime, mask, |
3532 | mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 3842 | NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
3533 | nla_get_u16); | 3843 | nla_get_u16); |
3844 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask, | ||
3845 | NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8); | ||
3846 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask, | ||
3847 | NL80211_MESHCONF_HWMP_RANN_INTERVAL, | ||
3848 | nla_get_u16); | ||
3534 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | 3849 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, |
3535 | dot11MeshHWMPRootMode, mask, | 3850 | dot11MeshGateAnnouncementProtocol, mask, |
3536 | NL80211_MESHCONF_HWMP_ROOTMODE, | 3851 | NL80211_MESHCONF_GATE_ANNOUNCEMENTS, |
3537 | nla_get_u8); | 3852 | nla_get_u8); |
3538 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | ||
3539 | dot11MeshHWMPRannInterval, mask, | ||
3540 | NL80211_MESHCONF_HWMP_RANN_INTERVAL, | ||
3541 | nla_get_u16); | ||
3542 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | ||
3543 | dot11MeshGateAnnouncementProtocol, mask, | ||
3544 | NL80211_MESHCONF_GATE_ANNOUNCEMENTS, | ||
3545 | nla_get_u8); | ||
3546 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, | 3853 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, |
3547 | mask, NL80211_MESHCONF_FORWARDING, nla_get_u8); | 3854 | mask, NL80211_MESHCONF_FORWARDING, |
3855 | nla_get_u8); | ||
3548 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, | 3856 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, |
3549 | mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32); | 3857 | mask, NL80211_MESHCONF_RSSI_THRESHOLD, |
3858 | nla_get_u32); | ||
3550 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, | 3859 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, |
3551 | mask, NL80211_MESHCONF_HT_OPMODE, nla_get_u16); | 3860 | mask, NL80211_MESHCONF_HT_OPMODE, |
3861 | nla_get_u16); | ||
3862 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout, | ||
3863 | mask, | ||
3864 | NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, | ||
3865 | nla_get_u32); | ||
3866 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, | ||
3867 | mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL, | ||
3868 | nla_get_u16); | ||
3869 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | ||
3870 | dot11MeshHWMPconfirmationInterval, mask, | ||
3871 | NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, | ||
3872 | nla_get_u16); | ||
3552 | if (mask_out) | 3873 | if (mask_out) |
3553 | *mask_out = mask; | 3874 | *mask_out = mask; |
3554 | 3875 | ||
@@ -3666,6 +3987,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
3666 | cfg80211_regdomain->dfs_region))) | 3987 | cfg80211_regdomain->dfs_region))) |
3667 | goto nla_put_failure; | 3988 | goto nla_put_failure; |
3668 | 3989 | ||
3990 | if (reg_last_request_cell_base() && | ||
3991 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
3992 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
3993 | goto nla_put_failure; | ||
3994 | |||
3669 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); | 3995 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); |
3670 | if (!nl_reg_rules) | 3996 | if (!nl_reg_rules) |
3671 | goto nla_put_failure; | 3997 | goto nla_put_failure; |
@@ -3831,7 +4157,7 @@ static int validate_scan_freqs(struct nlattr *freqs) | |||
3831 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 4157 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
3832 | { | 4158 | { |
3833 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4159 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3834 | struct net_device *dev = info->user_ptr[1]; | 4160 | struct wireless_dev *wdev = info->user_ptr[1]; |
3835 | struct cfg80211_scan_request *request; | 4161 | struct cfg80211_scan_request *request; |
3836 | struct nlattr *attr; | 4162 | struct nlattr *attr; |
3837 | struct wiphy *wiphy; | 4163 | struct wiphy *wiphy; |
@@ -3991,15 +4317,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3991 | request->no_cck = | 4317 | request->no_cck = |
3992 | nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); | 4318 | nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); |
3993 | 4319 | ||
3994 | request->dev = dev; | 4320 | request->wdev = wdev; |
3995 | request->wiphy = &rdev->wiphy; | 4321 | request->wiphy = &rdev->wiphy; |
3996 | 4322 | ||
3997 | rdev->scan_req = request; | 4323 | rdev->scan_req = request; |
3998 | err = rdev->ops->scan(&rdev->wiphy, dev, request); | 4324 | err = rdev->ops->scan(&rdev->wiphy, request); |
3999 | 4325 | ||
4000 | if (!err) { | 4326 | if (!err) { |
4001 | nl80211_send_scan_start(rdev, dev); | 4327 | nl80211_send_scan_start(rdev, wdev); |
4002 | dev_hold(dev); | 4328 | if (wdev->netdev) |
4329 | dev_hold(wdev->netdev); | ||
4003 | } else { | 4330 | } else { |
4004 | out_free: | 4331 | out_free: |
4005 | rdev->scan_req = NULL; | 4332 | rdev->scan_req = NULL; |
@@ -4185,12 +4512,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
4185 | nla_for_each_nested(attr, | 4512 | nla_for_each_nested(attr, |
4186 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], | 4513 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], |
4187 | tmp) { | 4514 | tmp) { |
4188 | struct nlattr *ssid; | 4515 | struct nlattr *ssid, *rssi; |
4189 | 4516 | ||
4190 | nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, | 4517 | nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, |
4191 | nla_data(attr), nla_len(attr), | 4518 | nla_data(attr), nla_len(attr), |
4192 | nl80211_match_policy); | 4519 | nl80211_match_policy); |
4193 | ssid = tb[NL80211_ATTR_SCHED_SCAN_MATCH_SSID]; | 4520 | ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; |
4194 | if (ssid) { | 4521 | if (ssid) { |
4195 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { | 4522 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { |
4196 | err = -EINVAL; | 4523 | err = -EINVAL; |
@@ -4201,6 +4528,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
4201 | request->match_sets[i].ssid.ssid_len = | 4528 | request->match_sets[i].ssid.ssid_len = |
4202 | nla_len(ssid); | 4529 | nla_len(ssid); |
4203 | } | 4530 | } |
4531 | rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; | ||
4532 | if (rssi) | ||
4533 | request->rssi_thold = nla_get_u32(rssi); | ||
4534 | else | ||
4535 | request->rssi_thold = | ||
4536 | NL80211_SCAN_RSSI_THOLD_OFF; | ||
4204 | i++; | 4537 | i++; |
4205 | } | 4538 | } |
4206 | } | 4539 | } |
@@ -5058,21 +5391,18 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
5058 | nl80211_policy); | 5391 | nl80211_policy); |
5059 | if (err) | 5392 | if (err) |
5060 | return err; | 5393 | return err; |
5061 | if (nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) { | ||
5062 | phy_idx = nla_get_u32( | ||
5063 | nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]); | ||
5064 | } else { | ||
5065 | struct net_device *netdev; | ||
5066 | 5394 | ||
5067 | err = get_rdev_dev_by_ifindex(sock_net(skb->sk), | 5395 | mutex_lock(&cfg80211_mutex); |
5068 | nl80211_fam.attrbuf, | 5396 | rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), |
5069 | &rdev, &netdev); | 5397 | nl80211_fam.attrbuf); |
5070 | if (err) | 5398 | if (IS_ERR(rdev)) { |
5071 | return err; | 5399 | mutex_unlock(&cfg80211_mutex); |
5072 | dev_put(netdev); | 5400 | return PTR_ERR(rdev); |
5073 | phy_idx = rdev->wiphy_idx; | ||
5074 | cfg80211_unlock_rdev(rdev); | ||
5075 | } | 5401 | } |
5402 | phy_idx = rdev->wiphy_idx; | ||
5403 | rdev = NULL; | ||
5404 | mutex_unlock(&cfg80211_mutex); | ||
5405 | |||
5076 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) | 5406 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) |
5077 | cb->args[1] = | 5407 | cb->args[1] = |
5078 | (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; | 5408 | (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; |
@@ -5474,7 +5804,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5474 | struct genl_info *info) | 5804 | struct genl_info *info) |
5475 | { | 5805 | { |
5476 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5806 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5477 | struct net_device *dev = info->user_ptr[1]; | 5807 | struct wireless_dev *wdev = info->user_ptr[1]; |
5478 | struct ieee80211_channel *chan; | 5808 | struct ieee80211_channel *chan; |
5479 | struct sk_buff *msg; | 5809 | struct sk_buff *msg; |
5480 | void *hdr; | 5810 | void *hdr; |
@@ -5489,18 +5819,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5489 | 5819 | ||
5490 | duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | 5820 | duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); |
5491 | 5821 | ||
5822 | if (!rdev->ops->remain_on_channel || | ||
5823 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)) | ||
5824 | return -EOPNOTSUPP; | ||
5825 | |||
5492 | /* | 5826 | /* |
5493 | * We should be on that channel for at least one jiffie, | 5827 | * We should be on that channel for at least a minimum amount of |
5494 | * and more than 5 seconds seems excessive. | 5828 | * time (10ms) but no longer than the driver supports. |
5495 | */ | 5829 | */ |
5496 | if (!duration || !msecs_to_jiffies(duration) || | 5830 | if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || |
5497 | duration > rdev->wiphy.max_remain_on_channel_duration) | 5831 | duration > rdev->wiphy.max_remain_on_channel_duration) |
5498 | return -EINVAL; | 5832 | return -EINVAL; |
5499 | 5833 | ||
5500 | if (!rdev->ops->remain_on_channel || | ||
5501 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)) | ||
5502 | return -EOPNOTSUPP; | ||
5503 | |||
5504 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | 5834 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && |
5505 | !nl80211_valid_channel_type(info, &channel_type)) | 5835 | !nl80211_valid_channel_type(info, &channel_type)) |
5506 | return -EINVAL; | 5836 | return -EINVAL; |
@@ -5522,7 +5852,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5522 | goto free_msg; | 5852 | goto free_msg; |
5523 | } | 5853 | } |
5524 | 5854 | ||
5525 | err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, | 5855 | err = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, |
5526 | channel_type, duration, &cookie); | 5856 | channel_type, duration, &cookie); |
5527 | 5857 | ||
5528 | if (err) | 5858 | if (err) |
@@ -5546,7 +5876,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
5546 | struct genl_info *info) | 5876 | struct genl_info *info) |
5547 | { | 5877 | { |
5548 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5878 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5549 | struct net_device *dev = info->user_ptr[1]; | 5879 | struct wireless_dev *wdev = info->user_ptr[1]; |
5550 | u64 cookie; | 5880 | u64 cookie; |
5551 | 5881 | ||
5552 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 5882 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
@@ -5557,7 +5887,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
5557 | 5887 | ||
5558 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 5888 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
5559 | 5889 | ||
5560 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); | 5890 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie); |
5561 | } | 5891 | } |
5562 | 5892 | ||
5563 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | 5893 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, |
@@ -5706,7 +6036,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
5706 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | 6036 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) |
5707 | { | 6037 | { |
5708 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6038 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5709 | struct net_device *dev = info->user_ptr[1]; | 6039 | struct wireless_dev *wdev = info->user_ptr[1]; |
5710 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; | 6040 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; |
5711 | 6041 | ||
5712 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) | 6042 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) |
@@ -5715,21 +6045,24 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5715 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) | 6045 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) |
5716 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); | 6046 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); |
5717 | 6047 | ||
5718 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6048 | switch (wdev->iftype) { |
5719 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6049 | case NL80211_IFTYPE_STATION: |
5720 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6050 | case NL80211_IFTYPE_ADHOC: |
5721 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6051 | case NL80211_IFTYPE_P2P_CLIENT: |
5722 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6052 | case NL80211_IFTYPE_AP: |
5723 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 6053 | case NL80211_IFTYPE_AP_VLAN: |
5724 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6054 | case NL80211_IFTYPE_MESH_POINT: |
6055 | case NL80211_IFTYPE_P2P_GO: | ||
6056 | break; | ||
6057 | default: | ||
5725 | return -EOPNOTSUPP; | 6058 | return -EOPNOTSUPP; |
6059 | } | ||
5726 | 6060 | ||
5727 | /* not much point in registering if we can't reply */ | 6061 | /* not much point in registering if we can't reply */ |
5728 | if (!rdev->ops->mgmt_tx) | 6062 | if (!rdev->ops->mgmt_tx) |
5729 | return -EOPNOTSUPP; | 6063 | return -EOPNOTSUPP; |
5730 | 6064 | ||
5731 | return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, | 6065 | return cfg80211_mlme_register_mgmt(wdev, info->snd_pid, frame_type, |
5732 | frame_type, | ||
5733 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), | 6066 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), |
5734 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); | 6067 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); |
5735 | } | 6068 | } |
@@ -5737,7 +6070,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5737 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | 6070 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) |
5738 | { | 6071 | { |
5739 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6072 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5740 | struct net_device *dev = info->user_ptr[1]; | 6073 | struct wireless_dev *wdev = info->user_ptr[1]; |
5741 | struct ieee80211_channel *chan; | 6074 | struct ieee80211_channel *chan; |
5742 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 6075 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
5743 | bool channel_type_valid = false; | 6076 | bool channel_type_valid = false; |
@@ -5758,19 +6091,32 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5758 | if (!rdev->ops->mgmt_tx) | 6091 | if (!rdev->ops->mgmt_tx) |
5759 | return -EOPNOTSUPP; | 6092 | return -EOPNOTSUPP; |
5760 | 6093 | ||
5761 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6094 | switch (wdev->iftype) { |
5762 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6095 | case NL80211_IFTYPE_STATION: |
5763 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6096 | case NL80211_IFTYPE_ADHOC: |
5764 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6097 | case NL80211_IFTYPE_P2P_CLIENT: |
5765 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6098 | case NL80211_IFTYPE_AP: |
5766 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 6099 | case NL80211_IFTYPE_AP_VLAN: |
5767 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6100 | case NL80211_IFTYPE_MESH_POINT: |
6101 | case NL80211_IFTYPE_P2P_GO: | ||
6102 | break; | ||
6103 | default: | ||
5768 | return -EOPNOTSUPP; | 6104 | return -EOPNOTSUPP; |
6105 | } | ||
5769 | 6106 | ||
5770 | if (info->attrs[NL80211_ATTR_DURATION]) { | 6107 | if (info->attrs[NL80211_ATTR_DURATION]) { |
5771 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) | 6108 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) |
5772 | return -EINVAL; | 6109 | return -EINVAL; |
5773 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | 6110 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); |
6111 | |||
6112 | /* | ||
6113 | * We should wait on the channel for at least a minimum amount | ||
6114 | * of time (10ms) but no longer than the driver supports. | ||
6115 | */ | ||
6116 | if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || | ||
6117 | wait > rdev->wiphy.max_remain_on_channel_duration) | ||
6118 | return -EINVAL; | ||
6119 | |||
5774 | } | 6120 | } |
5775 | 6121 | ||
5776 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 6122 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
@@ -5805,7 +6151,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5805 | } | 6151 | } |
5806 | } | 6152 | } |
5807 | 6153 | ||
5808 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, | 6154 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type, |
5809 | channel_type_valid, wait, | 6155 | channel_type_valid, wait, |
5810 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 6156 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
5811 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 6157 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
@@ -5833,7 +6179,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5833 | static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info) | 6179 | static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info) |
5834 | { | 6180 | { |
5835 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6181 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5836 | struct net_device *dev = info->user_ptr[1]; | 6182 | struct wireless_dev *wdev = info->user_ptr[1]; |
5837 | u64 cookie; | 6183 | u64 cookie; |
5838 | 6184 | ||
5839 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 6185 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
@@ -5842,17 +6188,21 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in | |||
5842 | if (!rdev->ops->mgmt_tx_cancel_wait) | 6188 | if (!rdev->ops->mgmt_tx_cancel_wait) |
5843 | return -EOPNOTSUPP; | 6189 | return -EOPNOTSUPP; |
5844 | 6190 | ||
5845 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6191 | switch (wdev->iftype) { |
5846 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6192 | case NL80211_IFTYPE_STATION: |
5847 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6193 | case NL80211_IFTYPE_ADHOC: |
5848 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6194 | case NL80211_IFTYPE_P2P_CLIENT: |
5849 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6195 | case NL80211_IFTYPE_AP: |
5850 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6196 | case NL80211_IFTYPE_AP_VLAN: |
6197 | case NL80211_IFTYPE_P2P_GO: | ||
6198 | break; | ||
6199 | default: | ||
5851 | return -EOPNOTSUPP; | 6200 | return -EOPNOTSUPP; |
6201 | } | ||
5852 | 6202 | ||
5853 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 6203 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
5854 | 6204 | ||
5855 | return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, dev, cookie); | 6205 | return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie); |
5856 | } | 6206 | } |
5857 | 6207 | ||
5858 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) | 6208 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) |
@@ -5938,8 +6288,35 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | |||
5938 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, | 6288 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, |
5939 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, | 6289 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, |
5940 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, | 6290 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, |
6291 | [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 }, | ||
6292 | [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 }, | ||
6293 | [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 }, | ||
5941 | }; | 6294 | }; |
5942 | 6295 | ||
6296 | static int nl80211_set_cqm_txe(struct genl_info *info, | ||
6297 | u32 rate, u32 pkts, u32 intvl) | ||
6298 | { | ||
6299 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
6300 | struct wireless_dev *wdev; | ||
6301 | struct net_device *dev = info->user_ptr[1]; | ||
6302 | |||
6303 | if ((rate < 0 || rate > 100) || | ||
6304 | (intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL)) | ||
6305 | return -EINVAL; | ||
6306 | |||
6307 | wdev = dev->ieee80211_ptr; | ||
6308 | |||
6309 | if (!rdev->ops->set_cqm_txe_config) | ||
6310 | return -EOPNOTSUPP; | ||
6311 | |||
6312 | if (wdev->iftype != NL80211_IFTYPE_STATION && | ||
6313 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) | ||
6314 | return -EOPNOTSUPP; | ||
6315 | |||
6316 | return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev, | ||
6317 | rate, pkts, intvl); | ||
6318 | } | ||
6319 | |||
5943 | static int nl80211_set_cqm_rssi(struct genl_info *info, | 6320 | static int nl80211_set_cqm_rssi(struct genl_info *info, |
5944 | s32 threshold, u32 hysteresis) | 6321 | s32 threshold, u32 hysteresis) |
5945 | { | 6322 | { |
@@ -5987,6 +6364,14 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | |||
5987 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); | 6364 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); |
5988 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); | 6365 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); |
5989 | err = nl80211_set_cqm_rssi(info, threshold, hysteresis); | 6366 | err = nl80211_set_cqm_rssi(info, threshold, hysteresis); |
6367 | } else if (attrs[NL80211_ATTR_CQM_TXE_RATE] && | ||
6368 | attrs[NL80211_ATTR_CQM_TXE_PKTS] && | ||
6369 | attrs[NL80211_ATTR_CQM_TXE_INTVL]) { | ||
6370 | u32 rate, pkts, intvl; | ||
6371 | rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]); | ||
6372 | pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]); | ||
6373 | intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]); | ||
6374 | err = nl80211_set_cqm_txe(info, rate, pkts, intvl); | ||
5990 | } else | 6375 | } else |
5991 | err = -EINVAL; | 6376 | err = -EINVAL; |
5992 | 6377 | ||
@@ -6032,6 +6417,24 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6032 | return err; | 6417 | return err; |
6033 | } | 6418 | } |
6034 | 6419 | ||
6420 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
6421 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
6422 | |||
6423 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | ||
6424 | !nl80211_valid_channel_type(info, &channel_type)) | ||
6425 | return -EINVAL; | ||
6426 | |||
6427 | setup.channel = rdev_freq_to_chan(rdev, | ||
6428 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), | ||
6429 | channel_type); | ||
6430 | if (!setup.channel) | ||
6431 | return -EINVAL; | ||
6432 | setup.channel_type = channel_type; | ||
6433 | } else { | ||
6434 | /* cfg80211_join_mesh() will sort it out */ | ||
6435 | setup.channel = NULL; | ||
6436 | } | ||
6437 | |||
6035 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); | 6438 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); |
6036 | } | 6439 | } |
6037 | 6440 | ||
@@ -6043,6 +6446,7 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6043 | return cfg80211_leave_mesh(rdev, dev); | 6446 | return cfg80211_leave_mesh(rdev, dev); |
6044 | } | 6447 | } |
6045 | 6448 | ||
6449 | #ifdef CONFIG_PM | ||
6046 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 6450 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
6047 | { | 6451 | { |
6048 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6452 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -6124,8 +6528,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6124 | { | 6528 | { |
6125 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6529 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6126 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; | 6530 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; |
6127 | struct cfg80211_wowlan no_triggers = {}; | ||
6128 | struct cfg80211_wowlan new_triggers = {}; | 6531 | struct cfg80211_wowlan new_triggers = {}; |
6532 | struct cfg80211_wowlan *ntrig; | ||
6129 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; | 6533 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; |
6130 | int err, i; | 6534 | int err, i; |
6131 | bool prev_enabled = rdev->wowlan; | 6535 | bool prev_enabled = rdev->wowlan; |
@@ -6133,8 +6537,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6133 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 6537 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) |
6134 | return -EOPNOTSUPP; | 6538 | return -EOPNOTSUPP; |
6135 | 6539 | ||
6136 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) | 6540 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { |
6137 | goto no_triggers; | 6541 | cfg80211_rdev_free_wowlan(rdev); |
6542 | rdev->wowlan = NULL; | ||
6543 | goto set_wakeup; | ||
6544 | } | ||
6138 | 6545 | ||
6139 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, | 6546 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, |
6140 | nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), | 6547 | nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), |
@@ -6245,22 +6652,15 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6245 | } | 6652 | } |
6246 | } | 6653 | } |
6247 | 6654 | ||
6248 | if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) { | 6655 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); |
6249 | struct cfg80211_wowlan *ntrig; | 6656 | if (!ntrig) { |
6250 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), | 6657 | err = -ENOMEM; |
6251 | GFP_KERNEL); | 6658 | goto error; |
6252 | if (!ntrig) { | ||
6253 | err = -ENOMEM; | ||
6254 | goto error; | ||
6255 | } | ||
6256 | cfg80211_rdev_free_wowlan(rdev); | ||
6257 | rdev->wowlan = ntrig; | ||
6258 | } else { | ||
6259 | no_triggers: | ||
6260 | cfg80211_rdev_free_wowlan(rdev); | ||
6261 | rdev->wowlan = NULL; | ||
6262 | } | 6659 | } |
6660 | cfg80211_rdev_free_wowlan(rdev); | ||
6661 | rdev->wowlan = ntrig; | ||
6263 | 6662 | ||
6663 | set_wakeup: | ||
6264 | if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan) | 6664 | if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan) |
6265 | rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan); | 6665 | rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan); |
6266 | 6666 | ||
@@ -6271,6 +6671,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6271 | kfree(new_triggers.patterns); | 6671 | kfree(new_triggers.patterns); |
6272 | return err; | 6672 | return err; |
6273 | } | 6673 | } |
6674 | #endif | ||
6274 | 6675 | ||
6275 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | 6676 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) |
6276 | { | 6677 | { |
@@ -6415,44 +6816,75 @@ static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) | |||
6415 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 | 6816 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 |
6416 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ | 6817 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ |
6417 | NL80211_FLAG_CHECK_NETDEV_UP) | 6818 | NL80211_FLAG_CHECK_NETDEV_UP) |
6819 | #define NL80211_FLAG_NEED_WDEV 0x10 | ||
6820 | /* If a netdev is associated, it must be UP */ | ||
6821 | #define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\ | ||
6822 | NL80211_FLAG_CHECK_NETDEV_UP) | ||
6418 | 6823 | ||
6419 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | 6824 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, |
6420 | struct genl_info *info) | 6825 | struct genl_info *info) |
6421 | { | 6826 | { |
6422 | struct cfg80211_registered_device *rdev; | 6827 | struct cfg80211_registered_device *rdev; |
6828 | struct wireless_dev *wdev; | ||
6423 | struct net_device *dev; | 6829 | struct net_device *dev; |
6424 | int err; | ||
6425 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; | 6830 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; |
6426 | 6831 | ||
6427 | if (rtnl) | 6832 | if (rtnl) |
6428 | rtnl_lock(); | 6833 | rtnl_lock(); |
6429 | 6834 | ||
6430 | if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { | 6835 | if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { |
6431 | rdev = cfg80211_get_dev_from_info(info); | 6836 | rdev = cfg80211_get_dev_from_info(genl_info_net(info), info); |
6432 | if (IS_ERR(rdev)) { | 6837 | if (IS_ERR(rdev)) { |
6433 | if (rtnl) | 6838 | if (rtnl) |
6434 | rtnl_unlock(); | 6839 | rtnl_unlock(); |
6435 | return PTR_ERR(rdev); | 6840 | return PTR_ERR(rdev); |
6436 | } | 6841 | } |
6437 | info->user_ptr[0] = rdev; | 6842 | info->user_ptr[0] = rdev; |
6438 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { | 6843 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV || |
6439 | err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs, | 6844 | ops->internal_flags & NL80211_FLAG_NEED_WDEV) { |
6440 | &rdev, &dev); | 6845 | mutex_lock(&cfg80211_mutex); |
6441 | if (err) { | 6846 | wdev = __cfg80211_wdev_from_attrs(genl_info_net(info), |
6847 | info->attrs); | ||
6848 | if (IS_ERR(wdev)) { | ||
6849 | mutex_unlock(&cfg80211_mutex); | ||
6442 | if (rtnl) | 6850 | if (rtnl) |
6443 | rtnl_unlock(); | 6851 | rtnl_unlock(); |
6444 | return err; | 6852 | return PTR_ERR(wdev); |
6445 | } | 6853 | } |
6446 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | 6854 | |
6447 | !netif_running(dev)) { | 6855 | dev = wdev->netdev; |
6448 | cfg80211_unlock_rdev(rdev); | 6856 | rdev = wiphy_to_dev(wdev->wiphy); |
6449 | dev_put(dev); | 6857 | |
6450 | if (rtnl) | 6858 | if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { |
6451 | rtnl_unlock(); | 6859 | if (!dev) { |
6452 | return -ENETDOWN; | 6860 | mutex_unlock(&cfg80211_mutex); |
6861 | if (rtnl) | ||
6862 | rtnl_unlock(); | ||
6863 | return -EINVAL; | ||
6864 | } | ||
6865 | |||
6866 | info->user_ptr[1] = dev; | ||
6867 | } else { | ||
6868 | info->user_ptr[1] = wdev; | ||
6453 | } | 6869 | } |
6870 | |||
6871 | if (dev) { | ||
6872 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | ||
6873 | !netif_running(dev)) { | ||
6874 | mutex_unlock(&cfg80211_mutex); | ||
6875 | if (rtnl) | ||
6876 | rtnl_unlock(); | ||
6877 | return -ENETDOWN; | ||
6878 | } | ||
6879 | |||
6880 | dev_hold(dev); | ||
6881 | } | ||
6882 | |||
6883 | cfg80211_lock_rdev(rdev); | ||
6884 | |||
6885 | mutex_unlock(&cfg80211_mutex); | ||
6886 | |||
6454 | info->user_ptr[0] = rdev; | 6887 | info->user_ptr[0] = rdev; |
6455 | info->user_ptr[1] = dev; | ||
6456 | } | 6888 | } |
6457 | 6889 | ||
6458 | return 0; | 6890 | return 0; |
@@ -6463,8 +6895,16 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
6463 | { | 6895 | { |
6464 | if (info->user_ptr[0]) | 6896 | if (info->user_ptr[0]) |
6465 | cfg80211_unlock_rdev(info->user_ptr[0]); | 6897 | cfg80211_unlock_rdev(info->user_ptr[0]); |
6466 | if (info->user_ptr[1]) | 6898 | if (info->user_ptr[1]) { |
6467 | dev_put(info->user_ptr[1]); | 6899 | if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) { |
6900 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
6901 | |||
6902 | if (wdev->netdev) | ||
6903 | dev_put(wdev->netdev); | ||
6904 | } else { | ||
6905 | dev_put(info->user_ptr[1]); | ||
6906 | } | ||
6907 | } | ||
6468 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) | 6908 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) |
6469 | rtnl_unlock(); | 6909 | rtnl_unlock(); |
6470 | } | 6910 | } |
@@ -6491,7 +6931,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6491 | .dumpit = nl80211_dump_interface, | 6931 | .dumpit = nl80211_dump_interface, |
6492 | .policy = nl80211_policy, | 6932 | .policy = nl80211_policy, |
6493 | /* can be retrieved by unprivileged users */ | 6933 | /* can be retrieved by unprivileged users */ |
6494 | .internal_flags = NL80211_FLAG_NEED_NETDEV, | 6934 | .internal_flags = NL80211_FLAG_NEED_WDEV, |
6495 | }, | 6935 | }, |
6496 | { | 6936 | { |
6497 | .cmd = NL80211_CMD_SET_INTERFACE, | 6937 | .cmd = NL80211_CMD_SET_INTERFACE, |
@@ -6514,7 +6954,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6514 | .doit = nl80211_del_interface, | 6954 | .doit = nl80211_del_interface, |
6515 | .policy = nl80211_policy, | 6955 | .policy = nl80211_policy, |
6516 | .flags = GENL_ADMIN_PERM, | 6956 | .flags = GENL_ADMIN_PERM, |
6517 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 6957 | .internal_flags = NL80211_FLAG_NEED_WDEV | |
6518 | NL80211_FLAG_NEED_RTNL, | 6958 | NL80211_FLAG_NEED_RTNL, |
6519 | }, | 6959 | }, |
6520 | { | 6960 | { |
@@ -6685,7 +7125,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6685 | .doit = nl80211_trigger_scan, | 7125 | .doit = nl80211_trigger_scan, |
6686 | .policy = nl80211_policy, | 7126 | .policy = nl80211_policy, |
6687 | .flags = GENL_ADMIN_PERM, | 7127 | .flags = GENL_ADMIN_PERM, |
6688 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7128 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6689 | NL80211_FLAG_NEED_RTNL, | 7129 | NL80211_FLAG_NEED_RTNL, |
6690 | }, | 7130 | }, |
6691 | { | 7131 | { |
@@ -6826,7 +7266,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6826 | .doit = nl80211_remain_on_channel, | 7266 | .doit = nl80211_remain_on_channel, |
6827 | .policy = nl80211_policy, | 7267 | .policy = nl80211_policy, |
6828 | .flags = GENL_ADMIN_PERM, | 7268 | .flags = GENL_ADMIN_PERM, |
6829 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7269 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6830 | NL80211_FLAG_NEED_RTNL, | 7270 | NL80211_FLAG_NEED_RTNL, |
6831 | }, | 7271 | }, |
6832 | { | 7272 | { |
@@ -6834,7 +7274,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6834 | .doit = nl80211_cancel_remain_on_channel, | 7274 | .doit = nl80211_cancel_remain_on_channel, |
6835 | .policy = nl80211_policy, | 7275 | .policy = nl80211_policy, |
6836 | .flags = GENL_ADMIN_PERM, | 7276 | .flags = GENL_ADMIN_PERM, |
6837 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7277 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6838 | NL80211_FLAG_NEED_RTNL, | 7278 | NL80211_FLAG_NEED_RTNL, |
6839 | }, | 7279 | }, |
6840 | { | 7280 | { |
@@ -6850,7 +7290,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6850 | .doit = nl80211_register_mgmt, | 7290 | .doit = nl80211_register_mgmt, |
6851 | .policy = nl80211_policy, | 7291 | .policy = nl80211_policy, |
6852 | .flags = GENL_ADMIN_PERM, | 7292 | .flags = GENL_ADMIN_PERM, |
6853 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 7293 | .internal_flags = NL80211_FLAG_NEED_WDEV | |
6854 | NL80211_FLAG_NEED_RTNL, | 7294 | NL80211_FLAG_NEED_RTNL, |
6855 | }, | 7295 | }, |
6856 | { | 7296 | { |
@@ -6858,7 +7298,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6858 | .doit = nl80211_tx_mgmt, | 7298 | .doit = nl80211_tx_mgmt, |
6859 | .policy = nl80211_policy, | 7299 | .policy = nl80211_policy, |
6860 | .flags = GENL_ADMIN_PERM, | 7300 | .flags = GENL_ADMIN_PERM, |
6861 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7301 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6862 | NL80211_FLAG_NEED_RTNL, | 7302 | NL80211_FLAG_NEED_RTNL, |
6863 | }, | 7303 | }, |
6864 | { | 7304 | { |
@@ -6866,7 +7306,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6866 | .doit = nl80211_tx_mgmt_cancel_wait, | 7306 | .doit = nl80211_tx_mgmt_cancel_wait, |
6867 | .policy = nl80211_policy, | 7307 | .policy = nl80211_policy, |
6868 | .flags = GENL_ADMIN_PERM, | 7308 | .flags = GENL_ADMIN_PERM, |
6869 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7309 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6870 | NL80211_FLAG_NEED_RTNL, | 7310 | NL80211_FLAG_NEED_RTNL, |
6871 | }, | 7311 | }, |
6872 | { | 7312 | { |
@@ -6925,6 +7365,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6925 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7365 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
6926 | NL80211_FLAG_NEED_RTNL, | 7366 | NL80211_FLAG_NEED_RTNL, |
6927 | }, | 7367 | }, |
7368 | #ifdef CONFIG_PM | ||
6928 | { | 7369 | { |
6929 | .cmd = NL80211_CMD_GET_WOWLAN, | 7370 | .cmd = NL80211_CMD_GET_WOWLAN, |
6930 | .doit = nl80211_get_wowlan, | 7371 | .doit = nl80211_get_wowlan, |
@@ -6941,6 +7382,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6941 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 7382 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
6942 | NL80211_FLAG_NEED_RTNL, | 7383 | NL80211_FLAG_NEED_RTNL, |
6943 | }, | 7384 | }, |
7385 | #endif | ||
6944 | { | 7386 | { |
6945 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, | 7387 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, |
6946 | .doit = nl80211_set_rekey_data, | 7388 | .doit = nl80211_set_rekey_data, |
@@ -7075,7 +7517,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg, | |||
7075 | 7517 | ||
7076 | static int nl80211_send_scan_msg(struct sk_buff *msg, | 7518 | static int nl80211_send_scan_msg(struct sk_buff *msg, |
7077 | struct cfg80211_registered_device *rdev, | 7519 | struct cfg80211_registered_device *rdev, |
7078 | struct net_device *netdev, | 7520 | struct wireless_dev *wdev, |
7079 | u32 pid, u32 seq, int flags, | 7521 | u32 pid, u32 seq, int flags, |
7080 | u32 cmd) | 7522 | u32 cmd) |
7081 | { | 7523 | { |
@@ -7086,7 +7528,9 @@ static int nl80211_send_scan_msg(struct sk_buff *msg, | |||
7086 | return -1; | 7528 | return -1; |
7087 | 7529 | ||
7088 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 7530 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7089 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) | 7531 | (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
7532 | wdev->netdev->ifindex)) || | ||
7533 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
7090 | goto nla_put_failure; | 7534 | goto nla_put_failure; |
7091 | 7535 | ||
7092 | /* ignore errors and send incomplete event anyway */ | 7536 | /* ignore errors and send incomplete event anyway */ |
@@ -7123,15 +7567,15 @@ nl80211_send_sched_scan_msg(struct sk_buff *msg, | |||
7123 | } | 7567 | } |
7124 | 7568 | ||
7125 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | 7569 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, |
7126 | struct net_device *netdev) | 7570 | struct wireless_dev *wdev) |
7127 | { | 7571 | { |
7128 | struct sk_buff *msg; | 7572 | struct sk_buff *msg; |
7129 | 7573 | ||
7130 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 7574 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
7131 | if (!msg) | 7575 | if (!msg) |
7132 | return; | 7576 | return; |
7133 | 7577 | ||
7134 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7578 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7135 | NL80211_CMD_TRIGGER_SCAN) < 0) { | 7579 | NL80211_CMD_TRIGGER_SCAN) < 0) { |
7136 | nlmsg_free(msg); | 7580 | nlmsg_free(msg); |
7137 | return; | 7581 | return; |
@@ -7142,7 +7586,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | |||
7142 | } | 7586 | } |
7143 | 7587 | ||
7144 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | 7588 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, |
7145 | struct net_device *netdev) | 7589 | struct wireless_dev *wdev) |
7146 | { | 7590 | { |
7147 | struct sk_buff *msg; | 7591 | struct sk_buff *msg; |
7148 | 7592 | ||
@@ -7150,7 +7594,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
7150 | if (!msg) | 7594 | if (!msg) |
7151 | return; | 7595 | return; |
7152 | 7596 | ||
7153 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7597 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7154 | NL80211_CMD_NEW_SCAN_RESULTS) < 0) { | 7598 | NL80211_CMD_NEW_SCAN_RESULTS) < 0) { |
7155 | nlmsg_free(msg); | 7599 | nlmsg_free(msg); |
7156 | return; | 7600 | return; |
@@ -7161,7 +7605,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
7161 | } | 7605 | } |
7162 | 7606 | ||
7163 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 7607 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
7164 | struct net_device *netdev) | 7608 | struct wireless_dev *wdev) |
7165 | { | 7609 | { |
7166 | struct sk_buff *msg; | 7610 | struct sk_buff *msg; |
7167 | 7611 | ||
@@ -7169,7 +7613,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | |||
7169 | if (!msg) | 7613 | if (!msg) |
7170 | return; | 7614 | return; |
7171 | 7615 | ||
7172 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7616 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7173 | NL80211_CMD_SCAN_ABORTED) < 0) { | 7617 | NL80211_CMD_SCAN_ABORTED) < 0) { |
7174 | nlmsg_free(msg); | 7618 | nlmsg_free(msg); |
7175 | return; | 7619 | return; |
@@ -7203,7 +7647,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | |||
7203 | { | 7647 | { |
7204 | struct sk_buff *msg; | 7648 | struct sk_buff *msg; |
7205 | 7649 | ||
7206 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 7650 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
7207 | if (!msg) | 7651 | if (!msg) |
7208 | return; | 7652 | return; |
7209 | 7653 | ||
@@ -7419,7 +7863,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, | |||
7419 | struct sk_buff *msg; | 7863 | struct sk_buff *msg; |
7420 | void *hdr; | 7864 | void *hdr; |
7421 | 7865 | ||
7422 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 7866 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7423 | if (!msg) | 7867 | if (!msg) |
7424 | return; | 7868 | return; |
7425 | 7869 | ||
@@ -7459,7 +7903,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, | |||
7459 | struct sk_buff *msg; | 7903 | struct sk_buff *msg; |
7460 | void *hdr; | 7904 | void *hdr; |
7461 | 7905 | ||
7462 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 7906 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7463 | if (!msg) | 7907 | if (!msg) |
7464 | return; | 7908 | return; |
7465 | 7909 | ||
@@ -7497,7 +7941,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | |||
7497 | struct sk_buff *msg; | 7941 | struct sk_buff *msg; |
7498 | void *hdr; | 7942 | void *hdr; |
7499 | 7943 | ||
7500 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 7944 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
7501 | if (!msg) | 7945 | if (!msg) |
7502 | return; | 7946 | return; |
7503 | 7947 | ||
@@ -7692,7 +8136,7 @@ nla_put_failure: | |||
7692 | 8136 | ||
7693 | static void nl80211_send_remain_on_chan_event( | 8137 | static void nl80211_send_remain_on_chan_event( |
7694 | int cmd, struct cfg80211_registered_device *rdev, | 8138 | int cmd, struct cfg80211_registered_device *rdev, |
7695 | struct net_device *netdev, u64 cookie, | 8139 | struct wireless_dev *wdev, u64 cookie, |
7696 | struct ieee80211_channel *chan, | 8140 | struct ieee80211_channel *chan, |
7697 | enum nl80211_channel_type channel_type, | 8141 | enum nl80211_channel_type channel_type, |
7698 | unsigned int duration, gfp_t gfp) | 8142 | unsigned int duration, gfp_t gfp) |
@@ -7711,7 +8155,9 @@ static void nl80211_send_remain_on_chan_event( | |||
7711 | } | 8155 | } |
7712 | 8156 | ||
7713 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8157 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7714 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8158 | (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
8159 | wdev->netdev->ifindex)) || | ||
8160 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || | ||
7715 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || | 8161 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || |
7716 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || | 8162 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || |
7717 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) | 8163 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) |
@@ -7733,23 +8179,24 @@ static void nl80211_send_remain_on_chan_event( | |||
7733 | } | 8179 | } |
7734 | 8180 | ||
7735 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | 8181 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, |
7736 | struct net_device *netdev, u64 cookie, | 8182 | struct wireless_dev *wdev, u64 cookie, |
7737 | struct ieee80211_channel *chan, | 8183 | struct ieee80211_channel *chan, |
7738 | enum nl80211_channel_type channel_type, | 8184 | enum nl80211_channel_type channel_type, |
7739 | unsigned int duration, gfp_t gfp) | 8185 | unsigned int duration, gfp_t gfp) |
7740 | { | 8186 | { |
7741 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, | 8187 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, |
7742 | rdev, netdev, cookie, chan, | 8188 | rdev, wdev, cookie, chan, |
7743 | channel_type, duration, gfp); | 8189 | channel_type, duration, gfp); |
7744 | } | 8190 | } |
7745 | 8191 | ||
7746 | void nl80211_send_remain_on_channel_cancel( | 8192 | void nl80211_send_remain_on_channel_cancel( |
7747 | struct cfg80211_registered_device *rdev, struct net_device *netdev, | 8193 | struct cfg80211_registered_device *rdev, |
8194 | struct wireless_dev *wdev, | ||
7748 | u64 cookie, struct ieee80211_channel *chan, | 8195 | u64 cookie, struct ieee80211_channel *chan, |
7749 | enum nl80211_channel_type channel_type, gfp_t gfp) | 8196 | enum nl80211_channel_type channel_type, gfp_t gfp) |
7750 | { | 8197 | { |
7751 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 8198 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
7752 | rdev, netdev, cookie, chan, | 8199 | rdev, wdev, cookie, chan, |
7753 | channel_type, 0, gfp); | 8200 | channel_type, 0, gfp); |
7754 | } | 8201 | } |
7755 | 8202 | ||
@@ -7759,7 +8206,7 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
7759 | { | 8206 | { |
7760 | struct sk_buff *msg; | 8207 | struct sk_buff *msg; |
7761 | 8208 | ||
7762 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8209 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7763 | if (!msg) | 8210 | if (!msg) |
7764 | return; | 8211 | return; |
7765 | 8212 | ||
@@ -7780,7 +8227,7 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
7780 | struct sk_buff *msg; | 8227 | struct sk_buff *msg; |
7781 | void *hdr; | 8228 | void *hdr; |
7782 | 8229 | ||
7783 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8230 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7784 | if (!msg) | 8231 | if (!msg) |
7785 | return; | 8232 | return; |
7786 | 8233 | ||
@@ -7863,10 +8310,11 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev, | |||
7863 | } | 8310 | } |
7864 | 8311 | ||
7865 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 8312 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
7866 | struct net_device *netdev, u32 nlpid, | 8313 | struct wireless_dev *wdev, u32 nlpid, |
7867 | int freq, int sig_dbm, | 8314 | int freq, int sig_dbm, |
7868 | const u8 *buf, size_t len, gfp_t gfp) | 8315 | const u8 *buf, size_t len, gfp_t gfp) |
7869 | { | 8316 | { |
8317 | struct net_device *netdev = wdev->netdev; | ||
7870 | struct sk_buff *msg; | 8318 | struct sk_buff *msg; |
7871 | void *hdr; | 8319 | void *hdr; |
7872 | 8320 | ||
@@ -7881,7 +8329,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
7881 | } | 8329 | } |
7882 | 8330 | ||
7883 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8331 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7884 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8332 | (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
8333 | netdev->ifindex)) || | ||
7885 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || | 8334 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || |
7886 | (sig_dbm && | 8335 | (sig_dbm && |
7887 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || | 8336 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || |
@@ -7899,10 +8348,11 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
7899 | } | 8348 | } |
7900 | 8349 | ||
7901 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | 8350 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
7902 | struct net_device *netdev, u64 cookie, | 8351 | struct wireless_dev *wdev, u64 cookie, |
7903 | const u8 *buf, size_t len, bool ack, | 8352 | const u8 *buf, size_t len, bool ack, |
7904 | gfp_t gfp) | 8353 | gfp_t gfp) |
7905 | { | 8354 | { |
8355 | struct net_device *netdev = wdev->netdev; | ||
7906 | struct sk_buff *msg; | 8356 | struct sk_buff *msg; |
7907 | void *hdr; | 8357 | void *hdr; |
7908 | 8358 | ||
@@ -7917,7 +8367,8 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | |||
7917 | } | 8367 | } |
7918 | 8368 | ||
7919 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8369 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7920 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8370 | (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
8371 | netdev->ifindex)) || | ||
7921 | nla_put(msg, NL80211_ATTR_FRAME, len, buf) || | 8372 | nla_put(msg, NL80211_ATTR_FRAME, len, buf) || |
7922 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || | 8373 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || |
7923 | (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) | 8374 | (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) |
@@ -7943,7 +8394,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
7943 | struct nlattr *pinfoattr; | 8394 | struct nlattr *pinfoattr; |
7944 | void *hdr; | 8395 | void *hdr; |
7945 | 8396 | ||
7946 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8397 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7947 | if (!msg) | 8398 | if (!msg) |
7948 | return; | 8399 | return; |
7949 | 8400 | ||
@@ -7986,7 +8437,7 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | |||
7986 | struct nlattr *rekey_attr; | 8437 | struct nlattr *rekey_attr; |
7987 | void *hdr; | 8438 | void *hdr; |
7988 | 8439 | ||
7989 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8440 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7990 | if (!msg) | 8441 | if (!msg) |
7991 | return; | 8442 | return; |
7992 | 8443 | ||
@@ -8030,7 +8481,7 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | |||
8030 | struct nlattr *attr; | 8481 | struct nlattr *attr; |
8031 | void *hdr; | 8482 | void *hdr; |
8032 | 8483 | ||
8033 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8484 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8034 | if (!msg) | 8485 | if (!msg) |
8035 | return; | 8486 | return; |
8036 | 8487 | ||
@@ -8074,7 +8525,7 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
8074 | struct sk_buff *msg; | 8525 | struct sk_buff *msg; |
8075 | void *hdr; | 8526 | void *hdr; |
8076 | 8527 | ||
8077 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8528 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8078 | if (!msg) | 8529 | if (!msg) |
8079 | return; | 8530 | return; |
8080 | 8531 | ||
@@ -8101,6 +8552,56 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
8101 | } | 8552 | } |
8102 | 8553 | ||
8103 | void | 8554 | void |
8555 | nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | ||
8556 | struct net_device *netdev, const u8 *peer, | ||
8557 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp) | ||
8558 | { | ||
8559 | struct sk_buff *msg; | ||
8560 | struct nlattr *pinfoattr; | ||
8561 | void *hdr; | ||
8562 | |||
8563 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
8564 | if (!msg) | ||
8565 | return; | ||
8566 | |||
8567 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); | ||
8568 | if (!hdr) { | ||
8569 | nlmsg_free(msg); | ||
8570 | return; | ||
8571 | } | ||
8572 | |||
8573 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
8574 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | ||
8575 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | ||
8576 | goto nla_put_failure; | ||
8577 | |||
8578 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | ||
8579 | if (!pinfoattr) | ||
8580 | goto nla_put_failure; | ||
8581 | |||
8582 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets)) | ||
8583 | goto nla_put_failure; | ||
8584 | |||
8585 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate)) | ||
8586 | goto nla_put_failure; | ||
8587 | |||
8588 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl)) | ||
8589 | goto nla_put_failure; | ||
8590 | |||
8591 | nla_nest_end(msg, pinfoattr); | ||
8592 | |||
8593 | genlmsg_end(msg, hdr); | ||
8594 | |||
8595 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
8596 | nl80211_mlme_mcgrp.id, gfp); | ||
8597 | return; | ||
8598 | |||
8599 | nla_put_failure: | ||
8600 | genlmsg_cancel(msg, hdr); | ||
8601 | nlmsg_free(msg); | ||
8602 | } | ||
8603 | |||
8604 | void | ||
8104 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 8605 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
8105 | struct net_device *netdev, const u8 *peer, | 8606 | struct net_device *netdev, const u8 *peer, |
8106 | u32 num_packets, gfp_t gfp) | 8607 | u32 num_packets, gfp_t gfp) |
@@ -8109,7 +8610,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
8109 | struct nlattr *pinfoattr; | 8610 | struct nlattr *pinfoattr; |
8110 | void *hdr; | 8611 | void *hdr; |
8111 | 8612 | ||
8112 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8613 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8113 | if (!msg) | 8614 | if (!msg) |
8114 | return; | 8615 | return; |
8115 | 8616 | ||
@@ -8153,7 +8654,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | |||
8153 | void *hdr; | 8654 | void *hdr; |
8154 | int err; | 8655 | int err; |
8155 | 8656 | ||
8156 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8657 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8157 | if (!msg) | 8658 | if (!msg) |
8158 | return; | 8659 | return; |
8159 | 8660 | ||
@@ -8241,7 +8742,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
8241 | rcu_read_lock(); | 8742 | rcu_read_lock(); |
8242 | 8743 | ||
8243 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { | 8744 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
8244 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) | 8745 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) |
8245 | cfg80211_mlme_unregister_socket(wdev, notify->pid); | 8746 | cfg80211_mlme_unregister_socket(wdev, notify->pid); |
8246 | if (rdev->ap_beacons_nlpid == notify->pid) | 8747 | if (rdev->ap_beacons_nlpid == notify->pid) |
8247 | rdev->ap_beacons_nlpid = 0; | 8748 | rdev->ap_beacons_nlpid = 0; |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 01a1122c3b33..9f2616fffb40 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -7,11 +7,11 @@ int nl80211_init(void); | |||
7 | void nl80211_exit(void); | 7 | void nl80211_exit(void); |
8 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); | 8 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); |
9 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | 9 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, |
10 | struct net_device *netdev); | 10 | struct wireless_dev *wdev); |
11 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | 11 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, |
12 | struct net_device *netdev); | 12 | struct wireless_dev *wdev); |
13 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 13 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
14 | struct net_device *netdev); | 14 | struct wireless_dev *wdev); |
15 | void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | 15 | void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, |
16 | struct net_device *netdev, u32 cmd); | 16 | struct net_device *netdev, u32 cmd); |
17 | void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, | 17 | void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, |
@@ -74,13 +74,13 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
74 | gfp_t gfp); | 74 | gfp_t gfp); |
75 | 75 | ||
76 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | 76 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, |
77 | struct net_device *netdev, | 77 | struct wireless_dev *wdev, u64 cookie, |
78 | u64 cookie, | ||
79 | struct ieee80211_channel *chan, | 78 | struct ieee80211_channel *chan, |
80 | enum nl80211_channel_type channel_type, | 79 | enum nl80211_channel_type channel_type, |
81 | unsigned int duration, gfp_t gfp); | 80 | unsigned int duration, gfp_t gfp); |
82 | void nl80211_send_remain_on_channel_cancel( | 81 | void nl80211_send_remain_on_channel_cancel( |
83 | struct cfg80211_registered_device *rdev, struct net_device *netdev, | 82 | struct cfg80211_registered_device *rdev, |
83 | struct wireless_dev *wdev, | ||
84 | u64 cookie, struct ieee80211_channel *chan, | 84 | u64 cookie, struct ieee80211_channel *chan, |
85 | enum nl80211_channel_type channel_type, gfp_t gfp); | 85 | enum nl80211_channel_type channel_type, gfp_t gfp); |
86 | 86 | ||
@@ -92,11 +92,11 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
92 | gfp_t gfp); | 92 | gfp_t gfp); |
93 | 93 | ||
94 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 94 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
95 | struct net_device *netdev, u32 nlpid, | 95 | struct wireless_dev *wdev, u32 nlpid, |
96 | int freq, int sig_dbm, | 96 | int freq, int sig_dbm, |
97 | const u8 *buf, size_t len, gfp_t gfp); | 97 | const u8 *buf, size_t len, gfp_t gfp); |
98 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | 98 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
99 | struct net_device *netdev, u64 cookie, | 99 | struct wireless_dev *wdev, u64 cookie, |
100 | const u8 *buf, size_t len, bool ack, | 100 | const u8 *buf, size_t len, bool ack, |
101 | gfp_t gfp); | 101 | gfp_t gfp); |
102 | 102 | ||
@@ -110,6 +110,11 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
110 | struct net_device *netdev, const u8 *peer, | 110 | struct net_device *netdev, const u8 *peer, |
111 | u32 num_packets, gfp_t gfp); | 111 | u32 num_packets, gfp_t gfp); |
112 | 112 | ||
113 | void | ||
114 | nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | ||
115 | struct net_device *netdev, const u8 *peer, | ||
116 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); | ||
117 | |||
113 | void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | 118 | void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, |
114 | struct net_device *netdev, const u8 *bssid, | 119 | struct net_device *netdev, const u8 *bssid, |
115 | const u8 *replay_ctr, gfp_t gfp); | 120 | const u8 *replay_ctr, gfp_t gfp); |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 460af03d8149..a9175fedeb59 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -97,9 +97,16 @@ const struct ieee80211_regdomain *cfg80211_regdomain; | |||
97 | * - cfg80211_world_regdom | 97 | * - cfg80211_world_regdom |
98 | * - cfg80211_regdom | 98 | * - cfg80211_regdom |
99 | * - last_request | 99 | * - last_request |
100 | * - reg_num_devs_support_basehint | ||
100 | */ | 101 | */ |
101 | static DEFINE_MUTEX(reg_mutex); | 102 | static DEFINE_MUTEX(reg_mutex); |
102 | 103 | ||
104 | /* | ||
105 | * Number of devices that registered to the core | ||
106 | * that support cellular base station regulatory hints | ||
107 | */ | ||
108 | static int reg_num_devs_support_basehint; | ||
109 | |||
103 | static inline void assert_reg_lock(void) | 110 | static inline void assert_reg_lock(void) |
104 | { | 111 | { |
105 | lockdep_assert_held(®_mutex); | 112 | lockdep_assert_held(®_mutex); |
@@ -129,7 +136,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); | |||
129 | 136 | ||
130 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | 137 | /* We keep a static world regulatory domain in case of the absence of CRDA */ |
131 | static const struct ieee80211_regdomain world_regdom = { | 138 | static const struct ieee80211_regdomain world_regdom = { |
132 | .n_reg_rules = 5, | 139 | .n_reg_rules = 6, |
133 | .alpha2 = "00", | 140 | .alpha2 = "00", |
134 | .reg_rules = { | 141 | .reg_rules = { |
135 | /* IEEE 802.11b/g, channels 1..11 */ | 142 | /* IEEE 802.11b/g, channels 1..11 */ |
@@ -156,6 +163,9 @@ static const struct ieee80211_regdomain world_regdom = { | |||
156 | REG_RULE(5745-10, 5825+10, 40, 6, 20, | 163 | REG_RULE(5745-10, 5825+10, 40, 6, 20, |
157 | NL80211_RRF_PASSIVE_SCAN | | 164 | NL80211_RRF_PASSIVE_SCAN | |
158 | NL80211_RRF_NO_IBSS), | 165 | NL80211_RRF_NO_IBSS), |
166 | |||
167 | /* IEEE 802.11ad (60gHz), channels 1..3 */ | ||
168 | REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), | ||
159 | } | 169 | } |
160 | }; | 170 | }; |
161 | 171 | ||
@@ -922,6 +932,61 @@ static void handle_band(struct wiphy *wiphy, | |||
922 | handle_channel(wiphy, initiator, band, i); | 932 | handle_channel(wiphy, initiator, band, i); |
923 | } | 933 | } |
924 | 934 | ||
935 | static bool reg_request_cell_base(struct regulatory_request *request) | ||
936 | { | ||
937 | if (request->initiator != NL80211_REGDOM_SET_BY_USER) | ||
938 | return false; | ||
939 | if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE) | ||
940 | return false; | ||
941 | return true; | ||
942 | } | ||
943 | |||
944 | bool reg_last_request_cell_base(void) | ||
945 | { | ||
946 | bool val; | ||
947 | assert_cfg80211_lock(); | ||
948 | |||
949 | mutex_lock(®_mutex); | ||
950 | val = reg_request_cell_base(last_request); | ||
951 | mutex_unlock(®_mutex); | ||
952 | return val; | ||
953 | } | ||
954 | |||
955 | #ifdef CONFIG_CFG80211_CERTIFICATION_ONUS | ||
956 | |||
957 | /* Core specific check */ | ||
958 | static int reg_ignore_cell_hint(struct regulatory_request *pending_request) | ||
959 | { | ||
960 | if (!reg_num_devs_support_basehint) | ||
961 | return -EOPNOTSUPP; | ||
962 | |||
963 | if (reg_request_cell_base(last_request)) { | ||
964 | if (!regdom_changes(pending_request->alpha2)) | ||
965 | return -EALREADY; | ||
966 | return 0; | ||
967 | } | ||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | /* Device specific check */ | ||
972 | static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) | ||
973 | { | ||
974 | if (!(wiphy->features & NL80211_FEATURE_CELL_BASE_REG_HINTS)) | ||
975 | return true; | ||
976 | return false; | ||
977 | } | ||
978 | #else | ||
979 | static int reg_ignore_cell_hint(struct regulatory_request *pending_request) | ||
980 | { | ||
981 | return -EOPNOTSUPP; | ||
982 | } | ||
983 | static int reg_dev_ignore_cell_hint(struct wiphy *wiphy) | ||
984 | { | ||
985 | return true; | ||
986 | } | ||
987 | #endif | ||
988 | |||
989 | |||
925 | static bool ignore_reg_update(struct wiphy *wiphy, | 990 | static bool ignore_reg_update(struct wiphy *wiphy, |
926 | enum nl80211_reg_initiator initiator) | 991 | enum nl80211_reg_initiator initiator) |
927 | { | 992 | { |
@@ -955,6 +1020,9 @@ static bool ignore_reg_update(struct wiphy *wiphy, | |||
955 | return true; | 1020 | return true; |
956 | } | 1021 | } |
957 | 1022 | ||
1023 | if (reg_request_cell_base(last_request)) | ||
1024 | return reg_dev_ignore_cell_hint(wiphy); | ||
1025 | |||
958 | return false; | 1026 | return false; |
959 | } | 1027 | } |
960 | 1028 | ||
@@ -1180,14 +1248,6 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, | |||
1180 | wiphy->reg_notifier(wiphy, last_request); | 1248 | wiphy->reg_notifier(wiphy, last_request); |
1181 | } | 1249 | } |
1182 | 1250 | ||
1183 | void regulatory_update(struct wiphy *wiphy, | ||
1184 | enum nl80211_reg_initiator setby) | ||
1185 | { | ||
1186 | mutex_lock(®_mutex); | ||
1187 | wiphy_update_regulatory(wiphy, setby); | ||
1188 | mutex_unlock(®_mutex); | ||
1189 | } | ||
1190 | |||
1191 | static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) | 1251 | static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) |
1192 | { | 1252 | { |
1193 | struct cfg80211_registered_device *rdev; | 1253 | struct cfg80211_registered_device *rdev; |
@@ -1318,6 +1378,13 @@ static int ignore_request(struct wiphy *wiphy, | |||
1318 | return 0; | 1378 | return 0; |
1319 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | 1379 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: |
1320 | 1380 | ||
1381 | if (reg_request_cell_base(last_request)) { | ||
1382 | /* Trust a Cell base station over the AP's country IE */ | ||
1383 | if (regdom_changes(pending_request->alpha2)) | ||
1384 | return -EOPNOTSUPP; | ||
1385 | return -EALREADY; | ||
1386 | } | ||
1387 | |||
1321 | last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | 1388 | last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); |
1322 | 1389 | ||
1323 | if (unlikely(!is_an_alpha2(pending_request->alpha2))) | 1390 | if (unlikely(!is_an_alpha2(pending_request->alpha2))) |
@@ -1362,6 +1429,12 @@ static int ignore_request(struct wiphy *wiphy, | |||
1362 | 1429 | ||
1363 | return REG_INTERSECT; | 1430 | return REG_INTERSECT; |
1364 | case NL80211_REGDOM_SET_BY_USER: | 1431 | case NL80211_REGDOM_SET_BY_USER: |
1432 | if (reg_request_cell_base(pending_request)) | ||
1433 | return reg_ignore_cell_hint(pending_request); | ||
1434 | |||
1435 | if (reg_request_cell_base(last_request)) | ||
1436 | return -EOPNOTSUPP; | ||
1437 | |||
1365 | if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) | 1438 | if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) |
1366 | return REG_INTERSECT; | 1439 | return REG_INTERSECT; |
1367 | /* | 1440 | /* |
@@ -1651,7 +1724,8 @@ static int regulatory_hint_core(const char *alpha2) | |||
1651 | } | 1724 | } |
1652 | 1725 | ||
1653 | /* User hints */ | 1726 | /* User hints */ |
1654 | int regulatory_hint_user(const char *alpha2) | 1727 | int regulatory_hint_user(const char *alpha2, |
1728 | enum nl80211_user_reg_hint_type user_reg_hint_type) | ||
1655 | { | 1729 | { |
1656 | struct regulatory_request *request; | 1730 | struct regulatory_request *request; |
1657 | 1731 | ||
@@ -1665,6 +1739,7 @@ int regulatory_hint_user(const char *alpha2) | |||
1665 | request->alpha2[0] = alpha2[0]; | 1739 | request->alpha2[0] = alpha2[0]; |
1666 | request->alpha2[1] = alpha2[1]; | 1740 | request->alpha2[1] = alpha2[1]; |
1667 | request->initiator = NL80211_REGDOM_SET_BY_USER; | 1741 | request->initiator = NL80211_REGDOM_SET_BY_USER; |
1742 | request->user_reg_hint_type = user_reg_hint_type; | ||
1668 | 1743 | ||
1669 | queue_regulatory_request(request); | 1744 | queue_regulatory_request(request); |
1670 | 1745 | ||
@@ -1917,7 +1992,7 @@ static void restore_regulatory_settings(bool reset_user) | |||
1917 | * settings, user regulatory settings takes precedence. | 1992 | * settings, user regulatory settings takes precedence. |
1918 | */ | 1993 | */ |
1919 | if (is_an_alpha2(alpha2)) | 1994 | if (is_an_alpha2(alpha2)) |
1920 | regulatory_hint_user(user_alpha2); | 1995 | regulatory_hint_user(user_alpha2, NL80211_USER_REG_HINT_USER); |
1921 | 1996 | ||
1922 | if (list_empty(&tmp_reg_req_list)) | 1997 | if (list_empty(&tmp_reg_req_list)) |
1923 | return; | 1998 | return; |
@@ -2092,9 +2167,16 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
2092 | else { | 2167 | else { |
2093 | if (is_unknown_alpha2(rd->alpha2)) | 2168 | if (is_unknown_alpha2(rd->alpha2)) |
2094 | pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n"); | 2169 | pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n"); |
2095 | else | 2170 | else { |
2096 | pr_info("Regulatory domain changed to country: %c%c\n", | 2171 | if (reg_request_cell_base(last_request)) |
2097 | rd->alpha2[0], rd->alpha2[1]); | 2172 | pr_info("Regulatory domain changed " |
2173 | "to country: %c%c by Cell Station\n", | ||
2174 | rd->alpha2[0], rd->alpha2[1]); | ||
2175 | else | ||
2176 | pr_info("Regulatory domain changed " | ||
2177 | "to country: %c%c\n", | ||
2178 | rd->alpha2[0], rd->alpha2[1]); | ||
2179 | } | ||
2098 | } | 2180 | } |
2099 | print_dfs_region(rd->dfs_region); | 2181 | print_dfs_region(rd->dfs_region); |
2100 | print_rd_rules(rd); | 2182 | print_rd_rules(rd); |
@@ -2139,7 +2221,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2139 | * checking if the alpha2 changes if CRDA was already called | 2221 | * checking if the alpha2 changes if CRDA was already called |
2140 | */ | 2222 | */ |
2141 | if (!regdom_changes(rd->alpha2)) | 2223 | if (!regdom_changes(rd->alpha2)) |
2142 | return -EINVAL; | 2224 | return -EALREADY; |
2143 | } | 2225 | } |
2144 | 2226 | ||
2145 | /* | 2227 | /* |
@@ -2259,6 +2341,9 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2259 | /* Note that this doesn't update the wiphys, this is done below */ | 2341 | /* Note that this doesn't update the wiphys, this is done below */ |
2260 | r = __set_regdom(rd); | 2342 | r = __set_regdom(rd); |
2261 | if (r) { | 2343 | if (r) { |
2344 | if (r == -EALREADY) | ||
2345 | reg_set_request_processed(); | ||
2346 | |||
2262 | kfree(rd); | 2347 | kfree(rd); |
2263 | mutex_unlock(®_mutex); | 2348 | mutex_unlock(®_mutex); |
2264 | return r; | 2349 | return r; |
@@ -2301,8 +2386,22 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
2301 | } | 2386 | } |
2302 | #endif /* CONFIG_HOTPLUG */ | 2387 | #endif /* CONFIG_HOTPLUG */ |
2303 | 2388 | ||
2389 | void wiphy_regulatory_register(struct wiphy *wiphy) | ||
2390 | { | ||
2391 | assert_cfg80211_lock(); | ||
2392 | |||
2393 | mutex_lock(®_mutex); | ||
2394 | |||
2395 | if (!reg_dev_ignore_cell_hint(wiphy)) | ||
2396 | reg_num_devs_support_basehint++; | ||
2397 | |||
2398 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); | ||
2399 | |||
2400 | mutex_unlock(®_mutex); | ||
2401 | } | ||
2402 | |||
2304 | /* Caller must hold cfg80211_mutex */ | 2403 | /* Caller must hold cfg80211_mutex */ |
2305 | void reg_device_remove(struct wiphy *wiphy) | 2404 | void wiphy_regulatory_deregister(struct wiphy *wiphy) |
2306 | { | 2405 | { |
2307 | struct wiphy *request_wiphy = NULL; | 2406 | struct wiphy *request_wiphy = NULL; |
2308 | 2407 | ||
@@ -2310,6 +2409,9 @@ void reg_device_remove(struct wiphy *wiphy) | |||
2310 | 2409 | ||
2311 | mutex_lock(®_mutex); | 2410 | mutex_lock(®_mutex); |
2312 | 2411 | ||
2412 | if (!reg_dev_ignore_cell_hint(wiphy)) | ||
2413 | reg_num_devs_support_basehint--; | ||
2414 | |||
2313 | kfree(wiphy->regd); | 2415 | kfree(wiphy->regd); |
2314 | 2416 | ||
2315 | if (last_request) | 2417 | if (last_request) |
@@ -2375,7 +2477,8 @@ int __init regulatory_init(void) | |||
2375 | * as a user hint. | 2477 | * as a user hint. |
2376 | */ | 2478 | */ |
2377 | if (!is_world_regdom(ieee80211_regdom)) | 2479 | if (!is_world_regdom(ieee80211_regdom)) |
2378 | regulatory_hint_user(ieee80211_regdom); | 2480 | regulatory_hint_user(ieee80211_regdom, |
2481 | NL80211_USER_REG_HINT_USER); | ||
2379 | 2482 | ||
2380 | return 0; | 2483 | return 0; |
2381 | } | 2484 | } |
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index e2aaaf525a22..f023c8a31c60 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -22,17 +22,19 @@ bool is_world_regdom(const char *alpha2); | |||
22 | bool reg_is_valid_request(const char *alpha2); | 22 | bool reg_is_valid_request(const char *alpha2); |
23 | bool reg_supported_dfs_region(u8 dfs_region); | 23 | bool reg_supported_dfs_region(u8 dfs_region); |
24 | 24 | ||
25 | int regulatory_hint_user(const char *alpha2); | 25 | int regulatory_hint_user(const char *alpha2, |
26 | enum nl80211_user_reg_hint_type user_reg_hint_type); | ||
26 | 27 | ||
27 | int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env); | 28 | int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env); |
28 | void reg_device_remove(struct wiphy *wiphy); | 29 | void wiphy_regulatory_register(struct wiphy *wiphy); |
30 | void wiphy_regulatory_deregister(struct wiphy *wiphy); | ||
29 | 31 | ||
30 | int __init regulatory_init(void); | 32 | int __init regulatory_init(void); |
31 | void regulatory_exit(void); | 33 | void regulatory_exit(void); |
32 | 34 | ||
33 | int set_regdom(const struct ieee80211_regdomain *rd); | 35 | int set_regdom(const struct ieee80211_regdomain *rd); |
34 | 36 | ||
35 | void regulatory_update(struct wiphy *wiphy, enum nl80211_reg_initiator setby); | 37 | bool reg_last_request_cell_base(void); |
36 | 38 | ||
37 | /** | 39 | /** |
38 | * regulatory_hint_found_beacon - hints a beacon was found on a channel | 40 | * regulatory_hint_found_beacon - hints a beacon was found on a channel |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index af2b1caa37fa..848523a2b22f 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -23,7 +23,7 @@ | |||
23 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) | 23 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) |
24 | { | 24 | { |
25 | struct cfg80211_scan_request *request; | 25 | struct cfg80211_scan_request *request; |
26 | struct net_device *dev; | 26 | struct wireless_dev *wdev; |
27 | #ifdef CONFIG_CFG80211_WEXT | 27 | #ifdef CONFIG_CFG80211_WEXT |
28 | union iwreq_data wrqu; | 28 | union iwreq_data wrqu; |
29 | #endif | 29 | #endif |
@@ -35,29 +35,31 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) | |||
35 | if (!request) | 35 | if (!request) |
36 | return; | 36 | return; |
37 | 37 | ||
38 | dev = request->dev; | 38 | wdev = request->wdev; |
39 | 39 | ||
40 | /* | 40 | /* |
41 | * This must be before sending the other events! | 41 | * This must be before sending the other events! |
42 | * Otherwise, wpa_supplicant gets completely confused with | 42 | * Otherwise, wpa_supplicant gets completely confused with |
43 | * wext events. | 43 | * wext events. |
44 | */ | 44 | */ |
45 | cfg80211_sme_scan_done(dev); | 45 | if (wdev->netdev) |
46 | cfg80211_sme_scan_done(wdev->netdev); | ||
46 | 47 | ||
47 | if (request->aborted) | 48 | if (request->aborted) |
48 | nl80211_send_scan_aborted(rdev, dev); | 49 | nl80211_send_scan_aborted(rdev, wdev); |
49 | else | 50 | else |
50 | nl80211_send_scan_done(rdev, dev); | 51 | nl80211_send_scan_done(rdev, wdev); |
51 | 52 | ||
52 | #ifdef CONFIG_CFG80211_WEXT | 53 | #ifdef CONFIG_CFG80211_WEXT |
53 | if (!request->aborted) { | 54 | if (wdev->netdev && !request->aborted) { |
54 | memset(&wrqu, 0, sizeof(wrqu)); | 55 | memset(&wrqu, 0, sizeof(wrqu)); |
55 | 56 | ||
56 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); | 57 | wireless_send_event(wdev->netdev, SIOCGIWSCAN, &wrqu, NULL); |
57 | } | 58 | } |
58 | #endif | 59 | #endif |
59 | 60 | ||
60 | dev_put(dev); | 61 | if (wdev->netdev) |
62 | dev_put(wdev->netdev); | ||
61 | 63 | ||
62 | rdev->scan_req = NULL; | 64 | rdev->scan_req = NULL; |
63 | 65 | ||
@@ -955,7 +957,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
955 | } | 957 | } |
956 | 958 | ||
957 | creq->wiphy = wiphy; | 959 | creq->wiphy = wiphy; |
958 | creq->dev = dev; | 960 | creq->wdev = dev->ieee80211_ptr; |
959 | /* SSIDs come after channels */ | 961 | /* SSIDs come after channels */ |
960 | creq->ssids = (void *)&creq->channels[n_channels]; | 962 | creq->ssids = (void *)&creq->channels[n_channels]; |
961 | creq->n_channels = n_channels; | 963 | creq->n_channels = n_channels; |
@@ -1024,12 +1026,12 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
1024 | creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; | 1026 | creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; |
1025 | 1027 | ||
1026 | rdev->scan_req = creq; | 1028 | rdev->scan_req = creq; |
1027 | err = rdev->ops->scan(wiphy, dev, creq); | 1029 | err = rdev->ops->scan(wiphy, creq); |
1028 | if (err) { | 1030 | if (err) { |
1029 | rdev->scan_req = NULL; | 1031 | rdev->scan_req = NULL; |
1030 | /* creq will be freed below */ | 1032 | /* creq will be freed below */ |
1031 | } else { | 1033 | } else { |
1032 | nl80211_send_scan_start(rdev, dev); | 1034 | nl80211_send_scan_start(rdev, dev->ieee80211_ptr); |
1033 | /* creq now owned by driver */ | 1035 | /* creq now owned by driver */ |
1034 | creq = NULL; | 1036 | creq = NULL; |
1035 | dev_hold(dev); | 1037 | dev_hold(dev); |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f7e937ff8978..6f39cb808302 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -51,7 +51,7 @@ static bool cfg80211_is_all_idle(void) | |||
51 | */ | 51 | */ |
52 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 52 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
53 | cfg80211_lock_rdev(rdev); | 53 | cfg80211_lock_rdev(rdev); |
54 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 54 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
55 | wdev_lock(wdev); | 55 | wdev_lock(wdev); |
56 | if (wdev->sme_state != CFG80211_SME_IDLE) | 56 | if (wdev->sme_state != CFG80211_SME_IDLE) |
57 | is_all_idle = false; | 57 | is_all_idle = false; |
@@ -136,15 +136,15 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
136 | wdev->conn->params.ssid_len); | 136 | wdev->conn->params.ssid_len); |
137 | request->ssids[0].ssid_len = wdev->conn->params.ssid_len; | 137 | request->ssids[0].ssid_len = wdev->conn->params.ssid_len; |
138 | 138 | ||
139 | request->dev = wdev->netdev; | 139 | request->wdev = wdev; |
140 | request->wiphy = &rdev->wiphy; | 140 | request->wiphy = &rdev->wiphy; |
141 | 141 | ||
142 | rdev->scan_req = request; | 142 | rdev->scan_req = request; |
143 | 143 | ||
144 | err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request); | 144 | err = rdev->ops->scan(wdev->wiphy, request); |
145 | if (!err) { | 145 | if (!err) { |
146 | wdev->conn->state = CFG80211_CONN_SCANNING; | 146 | wdev->conn->state = CFG80211_CONN_SCANNING; |
147 | nl80211_send_scan_start(rdev, wdev->netdev); | 147 | nl80211_send_scan_start(rdev, wdev); |
148 | dev_hold(wdev->netdev); | 148 | dev_hold(wdev->netdev); |
149 | } else { | 149 | } else { |
150 | rdev->scan_req = NULL; | 150 | rdev->scan_req = NULL; |
@@ -221,7 +221,7 @@ void cfg80211_conn_work(struct work_struct *work) | |||
221 | cfg80211_lock_rdev(rdev); | 221 | cfg80211_lock_rdev(rdev); |
222 | mutex_lock(&rdev->devlist_mtx); | 222 | mutex_lock(&rdev->devlist_mtx); |
223 | 223 | ||
224 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 224 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
225 | wdev_lock(wdev); | 225 | wdev_lock(wdev); |
226 | if (!netif_running(wdev->netdev)) { | 226 | if (!netif_running(wdev->netdev)) { |
227 | wdev_unlock(wdev); | 227 | wdev_unlock(wdev); |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 316cfd00914f..26f8cd30f712 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -35,19 +35,29 @@ int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band) | |||
35 | { | 35 | { |
36 | /* see 802.11 17.3.8.3.2 and Annex J | 36 | /* see 802.11 17.3.8.3.2 and Annex J |
37 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ | 37 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ |
38 | if (band == IEEE80211_BAND_5GHZ) { | 38 | if (chan <= 0) |
39 | if (chan >= 182 && chan <= 196) | 39 | return 0; /* not supported */ |
40 | return 4000 + chan * 5; | 40 | switch (band) { |
41 | else | 41 | case IEEE80211_BAND_2GHZ: |
42 | return 5000 + chan * 5; | ||
43 | } else { /* IEEE80211_BAND_2GHZ */ | ||
44 | if (chan == 14) | 42 | if (chan == 14) |
45 | return 2484; | 43 | return 2484; |
46 | else if (chan < 14) | 44 | else if (chan < 14) |
47 | return 2407 + chan * 5; | 45 | return 2407 + chan * 5; |
46 | break; | ||
47 | case IEEE80211_BAND_5GHZ: | ||
48 | if (chan >= 182 && chan <= 196) | ||
49 | return 4000 + chan * 5; | ||
48 | else | 50 | else |
49 | return 0; /* not supported */ | 51 | return 5000 + chan * 5; |
52 | break; | ||
53 | case IEEE80211_BAND_60GHZ: | ||
54 | if (chan < 5) | ||
55 | return 56160 + chan * 2160; | ||
56 | break; | ||
57 | default: | ||
58 | ; | ||
50 | } | 59 | } |
60 | return 0; /* not supported */ | ||
51 | } | 61 | } |
52 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); | 62 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); |
53 | 63 | ||
@@ -60,8 +70,12 @@ int ieee80211_frequency_to_channel(int freq) | |||
60 | return (freq - 2407) / 5; | 70 | return (freq - 2407) / 5; |
61 | else if (freq >= 4910 && freq <= 4980) | 71 | else if (freq >= 4910 && freq <= 4980) |
62 | return (freq - 4000) / 5; | 72 | return (freq - 4000) / 5; |
63 | else | 73 | else if (freq <= 45000) /* DMG band lower limit */ |
64 | return (freq - 5000) / 5; | 74 | return (freq - 5000) / 5; |
75 | else if (freq >= 58320 && freq <= 64800) | ||
76 | return (freq - 56160) / 2160; | ||
77 | else | ||
78 | return 0; | ||
65 | } | 79 | } |
66 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); | 80 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); |
67 | 81 | ||
@@ -137,6 +151,11 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, | |||
137 | } | 151 | } |
138 | WARN_ON(want != 0 && want != 3 && want != 6); | 152 | WARN_ON(want != 0 && want != 3 && want != 6); |
139 | break; | 153 | break; |
154 | case IEEE80211_BAND_60GHZ: | ||
155 | /* check for mandatory HT MCS 1..4 */ | ||
156 | WARN_ON(!sband->ht_cap.ht_supported); | ||
157 | WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e); | ||
158 | break; | ||
140 | case IEEE80211_NUM_BANDS: | 159 | case IEEE80211_NUM_BANDS: |
141 | WARN_ON(1); | 160 | WARN_ON(1); |
142 | break; | 161 | break; |
@@ -774,7 +793,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) | |||
774 | 793 | ||
775 | mutex_lock(&rdev->devlist_mtx); | 794 | mutex_lock(&rdev->devlist_mtx); |
776 | 795 | ||
777 | list_for_each_entry(wdev, &rdev->netdev_list, list) | 796 | list_for_each_entry(wdev, &rdev->wdev_list, list) |
778 | cfg80211_process_wdev_events(wdev); | 797 | cfg80211_process_wdev_events(wdev); |
779 | 798 | ||
780 | mutex_unlock(&rdev->devlist_mtx); | 799 | mutex_unlock(&rdev->devlist_mtx); |
@@ -805,8 +824,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
805 | return -EBUSY; | 824 | return -EBUSY; |
806 | 825 | ||
807 | if (ntype != otype && netif_running(dev)) { | 826 | if (ntype != otype && netif_running(dev)) { |
827 | mutex_lock(&rdev->devlist_mtx); | ||
808 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, | 828 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, |
809 | ntype); | 829 | ntype); |
830 | mutex_unlock(&rdev->devlist_mtx); | ||
810 | if (err) | 831 | if (err) |
811 | return err; | 832 | return err; |
812 | 833 | ||
@@ -814,6 +835,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
814 | dev->ieee80211_ptr->mesh_id_up_len = 0; | 835 | dev->ieee80211_ptr->mesh_id_up_len = 0; |
815 | 836 | ||
816 | switch (otype) { | 837 | switch (otype) { |
838 | case NL80211_IFTYPE_AP: | ||
839 | cfg80211_stop_ap(rdev, dev); | ||
840 | break; | ||
817 | case NL80211_IFTYPE_ADHOC: | 841 | case NL80211_IFTYPE_ADHOC: |
818 | cfg80211_leave_ibss(rdev, dev, false); | 842 | cfg80211_leave_ibss(rdev, dev, false); |
819 | break; | 843 | break; |
@@ -868,15 +892,69 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
868 | } | 892 | } |
869 | } | 893 | } |
870 | 894 | ||
895 | if (!err && ntype != otype && netif_running(dev)) { | ||
896 | cfg80211_update_iface_num(rdev, ntype, 1); | ||
897 | cfg80211_update_iface_num(rdev, otype, -1); | ||
898 | } | ||
899 | |||
871 | return err; | 900 | return err; |
872 | } | 901 | } |
873 | 902 | ||
874 | u16 cfg80211_calculate_bitrate(struct rate_info *rate) | 903 | static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) |
904 | { | ||
905 | static const u32 __mcs2bitrate[] = { | ||
906 | /* control PHY */ | ||
907 | [0] = 275, | ||
908 | /* SC PHY */ | ||
909 | [1] = 3850, | ||
910 | [2] = 7700, | ||
911 | [3] = 9625, | ||
912 | [4] = 11550, | ||
913 | [5] = 12512, /* 1251.25 mbps */ | ||
914 | [6] = 15400, | ||
915 | [7] = 19250, | ||
916 | [8] = 23100, | ||
917 | [9] = 25025, | ||
918 | [10] = 30800, | ||
919 | [11] = 38500, | ||
920 | [12] = 46200, | ||
921 | /* OFDM PHY */ | ||
922 | [13] = 6930, | ||
923 | [14] = 8662, /* 866.25 mbps */ | ||
924 | [15] = 13860, | ||
925 | [16] = 17325, | ||
926 | [17] = 20790, | ||
927 | [18] = 27720, | ||
928 | [19] = 34650, | ||
929 | [20] = 41580, | ||
930 | [21] = 45045, | ||
931 | [22] = 51975, | ||
932 | [23] = 62370, | ||
933 | [24] = 67568, /* 6756.75 mbps */ | ||
934 | /* LP-SC PHY */ | ||
935 | [25] = 6260, | ||
936 | [26] = 8340, | ||
937 | [27] = 11120, | ||
938 | [28] = 12510, | ||
939 | [29] = 16680, | ||
940 | [30] = 22240, | ||
941 | [31] = 25030, | ||
942 | }; | ||
943 | |||
944 | if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate))) | ||
945 | return 0; | ||
946 | |||
947 | return __mcs2bitrate[rate->mcs]; | ||
948 | } | ||
949 | |||
950 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) | ||
875 | { | 951 | { |
876 | int modulation, streams, bitrate; | 952 | int modulation, streams, bitrate; |
877 | 953 | ||
878 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) | 954 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) |
879 | return rate->legacy; | 955 | return rate->legacy; |
956 | if (rate->flags & RATE_INFO_FLAGS_60G) | ||
957 | return cfg80211_calculate_bitrate_60g(rate); | ||
880 | 958 | ||
881 | /* the formula below does only work for MCS values smaller than 32 */ | 959 | /* the formula below does only work for MCS values smaller than 32 */ |
882 | if (WARN_ON_ONCE(rate->mcs >= 32)) | 960 | if (WARN_ON_ONCE(rate->mcs >= 32)) |
@@ -916,7 +994,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
916 | 994 | ||
917 | mutex_lock(&rdev->devlist_mtx); | 995 | mutex_lock(&rdev->devlist_mtx); |
918 | 996 | ||
919 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 997 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
920 | if (!wdev->beacon_interval) | 998 | if (!wdev->beacon_interval) |
921 | continue; | 999 | continue; |
922 | if (wdev->beacon_interval != beacon_int) { | 1000 | if (wdev->beacon_interval != beacon_int) { |
@@ -930,28 +1008,49 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
930 | return res; | 1008 | return res; |
931 | } | 1009 | } |
932 | 1010 | ||
933 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 1011 | int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, |
934 | struct wireless_dev *wdev, | 1012 | struct wireless_dev *wdev, |
935 | enum nl80211_iftype iftype) | 1013 | enum nl80211_iftype iftype, |
1014 | struct ieee80211_channel *chan, | ||
1015 | enum cfg80211_chan_mode chanmode) | ||
936 | { | 1016 | { |
937 | struct wireless_dev *wdev_iter; | 1017 | struct wireless_dev *wdev_iter; |
938 | u32 used_iftypes = BIT(iftype); | 1018 | u32 used_iftypes = BIT(iftype); |
939 | int num[NUM_NL80211_IFTYPES]; | 1019 | int num[NUM_NL80211_IFTYPES]; |
1020 | struct ieee80211_channel | ||
1021 | *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS]; | ||
1022 | struct ieee80211_channel *ch; | ||
1023 | enum cfg80211_chan_mode chmode; | ||
1024 | int num_different_channels = 0; | ||
940 | int total = 1; | 1025 | int total = 1; |
941 | int i, j; | 1026 | int i, j; |
942 | 1027 | ||
943 | ASSERT_RTNL(); | 1028 | ASSERT_RTNL(); |
1029 | lockdep_assert_held(&rdev->devlist_mtx); | ||
944 | 1030 | ||
945 | /* Always allow software iftypes */ | 1031 | /* Always allow software iftypes */ |
946 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 1032 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |
947 | return 0; | 1033 | return 0; |
948 | 1034 | ||
949 | memset(num, 0, sizeof(num)); | 1035 | memset(num, 0, sizeof(num)); |
1036 | memset(used_channels, 0, sizeof(used_channels)); | ||
950 | 1037 | ||
951 | num[iftype] = 1; | 1038 | num[iftype] = 1; |
952 | 1039 | ||
953 | mutex_lock(&rdev->devlist_mtx); | 1040 | switch (chanmode) { |
954 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { | 1041 | case CHAN_MODE_UNDEFINED: |
1042 | break; | ||
1043 | case CHAN_MODE_SHARED: | ||
1044 | WARN_ON(!chan); | ||
1045 | used_channels[0] = chan; | ||
1046 | num_different_channels++; | ||
1047 | break; | ||
1048 | case CHAN_MODE_EXCLUSIVE: | ||
1049 | num_different_channels++; | ||
1050 | break; | ||
1051 | } | ||
1052 | |||
1053 | list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { | ||
955 | if (wdev_iter == wdev) | 1054 | if (wdev_iter == wdev) |
956 | continue; | 1055 | continue; |
957 | if (!netif_running(wdev_iter->netdev)) | 1056 | if (!netif_running(wdev_iter->netdev)) |
@@ -960,11 +1059,42 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
960 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) | 1059 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) |
961 | continue; | 1060 | continue; |
962 | 1061 | ||
1062 | /* | ||
1063 | * We may be holding the "wdev" mutex, but now need to lock | ||
1064 | * wdev_iter. This is OK because once we get here wdev_iter | ||
1065 | * is not wdev (tested above), but we need to use the nested | ||
1066 | * locking for lockdep. | ||
1067 | */ | ||
1068 | mutex_lock_nested(&wdev_iter->mtx, 1); | ||
1069 | __acquire(wdev_iter->mtx); | ||
1070 | cfg80211_get_chan_state(wdev_iter, &ch, &chmode); | ||
1071 | wdev_unlock(wdev_iter); | ||
1072 | |||
1073 | switch (chmode) { | ||
1074 | case CHAN_MODE_UNDEFINED: | ||
1075 | break; | ||
1076 | case CHAN_MODE_SHARED: | ||
1077 | for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++) | ||
1078 | if (!used_channels[i] || used_channels[i] == ch) | ||
1079 | break; | ||
1080 | |||
1081 | if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) | ||
1082 | return -EBUSY; | ||
1083 | |||
1084 | if (used_channels[i] == NULL) { | ||
1085 | used_channels[i] = ch; | ||
1086 | num_different_channels++; | ||
1087 | } | ||
1088 | break; | ||
1089 | case CHAN_MODE_EXCLUSIVE: | ||
1090 | num_different_channels++; | ||
1091 | break; | ||
1092 | } | ||
1093 | |||
963 | num[wdev_iter->iftype]++; | 1094 | num[wdev_iter->iftype]++; |
964 | total++; | 1095 | total++; |
965 | used_iftypes |= BIT(wdev_iter->iftype); | 1096 | used_iftypes |= BIT(wdev_iter->iftype); |
966 | } | 1097 | } |
967 | mutex_unlock(&rdev->devlist_mtx); | ||
968 | 1098 | ||
969 | if (total == 1) | 1099 | if (total == 1) |
970 | return 0; | 1100 | return 0; |
@@ -976,12 +1106,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
976 | 1106 | ||
977 | c = &rdev->wiphy.iface_combinations[i]; | 1107 | c = &rdev->wiphy.iface_combinations[i]; |
978 | 1108 | ||
1109 | if (total > c->max_interfaces) | ||
1110 | continue; | ||
1111 | if (num_different_channels > c->num_different_channels) | ||
1112 | continue; | ||
1113 | |||
979 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, | 1114 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, |
980 | GFP_KERNEL); | 1115 | GFP_KERNEL); |
981 | if (!limits) | 1116 | if (!limits) |
982 | return -ENOMEM; | 1117 | return -ENOMEM; |
983 | if (total > c->max_interfaces) | ||
984 | goto cont; | ||
985 | 1118 | ||
986 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { | 1119 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { |
987 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 1120 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 6a6181a673ca..494379eb464f 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -796,7 +796,15 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, | |||
796 | case NL80211_IFTYPE_ADHOC: | 796 | case NL80211_IFTYPE_ADHOC: |
797 | return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); | 797 | return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); |
798 | case NL80211_IFTYPE_MONITOR: | 798 | case NL80211_IFTYPE_MONITOR: |
799 | case NL80211_IFTYPE_WDS: | 799 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
800 | if (freq < 0) | ||
801 | return freq; | ||
802 | if (freq == 0) | ||
803 | return -EINVAL; | ||
804 | mutex_lock(&rdev->devlist_mtx); | ||
805 | err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT); | ||
806 | mutex_unlock(&rdev->devlist_mtx); | ||
807 | return err; | ||
800 | case NL80211_IFTYPE_MESH_POINT: | 808 | case NL80211_IFTYPE_MESH_POINT: |
801 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); | 809 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
802 | if (freq < 0) | 810 | if (freq < 0) |
@@ -804,9 +812,8 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, | |||
804 | if (freq == 0) | 812 | if (freq == 0) |
805 | return -EINVAL; | 813 | return -EINVAL; |
806 | mutex_lock(&rdev->devlist_mtx); | 814 | mutex_lock(&rdev->devlist_mtx); |
807 | wdev_lock(wdev); | 815 | err = cfg80211_set_mesh_freq(rdev, wdev, freq, |
808 | err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT); | 816 | NL80211_CHAN_NO_HT); |
809 | wdev_unlock(wdev); | ||
810 | mutex_unlock(&rdev->devlist_mtx); | 817 | mutex_unlock(&rdev->devlist_mtx); |
811 | return err; | 818 | return err; |
812 | default: | 819 | default: |
@@ -832,18 +839,14 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, | |||
832 | if (!rdev->ops->get_channel) | 839 | if (!rdev->ops->get_channel) |
833 | return -EINVAL; | 840 | return -EINVAL; |
834 | 841 | ||
835 | chan = rdev->ops->get_channel(wdev->wiphy, &channel_type); | 842 | chan = rdev->ops->get_channel(wdev->wiphy, wdev, &channel_type); |
836 | if (!chan) | 843 | if (!chan) |
837 | return -EINVAL; | 844 | return -EINVAL; |
838 | freq->m = chan->center_freq; | 845 | freq->m = chan->center_freq; |
839 | freq->e = 6; | 846 | freq->e = 6; |
840 | return 0; | 847 | return 0; |
841 | default: | 848 | default: |
842 | if (!wdev->channel) | 849 | return -EINVAL; |
843 | return -EINVAL; | ||
844 | freq->m = wdev->channel->center_freq; | ||
845 | freq->e = 6; | ||
846 | return 0; | ||
847 | } | 850 | } |
848 | } | 851 | } |
849 | 852 | ||
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 7decbd357d51..1f773f668d1a 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -111,9 +111,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
111 | 111 | ||
112 | wdev->wext.connect.channel = chan; | 112 | wdev->wext.connect.channel = chan; |
113 | 113 | ||
114 | /* SSID is not set, we just want to switch channel */ | 114 | /* |
115 | * SSID is not set, we just want to switch monitor channel, | ||
116 | * this is really just backward compatibility, if the SSID | ||
117 | * is set then we use the channel to select the BSS to use | ||
118 | * to connect to instead. If we were connected on another | ||
119 | * channel we disconnected above and reconnect below. | ||
120 | */ | ||
115 | if (chan && !wdev->wext.connect.ssid_len) { | 121 | if (chan && !wdev->wext.connect.ssid_len) { |
116 | err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT); | 122 | err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT); |
117 | goto out; | 123 | goto out; |
118 | } | 124 | } |
119 | 125 | ||