diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-07-12 13:44:50 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-07-12 13:44:50 -0400 |
commit | 38a00840638b4932152bca48098dbfa069d942a2 (patch) | |
tree | dd12897854f6df8aac237d5fd46551c74be8153a /net/wireless | |
parent | 391e5c22f5f4e55817f8ba18a08ea717ed2d4a1f (diff) | |
parent | 2f8684ce7a47c91da7e0ccba2686277c103d02b6 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/Makefile | 2 | ||||
-rw-r--r-- | net/wireless/ap.c | 46 | ||||
-rw-r--r-- | net/wireless/chan.c | 62 | ||||
-rw-r--r-- | net/wireless/core.c | 84 | ||||
-rw-r--r-- | net/wireless/core.h | 64 | ||||
-rw-r--r-- | net/wireless/ibss.c | 11 | ||||
-rw-r--r-- | net/wireless/mesh.c | 30 | ||||
-rw-r--r-- | net/wireless/mlme.c | 17 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 65 | ||||
-rw-r--r-- | net/wireless/reg.c | 5 | ||||
-rw-r--r-- | net/wireless/util.c | 156 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 9 |
12 files changed, 488 insertions, 63 deletions
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 c1999e45a07c..434c56b92c3c 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -82,13 +82,73 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, | |||
82 | int freq, enum nl80211_channel_type chantype) | 82 | int freq, enum nl80211_channel_type chantype) |
83 | { | 83 | { |
84 | struct ieee80211_channel *chan; | 84 | struct ieee80211_channel *chan; |
85 | int err; | ||
85 | 86 | ||
86 | if (!rdev->ops->set_monitor_channel) | 87 | if (!rdev->ops->set_monitor_channel) |
87 | return -EOPNOTSUPP; | 88 | return -EOPNOTSUPP; |
89 | if (!cfg80211_has_monitors_only(rdev)) | ||
90 | return -EBUSY; | ||
88 | 91 | ||
89 | chan = rdev_freq_to_chan(rdev, freq, chantype); | 92 | chan = rdev_freq_to_chan(rdev, freq, chantype); |
90 | if (!chan) | 93 | if (!chan) |
91 | return -EINVAL; | 94 | return -EINVAL; |
92 | 95 | ||
93 | return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); | 96 | err = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); |
97 | if (!err) { | ||
98 | rdev->monitor_channel = chan; | ||
99 | rdev->monitor_channel_type = chantype; | ||
100 | } | ||
101 | |||
102 | return err; | ||
103 | } | ||
104 | |||
105 | void | ||
106 | cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, | ||
107 | struct wireless_dev *wdev, | ||
108 | struct ieee80211_channel **chan, | ||
109 | enum cfg80211_chan_mode *chanmode) | ||
110 | { | ||
111 | *chan = NULL; | ||
112 | *chanmode = CHAN_MODE_UNDEFINED; | ||
113 | |||
114 | ASSERT_RDEV_LOCK(rdev); | ||
115 | ASSERT_WDEV_LOCK(wdev); | ||
116 | |||
117 | if (!netif_running(wdev->netdev)) | ||
118 | return; | ||
119 | |||
120 | switch (wdev->iftype) { | ||
121 | case NL80211_IFTYPE_ADHOC: | ||
122 | if (wdev->current_bss) { | ||
123 | *chan = wdev->current_bss->pub.channel; | ||
124 | *chanmode = wdev->ibss_fixed | ||
125 | ? CHAN_MODE_SHARED | ||
126 | : CHAN_MODE_EXCLUSIVE; | ||
127 | return; | ||
128 | } | ||
129 | case NL80211_IFTYPE_STATION: | ||
130 | case NL80211_IFTYPE_P2P_CLIENT: | ||
131 | if (wdev->current_bss) { | ||
132 | *chan = wdev->current_bss->pub.channel; | ||
133 | *chanmode = CHAN_MODE_SHARED; | ||
134 | return; | ||
135 | } | ||
136 | break; | ||
137 | case NL80211_IFTYPE_AP: | ||
138 | case NL80211_IFTYPE_P2P_GO: | ||
139 | case NL80211_IFTYPE_MESH_POINT: | ||
140 | *chan = wdev->channel; | ||
141 | *chanmode = CHAN_MODE_SHARED; | ||
142 | return; | ||
143 | case NL80211_IFTYPE_MONITOR: | ||
144 | case NL80211_IFTYPE_AP_VLAN: | ||
145 | case NL80211_IFTYPE_WDS: | ||
146 | /* these interface types don't really have a channel */ | ||
147 | return; | ||
148 | case NL80211_IFTYPE_UNSPECIFIED: | ||
149 | case NUM_NL80211_IFTYPES: | ||
150 | WARN_ON(1); | ||
151 | } | ||
152 | |||
153 | return; | ||
94 | } | 154 | } |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 907f62c80e28..eb60410ae588 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -373,6 +373,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) | |||
373 | if (WARN_ON(!c->num_different_channels)) | 373 | if (WARN_ON(!c->num_different_channels)) |
374 | return -EINVAL; | 374 | return -EINVAL; |
375 | 375 | ||
376 | /* | ||
377 | * Put a sane limit on maximum number of different | ||
378 | * channels to simplify channel accounting code. | ||
379 | */ | ||
380 | if (WARN_ON(c->num_different_channels > | ||
381 | CFG80211_MAX_NUM_DIFFERENT_CHANNELS)) | ||
382 | return -EINVAL; | ||
383 | |||
376 | if (WARN_ON(!c->n_limits)) | 384 | if (WARN_ON(!c->n_limits)) |
377 | return -EINVAL; | 385 | return -EINVAL; |
378 | 386 | ||
@@ -421,9 +429,11 @@ int wiphy_register(struct wiphy *wiphy) | |||
421 | int i; | 429 | int i; |
422 | u16 ifmodes = wiphy->interface_modes; | 430 | u16 ifmodes = wiphy->interface_modes; |
423 | 431 | ||
432 | #ifdef CONFIG_PM | ||
424 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | 433 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && |
425 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | 434 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) |
426 | return -EINVAL; | 435 | return -EINVAL; |
436 | #endif | ||
427 | 437 | ||
428 | if (WARN_ON(wiphy->ap_sme_capa && | 438 | if (WARN_ON(wiphy->ap_sme_capa && |
429 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) | 439 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) |
@@ -458,8 +468,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
458 | continue; | 468 | continue; |
459 | 469 | ||
460 | sband->band = band; | 470 | sband->band = band; |
461 | 471 | if (WARN_ON(!sband->n_channels)) | |
462 | if (WARN_ON(!sband->n_channels || !sband->n_bitrates)) | 472 | return -EINVAL; |
473 | /* | ||
474 | * on 60gHz band, there are no legacy rates, so | ||
475 | * n_bitrates is 0 | ||
476 | */ | ||
477 | if (WARN_ON(band != IEEE80211_BAND_60GHZ && | ||
478 | !sband->n_bitrates)) | ||
463 | return -EINVAL; | 479 | return -EINVAL; |
464 | 480 | ||
465 | /* | 481 | /* |
@@ -500,12 +516,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
500 | return -EINVAL; | 516 | return -EINVAL; |
501 | } | 517 | } |
502 | 518 | ||
519 | #ifdef CONFIG_PM | ||
503 | if (rdev->wiphy.wowlan.n_patterns) { | 520 | if (rdev->wiphy.wowlan.n_patterns) { |
504 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || | 521 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || |
505 | rdev->wiphy.wowlan.pattern_min_len > | 522 | rdev->wiphy.wowlan.pattern_min_len > |
506 | rdev->wiphy.wowlan.pattern_max_len)) | 523 | rdev->wiphy.wowlan.pattern_max_len)) |
507 | return -EINVAL; | 524 | return -EINVAL; |
508 | } | 525 | } |
526 | #endif | ||
509 | 527 | ||
510 | /* check and set up bitrates */ | 528 | /* check and set up bitrates */ |
511 | ieee80211_set_bitrate_flags(wiphy); | 529 | ieee80211_set_bitrate_flags(wiphy); |
@@ -713,6 +731,61 @@ static struct device_type wiphy_type = { | |||
713 | .name = "wlan", | 731 | .name = "wlan", |
714 | }; | 732 | }; |
715 | 733 | ||
734 | static struct ieee80211_channel * | ||
735 | cfg80211_get_any_chan(struct cfg80211_registered_device *rdev) | ||
736 | { | ||
737 | struct ieee80211_supported_band *sband; | ||
738 | int i; | ||
739 | |||
740 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
741 | sband = rdev->wiphy.bands[i]; | ||
742 | if (sband && sband->n_channels > 0) | ||
743 | return &sband->channels[0]; | ||
744 | } | ||
745 | |||
746 | return NULL; | ||
747 | } | ||
748 | |||
749 | static void cfg80211_init_mon_chan(struct cfg80211_registered_device *rdev) | ||
750 | { | ||
751 | struct ieee80211_channel *chan; | ||
752 | |||
753 | chan = cfg80211_get_any_chan(rdev); | ||
754 | if (WARN_ON(!chan)) | ||
755 | return; | ||
756 | |||
757 | mutex_lock(&rdev->devlist_mtx); | ||
758 | WARN_ON(cfg80211_set_monitor_channel(rdev, chan->center_freq, | ||
759 | NL80211_CHAN_NO_HT)); | ||
760 | mutex_unlock(&rdev->devlist_mtx); | ||
761 | } | ||
762 | |||
763 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||
764 | enum nl80211_iftype iftype, int num) | ||
765 | { | ||
766 | bool has_monitors_only_old = cfg80211_has_monitors_only(rdev); | ||
767 | bool has_monitors_only_new; | ||
768 | |||
769 | ASSERT_RTNL(); | ||
770 | |||
771 | rdev->num_running_ifaces += num; | ||
772 | if (iftype == NL80211_IFTYPE_MONITOR) | ||
773 | rdev->num_running_monitor_ifaces += num; | ||
774 | |||
775 | has_monitors_only_new = cfg80211_has_monitors_only(rdev); | ||
776 | if (has_monitors_only_new != has_monitors_only_old) { | ||
777 | rdev->ops->set_monitor_enabled(&rdev->wiphy, | ||
778 | has_monitors_only_new); | ||
779 | |||
780 | if (!has_monitors_only_new) { | ||
781 | rdev->monitor_channel = NULL; | ||
782 | rdev->monitor_channel_type = NL80211_CHAN_NO_HT; | ||
783 | } else { | ||
784 | cfg80211_init_mon_chan(rdev); | ||
785 | } | ||
786 | } | ||
787 | } | ||
788 | |||
716 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 789 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
717 | unsigned long state, | 790 | unsigned long state, |
718 | void *ndev) | 791 | void *ndev) |
@@ -806,12 +879,16 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
806 | case NL80211_IFTYPE_MESH_POINT: | 879 | case NL80211_IFTYPE_MESH_POINT: |
807 | cfg80211_leave_mesh(rdev, dev); | 880 | cfg80211_leave_mesh(rdev, dev); |
808 | break; | 881 | break; |
882 | case NL80211_IFTYPE_AP: | ||
883 | cfg80211_stop_ap(rdev, dev); | ||
884 | break; | ||
809 | default: | 885 | default: |
810 | break; | 886 | break; |
811 | } | 887 | } |
812 | wdev->beacon_interval = 0; | 888 | wdev->beacon_interval = 0; |
813 | break; | 889 | break; |
814 | case NETDEV_DOWN: | 890 | case NETDEV_DOWN: |
891 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | ||
815 | dev_hold(dev); | 892 | dev_hold(dev); |
816 | queue_work(cfg80211_wq, &wdev->cleanup_work); | 893 | queue_work(cfg80211_wq, &wdev->cleanup_work); |
817 | break; | 894 | break; |
@@ -917,9 +994,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
917 | return notifier_from_errno(-EOPNOTSUPP); | 994 | return notifier_from_errno(-EOPNOTSUPP); |
918 | if (rfkill_blocked(rdev->rfkill)) | 995 | if (rfkill_blocked(rdev->rfkill)) |
919 | return notifier_from_errno(-ERFKILL); | 996 | return notifier_from_errno(-ERFKILL); |
997 | mutex_lock(&rdev->devlist_mtx); | ||
920 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | 998 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); |
999 | mutex_unlock(&rdev->devlist_mtx); | ||
921 | if (ret) | 1000 | if (ret) |
922 | return notifier_from_errno(ret); | 1001 | return notifier_from_errno(ret); |
1002 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); | ||
923 | break; | 1003 | break; |
924 | } | 1004 | } |
925 | 1005 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index 609a579255ac..377dc394f48c 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" |
@@ -56,6 +57,13 @@ struct cfg80211_registered_device { | |||
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 | |||
64 | struct ieee80211_channel *monitor_channel; | ||
65 | enum nl80211_channel_type monitor_channel_type; | ||
66 | |||
59 | /* BSSes/scanning */ | 67 | /* BSSes/scanning */ |
60 | spinlock_t bss_lock; | 68 | spinlock_t bss_lock; |
61 | struct list_head bss_list; | 69 | struct list_head bss_list; |
@@ -197,6 +205,14 @@ static inline void wdev_unlock(struct wireless_dev *wdev) | |||
197 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) | 205 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) |
198 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) | 206 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) |
199 | 207 | ||
208 | static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev) | ||
209 | { | ||
210 | ASSERT_RTNL(); | ||
211 | |||
212 | return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces && | ||
213 | rdev->num_running_ifaces > 0; | ||
214 | } | ||
215 | |||
200 | enum cfg80211_event_type { | 216 | enum cfg80211_event_type { |
201 | EVENT_CONNECT_RESULT, | 217 | EVENT_CONNECT_RESULT, |
202 | EVENT_ROAMED, | 218 | EVENT_ROAMED, |
@@ -241,6 +257,12 @@ struct cfg80211_cached_keys { | |||
241 | int def, defmgmt; | 257 | int def, defmgmt; |
242 | }; | 258 | }; |
243 | 259 | ||
260 | enum cfg80211_chan_mode { | ||
261 | CHAN_MODE_UNDEFINED, | ||
262 | CHAN_MODE_SHARED, | ||
263 | CHAN_MODE_EXCLUSIVE, | ||
264 | }; | ||
265 | |||
244 | 266 | ||
245 | /* free object */ | 267 | /* free object */ |
246 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); | 268 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); |
@@ -289,6 +311,10 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
289 | struct wireless_dev *wdev, int freq, | 311 | struct wireless_dev *wdev, int freq, |
290 | enum nl80211_channel_type channel_type); | 312 | enum nl80211_channel_type channel_type); |
291 | 313 | ||
314 | /* AP */ | ||
315 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
316 | struct net_device *dev); | ||
317 | |||
292 | /* MLME */ | 318 | /* MLME */ |
293 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 319 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
294 | struct net_device *dev, | 320 | struct net_device *dev, |
@@ -404,9 +430,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
404 | u32 *flags, struct vif_params *params); | 430 | u32 *flags, struct vif_params *params); |
405 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); | 431 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); |
406 | 432 | ||
407 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 433 | int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, |
408 | struct wireless_dev *wdev, | 434 | struct wireless_dev *wdev, |
409 | enum nl80211_iftype iftype); | 435 | enum nl80211_iftype iftype, |
436 | struct ieee80211_channel *chan, | ||
437 | enum cfg80211_chan_mode chanmode); | ||
438 | |||
439 | static inline int | ||
440 | cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | ||
441 | struct wireless_dev *wdev, | ||
442 | enum nl80211_iftype iftype) | ||
443 | { | ||
444 | return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL, | ||
445 | CHAN_MODE_UNDEFINED); | ||
446 | } | ||
410 | 447 | ||
411 | static inline int | 448 | static inline int |
412 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | 449 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, |
@@ -415,6 +452,22 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | |||
415 | return cfg80211_can_change_interface(rdev, NULL, iftype); | 452 | return cfg80211_can_change_interface(rdev, NULL, iftype); |
416 | } | 453 | } |
417 | 454 | ||
455 | static inline int | ||
456 | cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, | ||
457 | struct wireless_dev *wdev, | ||
458 | struct ieee80211_channel *chan, | ||
459 | enum cfg80211_chan_mode chanmode) | ||
460 | { | ||
461 | return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
462 | chan, chanmode); | ||
463 | } | ||
464 | |||
465 | void | ||
466 | cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, | ||
467 | struct wireless_dev *wdev, | ||
468 | struct ieee80211_channel **chan, | ||
469 | enum cfg80211_chan_mode *chanmode); | ||
470 | |||
418 | struct ieee80211_channel * | 471 | struct ieee80211_channel * |
419 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | 472 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, |
420 | int freq, enum nl80211_channel_type channel_type); | 473 | int freq, enum nl80211_channel_type channel_type); |
@@ -428,6 +481,11 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | |||
428 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 481 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
429 | u32 beacon_int); | 482 | u32 beacon_int); |
430 | 483 | ||
484 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||
485 | enum nl80211_iftype iftype, int num); | ||
486 | |||
487 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 | ||
488 | |||
431 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 489 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
432 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) | 490 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) |
433 | #else | 491 | #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 3b73b07486cf..c384e77ff77a 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -155,10 +155,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
155 | setup->channel_type)) | 155 | setup->channel_type)) |
156 | return -EINVAL; | 156 | return -EINVAL; |
157 | 157 | ||
158 | err = cfg80211_can_use_chan(rdev, wdev, setup->channel, | ||
159 | CHAN_MODE_SHARED); | ||
160 | if (err) | ||
161 | return err; | ||
162 | |||
158 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); | 163 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); |
159 | if (!err) { | 164 | if (!err) { |
160 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); | 165 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); |
161 | wdev->mesh_id_len = setup->mesh_id_len; | 166 | wdev->mesh_id_len = setup->mesh_id_len; |
167 | wdev->channel = setup->channel; | ||
162 | } | 168 | } |
163 | 169 | ||
164 | return err; | 170 | return err; |
@@ -172,9 +178,11 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
172 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 178 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
173 | int err; | 179 | int err; |
174 | 180 | ||
181 | mutex_lock(&rdev->devlist_mtx); | ||
175 | wdev_lock(wdev); | 182 | wdev_lock(wdev); |
176 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); | 183 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); |
177 | wdev_unlock(wdev); | 184 | wdev_unlock(wdev); |
185 | mutex_unlock(&rdev->devlist_mtx); | ||
178 | 186 | ||
179 | return err; | 187 | return err; |
180 | } | 188 | } |
@@ -184,6 +192,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
184 | enum nl80211_channel_type channel_type) | 192 | enum nl80211_channel_type channel_type) |
185 | { | 193 | { |
186 | struct ieee80211_channel *channel; | 194 | struct ieee80211_channel *channel; |
195 | int err; | ||
187 | 196 | ||
188 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | 197 | channel = rdev_freq_to_chan(rdev, freq, channel_type); |
189 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | 198 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, |
@@ -205,9 +214,19 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
205 | 214 | ||
206 | if (!netif_running(wdev->netdev)) | 215 | if (!netif_running(wdev->netdev)) |
207 | return -ENETDOWN; | 216 | return -ENETDOWN; |
208 | return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, | 217 | |
209 | wdev->netdev, | 218 | err = cfg80211_can_use_chan(rdev, wdev, channel, |
210 | 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; | ||
211 | } | 230 | } |
212 | 231 | ||
213 | if (wdev->mesh_id_len) | 232 | if (wdev->mesh_id_len) |
@@ -249,8 +268,11 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | |||
249 | return -ENOTCONN; | 268 | return -ENOTCONN; |
250 | 269 | ||
251 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); | 270 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); |
252 | if (!err) | 271 | if (!err) { |
253 | wdev->mesh_id_len = 0; | 272 | wdev->mesh_id_len = 0; |
273 | wdev->channel = NULL; | ||
274 | } | ||
275 | |||
254 | return err; | 276 | return err; |
255 | } | 277 | } |
256 | 278 | ||
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index da4406f11929..d4fece3bb18a 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 | } |
@@ -947,6 +963,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, | |||
947 | if (WARN_ON(!chan)) | 963 | if (WARN_ON(!chan)) |
948 | goto out; | 964 | goto out; |
949 | 965 | ||
966 | wdev->channel = chan; | ||
950 | nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); | 967 | nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); |
951 | out: | 968 | out: |
952 | wdev_unlock(wdev); | 969 | wdev_unlock(wdev); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3b508eaf2d07..0249cea53852 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -921,6 +921,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
921 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) | 921 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) |
922 | goto nla_put_failure; | 922 | goto nla_put_failure; |
923 | 923 | ||
924 | /* add VHT info */ | ||
925 | if (dev->wiphy.bands[band]->vht_cap.vht_supported && | ||
926 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, | ||
927 | sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), | ||
928 | &dev->wiphy.bands[band]->vht_cap.vht_mcs) || | ||
929 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, | ||
930 | dev->wiphy.bands[band]->vht_cap.cap))) | ||
931 | goto nla_put_failure; | ||
932 | |||
924 | /* add frequencies */ | 933 | /* add frequencies */ |
925 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | 934 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); |
926 | if (!nl_freqs) | 935 | if (!nl_freqs) |
@@ -1112,6 +1121,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1112 | nla_nest_end(msg, nl_ifs); | 1121 | nla_nest_end(msg, nl_ifs); |
1113 | } | 1122 | } |
1114 | 1123 | ||
1124 | #ifdef CONFIG_PM | ||
1115 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | 1125 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { |
1116 | struct nlattr *nl_wowlan; | 1126 | struct nlattr *nl_wowlan; |
1117 | 1127 | ||
@@ -1152,6 +1162,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1152 | 1162 | ||
1153 | nla_nest_end(msg, nl_wowlan); | 1163 | nla_nest_end(msg, nl_wowlan); |
1154 | } | 1164 | } |
1165 | #endif | ||
1155 | 1166 | ||
1156 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1167 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, |
1157 | dev->wiphy.software_iftypes)) | 1168 | dev->wiphy.software_iftypes)) |
@@ -1678,16 +1689,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1678 | (cfg80211_rdev_list_generation << 2))) | 1689 | (cfg80211_rdev_list_generation << 2))) |
1679 | goto nla_put_failure; | 1690 | goto nla_put_failure; |
1680 | 1691 | ||
1681 | if (rdev->ops->get_channel) { | 1692 | if (rdev->monitor_channel) { |
1682 | struct ieee80211_channel *chan; | 1693 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, |
1683 | enum nl80211_channel_type channel_type; | 1694 | rdev->monitor_channel->center_freq) || |
1684 | 1695 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | |
1685 | chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type); | 1696 | rdev->monitor_channel_type)) |
1686 | if (chan && | ||
1687 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | ||
1688 | chan->center_freq) || | ||
1689 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | ||
1690 | channel_type))) | ||
1691 | goto nla_put_failure; | 1697 | goto nla_put_failure; |
1692 | } | 1698 | } |
1693 | 1699 | ||
@@ -2472,11 +2478,20 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2472 | params.channel_type)) | 2478 | params.channel_type)) |
2473 | return -EINVAL; | 2479 | return -EINVAL; |
2474 | 2480 | ||
2481 | mutex_lock(&rdev->devlist_mtx); | ||
2482 | err = cfg80211_can_use_chan(rdev, wdev, params.channel, | ||
2483 | CHAN_MODE_SHARED); | ||
2484 | mutex_unlock(&rdev->devlist_mtx); | ||
2485 | |||
2486 | if (err) | ||
2487 | return err; | ||
2488 | |||
2475 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); | 2489 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); |
2476 | if (!err) { | 2490 | if (!err) { |
2477 | wdev->preset_chan = params.channel; | 2491 | wdev->preset_chan = params.channel; |
2478 | wdev->preset_chantype = params.channel_type; | 2492 | wdev->preset_chantype = params.channel_type; |
2479 | wdev->beacon_interval = params.beacon_interval; | 2493 | wdev->beacon_interval = params.beacon_interval; |
2494 | wdev->channel = params.channel; | ||
2480 | } | 2495 | } |
2481 | return err; | 2496 | return err; |
2482 | } | 2497 | } |
@@ -2510,23 +2525,8 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) | |||
2510 | { | 2525 | { |
2511 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2526 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2512 | struct net_device *dev = info->user_ptr[1]; | 2527 | struct net_device *dev = info->user_ptr[1]; |
2513 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2514 | int err; | ||
2515 | 2528 | ||
2516 | if (!rdev->ops->stop_ap) | 2529 | return cfg80211_stop_ap(rdev, dev); |
2517 | return -EOPNOTSUPP; | ||
2518 | |||
2519 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
2520 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
2521 | return -EOPNOTSUPP; | ||
2522 | |||
2523 | if (!wdev->beacon_interval) | ||
2524 | return -ENOENT; | ||
2525 | |||
2526 | err = rdev->ops->stop_ap(&rdev->wiphy, dev); | ||
2527 | if (!err) | ||
2528 | wdev->beacon_interval = 0; | ||
2529 | return err; | ||
2530 | } | 2530 | } |
2531 | 2531 | ||
2532 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 2532 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -2618,7 +2618,8 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2618 | int attr) | 2618 | int attr) |
2619 | { | 2619 | { |
2620 | struct nlattr *rate; | 2620 | struct nlattr *rate; |
2621 | u16 bitrate; | 2621 | u32 bitrate; |
2622 | u16 bitrate_compat; | ||
2622 | 2623 | ||
2623 | rate = nla_nest_start(msg, attr); | 2624 | rate = nla_nest_start(msg, attr); |
2624 | if (!rate) | 2625 | if (!rate) |
@@ -2626,8 +2627,12 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2626 | 2627 | ||
2627 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ | 2628 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ |
2628 | bitrate = cfg80211_calculate_bitrate(info); | 2629 | bitrate = cfg80211_calculate_bitrate(info); |
2630 | /* report 16-bit bitrate only if we can */ | ||
2631 | bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; | ||
2629 | if ((bitrate > 0 && | 2632 | if ((bitrate > 0 && |
2630 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate)) || | 2633 | nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) || |
2634 | (bitrate_compat > 0 && | ||
2635 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) || | ||
2631 | ((info->flags & RATE_INFO_FLAGS_MCS) && | 2636 | ((info->flags & RATE_INFO_FLAGS_MCS) && |
2632 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || | 2637 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || |
2633 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && | 2638 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && |
@@ -6276,6 +6281,7 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6276 | return cfg80211_leave_mesh(rdev, dev); | 6281 | return cfg80211_leave_mesh(rdev, dev); |
6277 | } | 6282 | } |
6278 | 6283 | ||
6284 | #ifdef CONFIG_PM | ||
6279 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 6285 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
6280 | { | 6286 | { |
6281 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6287 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -6504,6 +6510,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6504 | kfree(new_triggers.patterns); | 6510 | kfree(new_triggers.patterns); |
6505 | return err; | 6511 | return err; |
6506 | } | 6512 | } |
6513 | #endif | ||
6507 | 6514 | ||
6508 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | 6515 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) |
6509 | { | 6516 | { |
@@ -7158,6 +7165,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7158 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7165 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
7159 | NL80211_FLAG_NEED_RTNL, | 7166 | NL80211_FLAG_NEED_RTNL, |
7160 | }, | 7167 | }, |
7168 | #ifdef CONFIG_PM | ||
7161 | { | 7169 | { |
7162 | .cmd = NL80211_CMD_GET_WOWLAN, | 7170 | .cmd = NL80211_CMD_GET_WOWLAN, |
7163 | .doit = nl80211_get_wowlan, | 7171 | .doit = nl80211_get_wowlan, |
@@ -7174,6 +7182,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7174 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 7182 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
7175 | NL80211_FLAG_NEED_RTNL, | 7183 | NL80211_FLAG_NEED_RTNL, |
7176 | }, | 7184 | }, |
7185 | #endif | ||
7177 | { | 7186 | { |
7178 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, | 7187 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, |
7179 | .doit = nl80211_set_rekey_data, | 7188 | .doit = nl80211_set_rekey_data, |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index baf5704740ee..b2b32229b607 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -129,7 +129,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); | |||
129 | 129 | ||
130 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | 130 | /* We keep a static world regulatory domain in case of the absence of CRDA */ |
131 | static const struct ieee80211_regdomain world_regdom = { | 131 | static const struct ieee80211_regdomain world_regdom = { |
132 | .n_reg_rules = 5, | 132 | .n_reg_rules = 6, |
133 | .alpha2 = "00", | 133 | .alpha2 = "00", |
134 | .reg_rules = { | 134 | .reg_rules = { |
135 | /* IEEE 802.11b/g, channels 1..11 */ | 135 | /* IEEE 802.11b/g, channels 1..11 */ |
@@ -156,6 +156,9 @@ static const struct ieee80211_regdomain world_regdom = { | |||
156 | REG_RULE(5745-10, 5825+10, 40, 6, 20, | 156 | REG_RULE(5745-10, 5825+10, 40, 6, 20, |
157 | NL80211_RRF_PASSIVE_SCAN | | 157 | NL80211_RRF_PASSIVE_SCAN | |
158 | NL80211_RRF_NO_IBSS), | 158 | NL80211_RRF_NO_IBSS), |
159 | |||
160 | /* IEEE 802.11ad (60gHz), channels 1..3 */ | ||
161 | REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), | ||
159 | } | 162 | } |
160 | }; | 163 | }; |
161 | 164 | ||
diff --git a/net/wireless/util.c b/net/wireless/util.c index 316cfd00914f..e31f1dba79ec 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; |
@@ -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)) |
@@ -930,27 +1008,48 @@ 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) { |
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 | |||
954 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { | 1053 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { |
955 | if (wdev_iter == wdev) | 1054 | if (wdev_iter == wdev) |
956 | continue; | 1055 | continue; |
@@ -960,11 +1059,33 @@ 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 | cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode); | ||
1063 | |||
1064 | switch (chmode) { | ||
1065 | case CHAN_MODE_UNDEFINED: | ||
1066 | break; | ||
1067 | case CHAN_MODE_SHARED: | ||
1068 | for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++) | ||
1069 | if (!used_channels[i] || used_channels[i] == ch) | ||
1070 | break; | ||
1071 | |||
1072 | if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) | ||
1073 | return -EBUSY; | ||
1074 | |||
1075 | if (used_channels[i] == NULL) { | ||
1076 | used_channels[i] = ch; | ||
1077 | num_different_channels++; | ||
1078 | } | ||
1079 | break; | ||
1080 | case CHAN_MODE_EXCLUSIVE: | ||
1081 | num_different_channels++; | ||
1082 | break; | ||
1083 | } | ||
1084 | |||
963 | num[wdev_iter->iftype]++; | 1085 | num[wdev_iter->iftype]++; |
964 | total++; | 1086 | total++; |
965 | used_iftypes |= BIT(wdev_iter->iftype); | 1087 | used_iftypes |= BIT(wdev_iter->iftype); |
966 | } | 1088 | } |
967 | mutex_unlock(&rdev->devlist_mtx); | ||
968 | 1089 | ||
969 | if (total == 1) | 1090 | if (total == 1) |
970 | return 0; | 1091 | return 0; |
@@ -976,12 +1097,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
976 | 1097 | ||
977 | c = &rdev->wiphy.iface_combinations[i]; | 1098 | c = &rdev->wiphy.iface_combinations[i]; |
978 | 1099 | ||
1100 | if (total > c->max_interfaces) | ||
1101 | continue; | ||
1102 | if (num_different_channels > c->num_different_channels) | ||
1103 | continue; | ||
1104 | |||
979 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, | 1105 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, |
980 | GFP_KERNEL); | 1106 | GFP_KERNEL); |
981 | if (!limits) | 1107 | if (!limits) |
982 | return -ENOMEM; | 1108 | return -ENOMEM; |
983 | if (total > c->max_interfaces) | ||
984 | goto cont; | ||
985 | 1109 | ||
986 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { | 1110 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { |
987 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 1111 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index bc879833b21f..7df42f541873 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -827,8 +827,6 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, | |||
827 | { | 827 | { |
828 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 828 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
829 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 829 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
830 | struct ieee80211_channel *chan; | ||
831 | enum nl80211_channel_type channel_type; | ||
832 | 830 | ||
833 | switch (wdev->iftype) { | 831 | switch (wdev->iftype) { |
834 | case NL80211_IFTYPE_STATION: | 832 | case NL80211_IFTYPE_STATION: |
@@ -836,13 +834,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, | |||
836 | case NL80211_IFTYPE_ADHOC: | 834 | case NL80211_IFTYPE_ADHOC: |
837 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); | 835 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); |
838 | case NL80211_IFTYPE_MONITOR: | 836 | case NL80211_IFTYPE_MONITOR: |
839 | if (!rdev->ops->get_channel) | 837 | if (!rdev->monitor_channel) |
840 | return -EINVAL; | 838 | return -EINVAL; |
841 | 839 | ||
842 | chan = rdev->ops->get_channel(wdev->wiphy, &channel_type); | 840 | freq->m = rdev->monitor_channel->center_freq; |
843 | if (!chan) | ||
844 | return -EINVAL; | ||
845 | freq->m = chan->center_freq; | ||
846 | freq->e = 6; | 841 | freq->e = 6; |
847 | return 0; | 842 | return 0; |
848 | default: | 843 | default: |