diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 14:47:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 14:47:02 -0400 |
commit | 5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0 (patch) | |
tree | 7851ef1c93aa1aba7ef327ca4b75fd35e6d10f29 /net/wireless | |
parent | 02f36038c568111ad4fc433f6fa760ff5e38fab4 (diff) | |
parent | ec37a48d1d16c30b655ac5280209edf52a6775d4 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1699 commits)
bnx2/bnx2x: Unsupported Ethtool operations should return -EINVAL.
vlan: Calling vlan_hwaccel_do_receive() is always valid.
tproxy: use the interface primary IP address as a default value for --on-ip
tproxy: added IPv6 support to the socket match
cxgb3: function namespace cleanup
tproxy: added IPv6 support to the TPROXY target
tproxy: added IPv6 socket lookup function to nf_tproxy_core
be2net: Changes to use only priority codes allowed by f/w
tproxy: allow non-local binds of IPv6 sockets if IP_TRANSPARENT is enabled
tproxy: added tproxy sockopt interface in the IPV6 layer
tproxy: added udp6_lib_lookup function
tproxy: added const specifiers to udp lookup functions
tproxy: split off ipv6 defragmentation to a separate module
l2tp: small cleanup
nf_nat: restrict ICMP translation for embedded header
can: mcp251x: fix generation of error frames
can: mcp251x: fix endless loop in interrupt handler if CANINTF_MERRF is set
can-raw: add msg_flags to distinguish local traffic
9p: client code cleanup
rds: make local functions/variables static
...
Fix up conflicts in net/core/dev.c, drivers/net/pcmcia/smc91c92_cs.c and
drivers/net/wireless/ath/ath9k/debug.c as per David
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 66 | ||||
-rw-r--r-- | net/wireless/core.h | 34 | ||||
-rw-r--r-- | net/wireless/ibss.c | 21 | ||||
-rw-r--r-- | net/wireless/mlme.c | 225 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 2189 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 14 | ||||
-rw-r--r-- | net/wireless/radiotap.c | 61 | ||||
-rw-r--r-- | net/wireless/reg.c | 22 | ||||
-rw-r--r-- | net/wireless/scan.c | 12 | ||||
-rw-r--r-- | net/wireless/sme.c | 11 | ||||
-rw-r--r-- | net/wireless/sysfs.c | 18 | ||||
-rw-r--r-- | net/wireless/util.c | 40 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 42 | ||||
-rw-r--r-- | net/wireless/wext-core.c | 2 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 2 |
15 files changed, 1196 insertions, 1563 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index d6d046b9f6f2..9c21ebf9780e 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -253,11 +253,16 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | |||
253 | WARN_ON(err); | 253 | WARN_ON(err); |
254 | wdev->netdev->features |= NETIF_F_NETNS_LOCAL; | 254 | wdev->netdev->features |= NETIF_F_NETNS_LOCAL; |
255 | } | 255 | } |
256 | |||
257 | return err; | ||
256 | } | 258 | } |
257 | 259 | ||
258 | wiphy_net_set(&rdev->wiphy, net); | 260 | wiphy_net_set(&rdev->wiphy, net); |
259 | 261 | ||
260 | return err; | 262 | err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev)); |
263 | WARN_ON(err); | ||
264 | |||
265 | return 0; | ||
261 | } | 266 | } |
262 | 267 | ||
263 | static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) | 268 | static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) |
@@ -428,7 +433,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
428 | 433 | ||
429 | /* sanity check ifmodes */ | 434 | /* sanity check ifmodes */ |
430 | WARN_ON(!ifmodes); | 435 | WARN_ON(!ifmodes); |
431 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; | 436 | ifmodes &= ((1 << NUM_NL80211_IFTYPES) - 1) & ~1; |
432 | if (WARN_ON(ifmodes != wiphy->interface_modes)) | 437 | if (WARN_ON(ifmodes != wiphy->interface_modes)) |
433 | wiphy->interface_modes = ifmodes; | 438 | wiphy->interface_modes = ifmodes; |
434 | 439 | ||
@@ -683,8 +688,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
683 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); | 688 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); |
684 | INIT_LIST_HEAD(&wdev->event_list); | 689 | INIT_LIST_HEAD(&wdev->event_list); |
685 | spin_lock_init(&wdev->event_lock); | 690 | spin_lock_init(&wdev->event_lock); |
686 | INIT_LIST_HEAD(&wdev->action_registrations); | 691 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
687 | spin_lock_init(&wdev->action_registrations_lock); | 692 | spin_lock_init(&wdev->mgmt_registrations_lock); |
688 | 693 | ||
689 | mutex_lock(&rdev->devlist_mtx); | 694 | mutex_lock(&rdev->devlist_mtx); |
690 | list_add_rcu(&wdev->list, &rdev->netdev_list); | 695 | list_add_rcu(&wdev->list, &rdev->netdev_list); |
@@ -724,6 +729,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
724 | dev->ethtool_ops = &cfg80211_ethtool_ops; | 729 | dev->ethtool_ops = &cfg80211_ethtool_ops; |
725 | 730 | ||
726 | if ((wdev->iftype == NL80211_IFTYPE_STATION || | 731 | if ((wdev->iftype == NL80211_IFTYPE_STATION || |
732 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || | ||
727 | wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) | 733 | wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) |
728 | dev->priv_flags |= IFF_DONT_BRIDGE; | 734 | dev->priv_flags |= IFF_DONT_BRIDGE; |
729 | break; | 735 | break; |
@@ -732,6 +738,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
732 | case NL80211_IFTYPE_ADHOC: | 738 | case NL80211_IFTYPE_ADHOC: |
733 | cfg80211_leave_ibss(rdev, dev, true); | 739 | cfg80211_leave_ibss(rdev, dev, true); |
734 | break; | 740 | break; |
741 | case NL80211_IFTYPE_P2P_CLIENT: | ||
735 | case NL80211_IFTYPE_STATION: | 742 | case NL80211_IFTYPE_STATION: |
736 | wdev_lock(wdev); | 743 | wdev_lock(wdev); |
737 | #ifdef CONFIG_CFG80211_WEXT | 744 | #ifdef CONFIG_CFG80211_WEXT |
@@ -804,7 +811,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
804 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 811 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
805 | list_del_rcu(&wdev->list); | 812 | list_del_rcu(&wdev->list); |
806 | rdev->devlist_generation++; | 813 | rdev->devlist_generation++; |
807 | cfg80211_mlme_purge_actions(wdev); | 814 | cfg80211_mlme_purge_registrations(wdev); |
808 | #ifdef CONFIG_CFG80211_WEXT | 815 | #ifdef CONFIG_CFG80211_WEXT |
809 | kfree(wdev->wext.keys); | 816 | kfree(wdev->wext.keys); |
810 | #endif | 817 | #endif |
@@ -910,52 +917,3 @@ static void __exit cfg80211_exit(void) | |||
910 | destroy_workqueue(cfg80211_wq); | 917 | destroy_workqueue(cfg80211_wq); |
911 | } | 918 | } |
912 | module_exit(cfg80211_exit); | 919 | module_exit(cfg80211_exit); |
913 | |||
914 | static int ___wiphy_printk(const char *level, const struct wiphy *wiphy, | ||
915 | struct va_format *vaf) | ||
916 | { | ||
917 | if (!wiphy) | ||
918 | return printk("%s(NULL wiphy *): %pV", level, vaf); | ||
919 | |||
920 | return printk("%s%s: %pV", level, wiphy_name(wiphy), vaf); | ||
921 | } | ||
922 | |||
923 | int __wiphy_printk(const char *level, const struct wiphy *wiphy, | ||
924 | const char *fmt, ...) | ||
925 | { | ||
926 | struct va_format vaf; | ||
927 | va_list args; | ||
928 | int r; | ||
929 | |||
930 | va_start(args, fmt); | ||
931 | |||
932 | vaf.fmt = fmt; | ||
933 | vaf.va = &args; | ||
934 | |||
935 | r = ___wiphy_printk(level, wiphy, &vaf); | ||
936 | va_end(args); | ||
937 | |||
938 | return r; | ||
939 | } | ||
940 | EXPORT_SYMBOL(__wiphy_printk); | ||
941 | |||
942 | #define define_wiphy_printk_level(func, kern_level) \ | ||
943 | int func(const struct wiphy *wiphy, const char *fmt, ...) \ | ||
944 | { \ | ||
945 | struct va_format vaf; \ | ||
946 | va_list args; \ | ||
947 | int r; \ | ||
948 | \ | ||
949 | va_start(args, fmt); \ | ||
950 | \ | ||
951 | vaf.fmt = fmt; \ | ||
952 | vaf.va = &args; \ | ||
953 | \ | ||
954 | r = ___wiphy_printk(kern_level, wiphy, &vaf); \ | ||
955 | va_end(args); \ | ||
956 | \ | ||
957 | return r; \ | ||
958 | } \ | ||
959 | EXPORT_SYMBOL(func); | ||
960 | |||
961 | define_wiphy_printk_level(wiphy_debug, KERN_DEBUG); | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index 63d57ae399c3..6583cca0e2ee 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -86,7 +86,7 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy) | |||
86 | static inline | 86 | static inline |
87 | bool wiphy_idx_valid(int wiphy_idx) | 87 | bool wiphy_idx_valid(int wiphy_idx) |
88 | { | 88 | { |
89 | return (wiphy_idx >= 0); | 89 | return wiphy_idx >= 0; |
90 | } | 90 | } |
91 | 91 | ||
92 | 92 | ||
@@ -95,7 +95,10 @@ extern struct mutex cfg80211_mutex; | |||
95 | extern struct list_head cfg80211_rdev_list; | 95 | extern struct list_head cfg80211_rdev_list; |
96 | extern int cfg80211_rdev_list_generation; | 96 | extern int cfg80211_rdev_list_generation; |
97 | 97 | ||
98 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) | 98 | static inline void assert_cfg80211_lock(void) |
99 | { | ||
100 | lockdep_assert_held(&cfg80211_mutex); | ||
101 | } | ||
99 | 102 | ||
100 | /* | 103 | /* |
101 | * You can use this to mark a wiphy_idx as not having an associated wiphy. | 104 | * You can use this to mark a wiphy_idx as not having an associated wiphy. |
@@ -202,8 +205,8 @@ static inline void wdev_unlock(struct wireless_dev *wdev) | |||
202 | mutex_unlock(&wdev->mtx); | 205 | mutex_unlock(&wdev->mtx); |
203 | } | 206 | } |
204 | 207 | ||
205 | #define ASSERT_RDEV_LOCK(rdev) WARN_ON(!mutex_is_locked(&(rdev)->mtx)); | 208 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) |
206 | #define ASSERT_WDEV_LOCK(wdev) WARN_ON(!mutex_is_locked(&(wdev)->mtx)); | 209 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) |
207 | 210 | ||
208 | enum cfg80211_event_type { | 211 | enum cfg80211_event_type { |
209 | EVENT_CONNECT_RESULT, | 212 | EVENT_CONNECT_RESULT, |
@@ -331,16 +334,17 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
331 | const u8 *resp_ie, size_t resp_ie_len, | 334 | const u8 *resp_ie, size_t resp_ie_len, |
332 | u16 status, bool wextev, | 335 | u16 status, bool wextev, |
333 | struct cfg80211_bss *bss); | 336 | struct cfg80211_bss *bss); |
334 | int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | 337 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, |
335 | const u8 *match_data, int match_len); | 338 | u16 frame_type, const u8 *match_data, |
336 | void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid); | 339 | int match_len); |
337 | void cfg80211_mlme_purge_actions(struct wireless_dev *wdev); | 340 | void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); |
338 | int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | 341 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); |
339 | struct net_device *dev, | 342 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
340 | struct ieee80211_channel *chan, | 343 | struct net_device *dev, |
341 | enum nl80211_channel_type channel_type, | 344 | struct ieee80211_channel *chan, |
342 | bool channel_type_valid, | 345 | enum nl80211_channel_type channel_type, |
343 | const u8 *buf, size_t len, u64 *cookie); | 346 | bool channel_type_valid, |
347 | const u8 *buf, size_t len, u64 *cookie); | ||
344 | 348 | ||
345 | /* SME */ | 349 | /* SME */ |
346 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 350 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
@@ -371,7 +375,7 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); | |||
371 | /* internal helpers */ | 375 | /* internal helpers */ |
372 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 376 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
373 | struct key_params *params, int key_idx, | 377 | struct key_params *params, int key_idx, |
374 | const u8 *mac_addr); | 378 | bool pairwise, const u8 *mac_addr); |
375 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | 379 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, |
376 | size_t ie_len, u16 reason, bool from_ap); | 380 | size_t ie_len, u16 reason, bool from_ap); |
377 | void cfg80211_sme_scan_done(struct net_device *dev); | 381 | void cfg80211_sme_scan_done(struct net_device *dev); |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 27a8ce9343c3..f33fbb79437c 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -88,6 +88,25 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
88 | if (wdev->ssid_len) | 88 | if (wdev->ssid_len) |
89 | return -EALREADY; | 89 | return -EALREADY; |
90 | 90 | ||
91 | if (!params->basic_rates) { | ||
92 | /* | ||
93 | * If no rates were explicitly configured, | ||
94 | * use the mandatory rate set for 11b or | ||
95 | * 11a for maximum compatibility. | ||
96 | */ | ||
97 | struct ieee80211_supported_band *sband = | ||
98 | rdev->wiphy.bands[params->channel->band]; | ||
99 | int j; | ||
100 | u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ? | ||
101 | IEEE80211_RATE_MANDATORY_A : | ||
102 | IEEE80211_RATE_MANDATORY_B; | ||
103 | |||
104 | for (j = 0; j < sband->n_bitrates; j++) { | ||
105 | if (sband->bitrates[j].flags & flag) | ||
106 | params->basic_rates |= BIT(j); | ||
107 | } | ||
108 | } | ||
109 | |||
91 | if (WARN_ON(wdev->connect_keys)) | 110 | if (WARN_ON(wdev->connect_keys)) |
92 | kfree(wdev->connect_keys); | 111 | kfree(wdev->connect_keys); |
93 | wdev->connect_keys = connkeys; | 112 | wdev->connect_keys = connkeys; |
@@ -141,7 +160,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
141 | */ | 160 | */ |
142 | if (rdev->ops->del_key) | 161 | if (rdev->ops->del_key) |
143 | for (i = 0; i < 6; i++) | 162 | for (i = 0; i < 6; i++) |
144 | rdev->ops->del_key(wdev->wiphy, dev, i, NULL); | 163 | rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); |
145 | 164 | ||
146 | if (wdev->current_bss) { | 165 | if (wdev->current_bss) { |
147 | cfg80211_unhold_bss(wdev->current_bss); | 166 | cfg80211_unhold_bss(wdev->current_bss); |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index d1a3fb99fdf2..26838d903b9a 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -149,7 +149,7 @@ void __cfg80211_send_deauth(struct net_device *dev, | |||
149 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 149 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
150 | const u8 *bssid = mgmt->bssid; | 150 | const u8 *bssid = mgmt->bssid; |
151 | int i; | 151 | int i; |
152 | bool found = false; | 152 | bool found = false, was_current = false; |
153 | 153 | ||
154 | ASSERT_WDEV_LOCK(wdev); | 154 | ASSERT_WDEV_LOCK(wdev); |
155 | 155 | ||
@@ -159,6 +159,7 @@ void __cfg80211_send_deauth(struct net_device *dev, | |||
159 | cfg80211_put_bss(&wdev->current_bss->pub); | 159 | cfg80211_put_bss(&wdev->current_bss->pub); |
160 | wdev->current_bss = NULL; | 160 | wdev->current_bss = NULL; |
161 | found = true; | 161 | found = true; |
162 | was_current = true; | ||
162 | } else for (i = 0; i < MAX_AUTH_BSSES; i++) { | 163 | } else for (i = 0; i < MAX_AUTH_BSSES; i++) { |
163 | if (wdev->auth_bsses[i] && | 164 | if (wdev->auth_bsses[i] && |
164 | memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { | 165 | memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { |
@@ -183,7 +184,7 @@ void __cfg80211_send_deauth(struct net_device *dev, | |||
183 | 184 | ||
184 | nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); | 185 | nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); |
185 | 186 | ||
186 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { | 187 | if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) { |
187 | u16 reason_code; | 188 | u16 reason_code; |
188 | bool from_ap; | 189 | bool from_ap; |
189 | 190 | ||
@@ -747,31 +748,53 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
747 | } | 748 | } |
748 | EXPORT_SYMBOL(cfg80211_new_sta); | 749 | EXPORT_SYMBOL(cfg80211_new_sta); |
749 | 750 | ||
750 | struct cfg80211_action_registration { | 751 | struct cfg80211_mgmt_registration { |
751 | struct list_head list; | 752 | struct list_head list; |
752 | 753 | ||
753 | u32 nlpid; | 754 | u32 nlpid; |
754 | 755 | ||
755 | int match_len; | 756 | int match_len; |
756 | 757 | ||
758 | __le16 frame_type; | ||
759 | |||
757 | u8 match[]; | 760 | u8 match[]; |
758 | }; | 761 | }; |
759 | 762 | ||
760 | int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | 763 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, |
761 | const u8 *match_data, int match_len) | 764 | u16 frame_type, const u8 *match_data, |
765 | int match_len) | ||
762 | { | 766 | { |
763 | struct cfg80211_action_registration *reg, *nreg; | 767 | struct wiphy *wiphy = wdev->wiphy; |
768 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
769 | struct cfg80211_mgmt_registration *reg, *nreg; | ||
764 | int err = 0; | 770 | int err = 0; |
771 | u16 mgmt_type; | ||
772 | |||
773 | if (!wdev->wiphy->mgmt_stypes) | ||
774 | return -EOPNOTSUPP; | ||
775 | |||
776 | if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) | ||
777 | return -EINVAL; | ||
778 | |||
779 | if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) | ||
780 | return -EINVAL; | ||
781 | |||
782 | mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; | ||
783 | if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) | ||
784 | return -EINVAL; | ||
765 | 785 | ||
766 | nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); | 786 | nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); |
767 | if (!nreg) | 787 | if (!nreg) |
768 | return -ENOMEM; | 788 | return -ENOMEM; |
769 | 789 | ||
770 | spin_lock_bh(&wdev->action_registrations_lock); | 790 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
771 | 791 | ||
772 | list_for_each_entry(reg, &wdev->action_registrations, list) { | 792 | list_for_each_entry(reg, &wdev->mgmt_registrations, list) { |
773 | int mlen = min(match_len, reg->match_len); | 793 | int mlen = min(match_len, reg->match_len); |
774 | 794 | ||
795 | if (frame_type != le16_to_cpu(reg->frame_type)) | ||
796 | continue; | ||
797 | |||
775 | if (memcmp(reg->match, match_data, mlen) == 0) { | 798 | if (memcmp(reg->match, match_data, mlen) == 0) { |
776 | err = -EALREADY; | 799 | err = -EALREADY; |
777 | break; | 800 | break; |
@@ -786,140 +809,212 @@ int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | |||
786 | memcpy(nreg->match, match_data, match_len); | 809 | memcpy(nreg->match, match_data, match_len); |
787 | nreg->match_len = match_len; | 810 | nreg->match_len = match_len; |
788 | nreg->nlpid = snd_pid; | 811 | nreg->nlpid = snd_pid; |
789 | list_add(&nreg->list, &wdev->action_registrations); | 812 | nreg->frame_type = cpu_to_le16(frame_type); |
813 | list_add(&nreg->list, &wdev->mgmt_registrations); | ||
814 | |||
815 | if (rdev->ops->mgmt_frame_register) | ||
816 | rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, | ||
817 | frame_type, true); | ||
790 | 818 | ||
791 | out: | 819 | out: |
792 | spin_unlock_bh(&wdev->action_registrations_lock); | 820 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
821 | |||
793 | return err; | 822 | return err; |
794 | } | 823 | } |
795 | 824 | ||
796 | void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid) | 825 | void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid) |
797 | { | 826 | { |
798 | struct cfg80211_action_registration *reg, *tmp; | 827 | struct wiphy *wiphy = wdev->wiphy; |
828 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
829 | struct cfg80211_mgmt_registration *reg, *tmp; | ||
799 | 830 | ||
800 | spin_lock_bh(&wdev->action_registrations_lock); | 831 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
801 | 832 | ||
802 | list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { | 833 | list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
803 | if (reg->nlpid == nlpid) { | 834 | if (reg->nlpid != nlpid) |
804 | list_del(®->list); | 835 | continue; |
805 | kfree(reg); | 836 | |
837 | if (rdev->ops->mgmt_frame_register) { | ||
838 | u16 frame_type = le16_to_cpu(reg->frame_type); | ||
839 | |||
840 | rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, | ||
841 | frame_type, false); | ||
806 | } | 842 | } |
843 | |||
844 | list_del(®->list); | ||
845 | kfree(reg); | ||
807 | } | 846 | } |
808 | 847 | ||
809 | spin_unlock_bh(&wdev->action_registrations_lock); | 848 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
810 | } | 849 | } |
811 | 850 | ||
812 | void cfg80211_mlme_purge_actions(struct wireless_dev *wdev) | 851 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) |
813 | { | 852 | { |
814 | struct cfg80211_action_registration *reg, *tmp; | 853 | struct cfg80211_mgmt_registration *reg, *tmp; |
815 | 854 | ||
816 | spin_lock_bh(&wdev->action_registrations_lock); | 855 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
817 | 856 | ||
818 | list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { | 857 | list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
819 | list_del(®->list); | 858 | list_del(®->list); |
820 | kfree(reg); | 859 | kfree(reg); |
821 | } | 860 | } |
822 | 861 | ||
823 | spin_unlock_bh(&wdev->action_registrations_lock); | 862 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
824 | } | 863 | } |
825 | 864 | ||
826 | int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | 865 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
827 | struct net_device *dev, | 866 | struct net_device *dev, |
828 | struct ieee80211_channel *chan, | 867 | struct ieee80211_channel *chan, |
829 | enum nl80211_channel_type channel_type, | 868 | enum nl80211_channel_type channel_type, |
830 | bool channel_type_valid, | 869 | bool channel_type_valid, |
831 | const u8 *buf, size_t len, u64 *cookie) | 870 | const u8 *buf, size_t len, u64 *cookie) |
832 | { | 871 | { |
833 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 872 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
834 | const struct ieee80211_mgmt *mgmt; | 873 | const struct ieee80211_mgmt *mgmt; |
874 | u16 stype; | ||
835 | 875 | ||
836 | if (rdev->ops->action == NULL) | 876 | if (!wdev->wiphy->mgmt_stypes) |
837 | return -EOPNOTSUPP; | 877 | return -EOPNOTSUPP; |
878 | |||
879 | if (!rdev->ops->mgmt_tx) | ||
880 | return -EOPNOTSUPP; | ||
881 | |||
838 | if (len < 24 + 1) | 882 | if (len < 24 + 1) |
839 | return -EINVAL; | 883 | return -EINVAL; |
840 | 884 | ||
841 | mgmt = (const struct ieee80211_mgmt *) buf; | 885 | mgmt = (const struct ieee80211_mgmt *) buf; |
842 | if (!ieee80211_is_action(mgmt->frame_control)) | 886 | |
887 | if (!ieee80211_is_mgmt(mgmt->frame_control)) | ||
843 | return -EINVAL; | 888 | return -EINVAL; |
844 | if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { | 889 | |
845 | /* Verify that we are associated with the destination AP */ | 890 | stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; |
891 | if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4))) | ||
892 | return -EINVAL; | ||
893 | |||
894 | if (ieee80211_is_action(mgmt->frame_control) && | ||
895 | mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { | ||
896 | int err = 0; | ||
897 | |||
846 | wdev_lock(wdev); | 898 | wdev_lock(wdev); |
847 | 899 | ||
848 | if (!wdev->current_bss || | 900 | switch (wdev->iftype) { |
849 | memcmp(wdev->current_bss->pub.bssid, mgmt->bssid, | 901 | case NL80211_IFTYPE_ADHOC: |
850 | ETH_ALEN) != 0 || | 902 | case NL80211_IFTYPE_STATION: |
851 | (wdev->iftype == NL80211_IFTYPE_STATION && | 903 | case NL80211_IFTYPE_P2P_CLIENT: |
852 | memcmp(wdev->current_bss->pub.bssid, mgmt->da, | 904 | if (!wdev->current_bss) { |
853 | ETH_ALEN) != 0)) { | 905 | err = -ENOTCONN; |
854 | wdev_unlock(wdev); | 906 | break; |
855 | return -ENOTCONN; | 907 | } |
856 | } | 908 | |
909 | if (memcmp(wdev->current_bss->pub.bssid, | ||
910 | mgmt->bssid, ETH_ALEN)) { | ||
911 | err = -ENOTCONN; | ||
912 | break; | ||
913 | } | ||
914 | |||
915 | /* | ||
916 | * check for IBSS DA must be done by driver as | ||
917 | * cfg80211 doesn't track the stations | ||
918 | */ | ||
919 | if (wdev->iftype == NL80211_IFTYPE_ADHOC) | ||
920 | break; | ||
857 | 921 | ||
922 | /* for station, check that DA is the AP */ | ||
923 | if (memcmp(wdev->current_bss->pub.bssid, | ||
924 | mgmt->da, ETH_ALEN)) { | ||
925 | err = -ENOTCONN; | ||
926 | break; | ||
927 | } | ||
928 | break; | ||
929 | case NL80211_IFTYPE_AP: | ||
930 | case NL80211_IFTYPE_P2P_GO: | ||
931 | case NL80211_IFTYPE_AP_VLAN: | ||
932 | if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN)) | ||
933 | err = -EINVAL; | ||
934 | break; | ||
935 | default: | ||
936 | err = -EOPNOTSUPP; | ||
937 | break; | ||
938 | } | ||
858 | wdev_unlock(wdev); | 939 | wdev_unlock(wdev); |
940 | |||
941 | if (err) | ||
942 | return err; | ||
859 | } | 943 | } |
860 | 944 | ||
861 | if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) | 945 | if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) |
862 | return -EINVAL; | 946 | return -EINVAL; |
863 | 947 | ||
864 | /* Transmit the Action frame as requested by user space */ | 948 | /* Transmit the Action frame as requested by user space */ |
865 | return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type, | 949 | return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, channel_type, |
866 | channel_type_valid, buf, len, cookie); | 950 | channel_type_valid, buf, len, cookie); |
867 | } | 951 | } |
868 | 952 | ||
869 | bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, | 953 | bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, |
870 | size_t len, gfp_t gfp) | 954 | size_t len, gfp_t gfp) |
871 | { | 955 | { |
872 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 956 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
873 | struct wiphy *wiphy = wdev->wiphy; | 957 | struct wiphy *wiphy = wdev->wiphy; |
874 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 958 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
875 | struct cfg80211_action_registration *reg; | 959 | struct cfg80211_mgmt_registration *reg; |
876 | const u8 *action_data; | 960 | const struct ieee80211_txrx_stypes *stypes = |
877 | int action_data_len; | 961 | &wiphy->mgmt_stypes[wdev->iftype]; |
962 | struct ieee80211_mgmt *mgmt = (void *)buf; | ||
963 | const u8 *data; | ||
964 | int data_len; | ||
878 | bool result = false; | 965 | bool result = false; |
966 | __le16 ftype = mgmt->frame_control & | ||
967 | cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); | ||
968 | u16 stype; | ||
879 | 969 | ||
880 | /* frame length - min size excluding category */ | 970 | stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4; |
881 | action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1); | ||
882 | 971 | ||
883 | /* action data starts with category */ | 972 | if (!(stypes->rx & BIT(stype))) |
884 | action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1; | 973 | return false; |
885 | 974 | ||
886 | spin_lock_bh(&wdev->action_registrations_lock); | 975 | data = buf + ieee80211_hdrlen(mgmt->frame_control); |
976 | data_len = len - ieee80211_hdrlen(mgmt->frame_control); | ||
977 | |||
978 | spin_lock_bh(&wdev->mgmt_registrations_lock); | ||
979 | |||
980 | list_for_each_entry(reg, &wdev->mgmt_registrations, list) { | ||
981 | if (reg->frame_type != ftype) | ||
982 | continue; | ||
887 | 983 | ||
888 | list_for_each_entry(reg, &wdev->action_registrations, list) { | 984 | if (reg->match_len > data_len) |
889 | if (reg->match_len > action_data_len) | ||
890 | continue; | 985 | continue; |
891 | 986 | ||
892 | if (memcmp(reg->match, action_data, reg->match_len)) | 987 | if (memcmp(reg->match, data, reg->match_len)) |
893 | continue; | 988 | continue; |
894 | 989 | ||
895 | /* found match! */ | 990 | /* found match! */ |
896 | 991 | ||
897 | /* Indicate the received Action frame to user space */ | 992 | /* Indicate the received Action frame to user space */ |
898 | if (nl80211_send_action(rdev, dev, reg->nlpid, freq, | 993 | if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq, |
899 | buf, len, gfp)) | 994 | buf, len, gfp)) |
900 | continue; | 995 | continue; |
901 | 996 | ||
902 | result = true; | 997 | result = true; |
903 | break; | 998 | break; |
904 | } | 999 | } |
905 | 1000 | ||
906 | spin_unlock_bh(&wdev->action_registrations_lock); | 1001 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
907 | 1002 | ||
908 | return result; | 1003 | return result; |
909 | } | 1004 | } |
910 | EXPORT_SYMBOL(cfg80211_rx_action); | 1005 | EXPORT_SYMBOL(cfg80211_rx_mgmt); |
911 | 1006 | ||
912 | void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, | 1007 | void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, |
913 | const u8 *buf, size_t len, bool ack, gfp_t gfp) | 1008 | const u8 *buf, size_t len, bool ack, gfp_t gfp) |
914 | { | 1009 | { |
915 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1010 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
916 | struct wiphy *wiphy = wdev->wiphy; | 1011 | struct wiphy *wiphy = wdev->wiphy; |
917 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 1012 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
918 | 1013 | ||
919 | /* Indicate TX status of the Action frame to user space */ | 1014 | /* Indicate TX status of the Action frame to user space */ |
920 | nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp); | 1015 | nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp); |
921 | } | 1016 | } |
922 | EXPORT_SYMBOL(cfg80211_action_tx_status); | 1017 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); |
923 | 1018 | ||
924 | void cfg80211_cqm_rssi_notify(struct net_device *dev, | 1019 | void cfg80211_cqm_rssi_notify(struct net_device *dev, |
925 | enum nl80211_cqm_rssi_threshold_event rssi_event, | 1020 | enum nl80211_cqm_rssi_threshold_event rssi_event, |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 37902a54e9c1..c506241f8637 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -23,6 +23,11 @@ | |||
23 | #include "nl80211.h" | 23 | #include "nl80211.h" |
24 | #include "reg.h" | 24 | #include "reg.h" |
25 | 25 | ||
26 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
27 | struct genl_info *info); | ||
28 | static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
29 | struct genl_info *info); | ||
30 | |||
26 | /* the netlink family */ | 31 | /* the netlink family */ |
27 | static struct genl_family nl80211_fam = { | 32 | static struct genl_family nl80211_fam = { |
28 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ | 33 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ |
@@ -31,6 +36,8 @@ static struct genl_family nl80211_fam = { | |||
31 | .version = 1, /* no particular meaning now */ | 36 | .version = 1, /* no particular meaning now */ |
32 | .maxattr = NL80211_ATTR_MAX, | 37 | .maxattr = NL80211_ATTR_MAX, |
33 | .netnsok = true, | 38 | .netnsok = true, |
39 | .pre_doit = nl80211_pre_doit, | ||
40 | .post_doit = nl80211_post_doit, | ||
34 | }; | 41 | }; |
35 | 42 | ||
36 | /* internal helper: get rdev and dev */ | 43 | /* internal helper: get rdev and dev */ |
@@ -86,6 +93,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
86 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, | 93 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, |
87 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, | 94 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, |
88 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 95 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, |
96 | [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 }, | ||
89 | 97 | ||
90 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, | 98 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, |
91 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, | 99 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, |
@@ -136,6 +144,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
136 | .len = sizeof(struct nl80211_sta_flag_update), | 144 | .len = sizeof(struct nl80211_sta_flag_update), |
137 | }, | 145 | }, |
138 | [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, | 146 | [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, |
147 | [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 }, | ||
148 | [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG }, | ||
139 | [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, | 149 | [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, |
140 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, | 150 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, |
141 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, | 151 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, |
@@ -156,9 +166,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
156 | 166 | ||
157 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, | 167 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, |
158 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, | 168 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, |
169 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, | ||
159 | }; | 170 | }; |
160 | 171 | ||
161 | /* policy for the attributes */ | 172 | /* policy for the key attributes */ |
162 | static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | 173 | static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { |
163 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, | 174 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, |
164 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, | 175 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, |
@@ -166,6 +177,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | |||
166 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 177 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, |
167 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, | 178 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, |
168 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | 179 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, |
180 | [NL80211_KEY_TYPE] = { .type = NLA_U32 }, | ||
169 | }; | 181 | }; |
170 | 182 | ||
171 | /* ifidx get helper */ | 183 | /* ifidx get helper */ |
@@ -188,6 +200,47 @@ static int nl80211_get_ifidx(struct netlink_callback *cb) | |||
188 | return res; | 200 | return res; |
189 | } | 201 | } |
190 | 202 | ||
203 | static int nl80211_prepare_netdev_dump(struct sk_buff *skb, | ||
204 | struct netlink_callback *cb, | ||
205 | struct cfg80211_registered_device **rdev, | ||
206 | struct net_device **dev) | ||
207 | { | ||
208 | int ifidx = cb->args[0]; | ||
209 | int err; | ||
210 | |||
211 | if (!ifidx) | ||
212 | ifidx = nl80211_get_ifidx(cb); | ||
213 | if (ifidx < 0) | ||
214 | return ifidx; | ||
215 | |||
216 | cb->args[0] = ifidx; | ||
217 | |||
218 | rtnl_lock(); | ||
219 | |||
220 | *dev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
221 | if (!*dev) { | ||
222 | err = -ENODEV; | ||
223 | goto out_rtnl; | ||
224 | } | ||
225 | |||
226 | *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
227 | if (IS_ERR(dev)) { | ||
228 | err = PTR_ERR(dev); | ||
229 | goto out_rtnl; | ||
230 | } | ||
231 | |||
232 | return 0; | ||
233 | out_rtnl: | ||
234 | rtnl_unlock(); | ||
235 | return err; | ||
236 | } | ||
237 | |||
238 | static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) | ||
239 | { | ||
240 | cfg80211_unlock_rdev(rdev); | ||
241 | rtnl_unlock(); | ||
242 | } | ||
243 | |||
191 | /* IE validation */ | 244 | /* IE validation */ |
192 | static bool is_valid_ie_attr(const struct nlattr *attr) | 245 | static bool is_valid_ie_attr(const struct nlattr *attr) |
193 | { | 246 | { |
@@ -255,6 +308,7 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
255 | struct key_parse { | 308 | struct key_parse { |
256 | struct key_params p; | 309 | struct key_params p; |
257 | int idx; | 310 | int idx; |
311 | int type; | ||
258 | bool def, defmgmt; | 312 | bool def, defmgmt; |
259 | }; | 313 | }; |
260 | 314 | ||
@@ -285,6 +339,12 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | |||
285 | if (tb[NL80211_KEY_CIPHER]) | 339 | if (tb[NL80211_KEY_CIPHER]) |
286 | k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); | 340 | k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); |
287 | 341 | ||
342 | if (tb[NL80211_KEY_TYPE]) { | ||
343 | k->type = nla_get_u32(tb[NL80211_KEY_TYPE]); | ||
344 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
288 | return 0; | 348 | return 0; |
289 | } | 349 | } |
290 | 350 | ||
@@ -309,6 +369,12 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) | |||
309 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; | 369 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; |
310 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; | 370 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; |
311 | 371 | ||
372 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { | ||
373 | k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); | ||
374 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) | ||
375 | return -EINVAL; | ||
376 | } | ||
377 | |||
312 | return 0; | 378 | return 0; |
313 | } | 379 | } |
314 | 380 | ||
@@ -318,6 +384,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) | |||
318 | 384 | ||
319 | memset(k, 0, sizeof(*k)); | 385 | memset(k, 0, sizeof(*k)); |
320 | k->idx = -1; | 386 | k->idx = -1; |
387 | k->type = -1; | ||
321 | 388 | ||
322 | if (info->attrs[NL80211_ATTR_KEY]) | 389 | if (info->attrs[NL80211_ATTR_KEY]) |
323 | err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); | 390 | err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); |
@@ -382,7 +449,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, | |||
382 | } else if (parse.defmgmt) | 449 | } else if (parse.defmgmt) |
383 | goto error; | 450 | goto error; |
384 | err = cfg80211_validate_key_settings(rdev, &parse.p, | 451 | err = cfg80211_validate_key_settings(rdev, &parse.p, |
385 | parse.idx, NULL); | 452 | parse.idx, false, NULL); |
386 | if (err) | 453 | if (err) |
387 | goto error; | 454 | goto error; |
388 | result->params[parse.idx].cipher = parse.p.cipher; | 455 | result->params[parse.idx].cipher = parse.p.cipher; |
@@ -401,18 +468,17 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
401 | { | 468 | { |
402 | ASSERT_WDEV_LOCK(wdev); | 469 | ASSERT_WDEV_LOCK(wdev); |
403 | 470 | ||
404 | if (!netif_running(wdev->netdev)) | ||
405 | return -ENETDOWN; | ||
406 | |||
407 | switch (wdev->iftype) { | 471 | switch (wdev->iftype) { |
408 | case NL80211_IFTYPE_AP: | 472 | case NL80211_IFTYPE_AP: |
409 | case NL80211_IFTYPE_AP_VLAN: | 473 | case NL80211_IFTYPE_AP_VLAN: |
474 | case NL80211_IFTYPE_P2P_GO: | ||
410 | break; | 475 | break; |
411 | case NL80211_IFTYPE_ADHOC: | 476 | case NL80211_IFTYPE_ADHOC: |
412 | if (!wdev->current_bss) | 477 | if (!wdev->current_bss) |
413 | return -ENOLINK; | 478 | return -ENOLINK; |
414 | break; | 479 | break; |
415 | case NL80211_IFTYPE_STATION: | 480 | case NL80211_IFTYPE_STATION: |
481 | case NL80211_IFTYPE_P2P_CLIENT: | ||
416 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 482 | if (wdev->sme_state != CFG80211_SME_CONNECTED) |
417 | return -ENOLINK; | 483 | return -ENOLINK; |
418 | break; | 484 | break; |
@@ -437,6 +503,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
437 | struct ieee80211_rate *rate; | 503 | struct ieee80211_rate *rate; |
438 | int i; | 504 | int i; |
439 | u16 ifmodes = dev->wiphy.interface_modes; | 505 | u16 ifmodes = dev->wiphy.interface_modes; |
506 | const struct ieee80211_txrx_stypes *mgmt_stypes = | ||
507 | dev->wiphy.mgmt_stypes; | ||
440 | 508 | ||
441 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); | 509 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); |
442 | if (!hdr) | 510 | if (!hdr) |
@@ -464,6 +532,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
464 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | 532 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, |
465 | dev->wiphy.max_scan_ie_len); | 533 | dev->wiphy.max_scan_ie_len); |
466 | 534 | ||
535 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) | ||
536 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); | ||
537 | |||
467 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, | 538 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, |
468 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 539 | sizeof(u32) * dev->wiphy.n_cipher_suites, |
469 | dev->wiphy.cipher_suites); | 540 | dev->wiphy.cipher_suites); |
@@ -471,6 +542,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
471 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, | 542 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, |
472 | dev->wiphy.max_num_pmkids); | 543 | dev->wiphy.max_num_pmkids); |
473 | 544 | ||
545 | if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) | ||
546 | NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE); | ||
547 | |||
474 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 548 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); |
475 | if (!nl_modes) | 549 | if (!nl_modes) |
476 | goto nla_put_failure; | 550 | goto nla_put_failure; |
@@ -587,12 +661,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
587 | CMD(flush_pmksa, FLUSH_PMKSA); | 661 | CMD(flush_pmksa, FLUSH_PMKSA); |
588 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | 662 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); |
589 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | 663 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); |
590 | CMD(action, ACTION); | 664 | CMD(mgmt_tx, FRAME); |
591 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | 665 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { |
592 | i++; | 666 | i++; |
593 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 667 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
594 | } | 668 | } |
595 | CMD(set_channel, SET_CHANNEL); | 669 | CMD(set_channel, SET_CHANNEL); |
670 | CMD(set_wds_peer, SET_WDS_PEER); | ||
596 | 671 | ||
597 | #undef CMD | 672 | #undef CMD |
598 | 673 | ||
@@ -608,6 +683,55 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
608 | 683 | ||
609 | nla_nest_end(msg, nl_cmds); | 684 | nla_nest_end(msg, nl_cmds); |
610 | 685 | ||
686 | if (mgmt_stypes) { | ||
687 | u16 stypes; | ||
688 | struct nlattr *nl_ftypes, *nl_ifs; | ||
689 | enum nl80211_iftype ift; | ||
690 | |||
691 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); | ||
692 | if (!nl_ifs) | ||
693 | goto nla_put_failure; | ||
694 | |||
695 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | ||
696 | nl_ftypes = nla_nest_start(msg, ift); | ||
697 | if (!nl_ftypes) | ||
698 | goto nla_put_failure; | ||
699 | i = 0; | ||
700 | stypes = mgmt_stypes[ift].tx; | ||
701 | while (stypes) { | ||
702 | if (stypes & 1) | ||
703 | NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, | ||
704 | (i << 4) | IEEE80211_FTYPE_MGMT); | ||
705 | stypes >>= 1; | ||
706 | i++; | ||
707 | } | ||
708 | nla_nest_end(msg, nl_ftypes); | ||
709 | } | ||
710 | |||
711 | nla_nest_end(msg, nl_ifs); | ||
712 | |||
713 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); | ||
714 | if (!nl_ifs) | ||
715 | goto nla_put_failure; | ||
716 | |||
717 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | ||
718 | nl_ftypes = nla_nest_start(msg, ift); | ||
719 | if (!nl_ftypes) | ||
720 | goto nla_put_failure; | ||
721 | i = 0; | ||
722 | stypes = mgmt_stypes[ift].rx; | ||
723 | while (stypes) { | ||
724 | if (stypes & 1) | ||
725 | NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, | ||
726 | (i << 4) | IEEE80211_FTYPE_MGMT); | ||
727 | stypes >>= 1; | ||
728 | i++; | ||
729 | } | ||
730 | nla_nest_end(msg, nl_ftypes); | ||
731 | } | ||
732 | nla_nest_end(msg, nl_ifs); | ||
733 | } | ||
734 | |||
611 | return genlmsg_end(msg, hdr); | 735 | return genlmsg_end(msg, hdr); |
612 | 736 | ||
613 | nla_put_failure: | 737 | nla_put_failure: |
@@ -644,28 +768,18 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
644 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | 768 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) |
645 | { | 769 | { |
646 | struct sk_buff *msg; | 770 | struct sk_buff *msg; |
647 | struct cfg80211_registered_device *dev; | 771 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
648 | |||
649 | dev = cfg80211_get_dev_from_info(info); | ||
650 | if (IS_ERR(dev)) | ||
651 | return PTR_ERR(dev); | ||
652 | 772 | ||
653 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 773 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
654 | if (!msg) | 774 | if (!msg) |
655 | goto out_err; | 775 | return -ENOMEM; |
656 | |||
657 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) | ||
658 | goto out_free; | ||
659 | 776 | ||
660 | cfg80211_unlock_rdev(dev); | 777 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) { |
778 | nlmsg_free(msg); | ||
779 | return -ENOBUFS; | ||
780 | } | ||
661 | 781 | ||
662 | return genlmsg_reply(msg, info); | 782 | return genlmsg_reply(msg, info); |
663 | |||
664 | out_free: | ||
665 | nlmsg_free(msg); | ||
666 | out_err: | ||
667 | cfg80211_unlock_rdev(dev); | ||
668 | return -ENOBUFS; | ||
669 | } | 783 | } |
670 | 784 | ||
671 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { | 785 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { |
@@ -709,7 +823,8 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) | |||
709 | wdev->iftype == NL80211_IFTYPE_AP || | 823 | wdev->iftype == NL80211_IFTYPE_AP || |
710 | wdev->iftype == NL80211_IFTYPE_WDS || | 824 | wdev->iftype == NL80211_IFTYPE_WDS || |
711 | wdev->iftype == NL80211_IFTYPE_MESH_POINT || | 825 | wdev->iftype == NL80211_IFTYPE_MESH_POINT || |
712 | wdev->iftype == NL80211_IFTYPE_MONITOR; | 826 | wdev->iftype == NL80211_IFTYPE_MONITOR || |
827 | wdev->iftype == NL80211_IFTYPE_P2P_GO; | ||
713 | } | 828 | } |
714 | 829 | ||
715 | static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | 830 | static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, |
@@ -753,38 +868,48 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
753 | 868 | ||
754 | static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) | 869 | static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) |
755 | { | 870 | { |
756 | struct cfg80211_registered_device *rdev; | 871 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
757 | struct net_device *netdev; | 872 | struct net_device *netdev = info->user_ptr[1]; |
758 | int result; | ||
759 | 873 | ||
760 | rtnl_lock(); | 874 | return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); |
875 | } | ||
761 | 876 | ||
762 | result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev); | 877 | static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) |
763 | if (result) | 878 | { |
764 | goto unlock; | 879 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
880 | struct net_device *dev = info->user_ptr[1]; | ||
881 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
882 | const u8 *bssid; | ||
765 | 883 | ||
766 | result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); | 884 | if (!info->attrs[NL80211_ATTR_MAC]) |
885 | return -EINVAL; | ||
767 | 886 | ||
768 | unlock: | 887 | if (netif_running(dev)) |
769 | rtnl_unlock(); | 888 | return -EBUSY; |
770 | 889 | ||
771 | return result; | 890 | if (!rdev->ops->set_wds_peer) |
891 | return -EOPNOTSUPP; | ||
892 | |||
893 | if (wdev->iftype != NL80211_IFTYPE_WDS) | ||
894 | return -EOPNOTSUPP; | ||
895 | |||
896 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
897 | return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); | ||
772 | } | 898 | } |
773 | 899 | ||
900 | |||
774 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | 901 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) |
775 | { | 902 | { |
776 | struct cfg80211_registered_device *rdev; | 903 | struct cfg80211_registered_device *rdev; |
777 | struct net_device *netdev = NULL; | 904 | struct net_device *netdev = NULL; |
778 | struct wireless_dev *wdev; | 905 | struct wireless_dev *wdev; |
779 | int result, rem_txq_params = 0; | 906 | int result = 0, rem_txq_params = 0; |
780 | struct nlattr *nl_txq_params; | 907 | struct nlattr *nl_txq_params; |
781 | u32 changed; | 908 | u32 changed; |
782 | u8 retry_short = 0, retry_long = 0; | 909 | u8 retry_short = 0, retry_long = 0; |
783 | u32 frag_threshold = 0, rts_threshold = 0; | 910 | u32 frag_threshold = 0, rts_threshold = 0; |
784 | u8 coverage_class = 0; | 911 | u8 coverage_class = 0; |
785 | 912 | ||
786 | rtnl_lock(); | ||
787 | |||
788 | /* | 913 | /* |
789 | * Try to find the wiphy and netdev. Normally this | 914 | * Try to find the wiphy and netdev. Normally this |
790 | * function shouldn't need the netdev, but this is | 915 | * function shouldn't need the netdev, but this is |
@@ -811,8 +936,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
811 | rdev = __cfg80211_rdev_from_info(info); | 936 | rdev = __cfg80211_rdev_from_info(info); |
812 | if (IS_ERR(rdev)) { | 937 | if (IS_ERR(rdev)) { |
813 | mutex_unlock(&cfg80211_mutex); | 938 | mutex_unlock(&cfg80211_mutex); |
814 | result = PTR_ERR(rdev); | 939 | return PTR_ERR(rdev); |
815 | goto unlock; | ||
816 | } | 940 | } |
817 | wdev = NULL; | 941 | wdev = NULL; |
818 | netdev = NULL; | 942 | netdev = NULL; |
@@ -994,8 +1118,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
994 | mutex_unlock(&rdev->mtx); | 1118 | mutex_unlock(&rdev->mtx); |
995 | if (netdev) | 1119 | if (netdev) |
996 | dev_put(netdev); | 1120 | dev_put(netdev); |
997 | unlock: | ||
998 | rtnl_unlock(); | ||
999 | return result; | 1121 | return result; |
1000 | } | 1122 | } |
1001 | 1123 | ||
@@ -1075,33 +1197,20 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
1075 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | 1197 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) |
1076 | { | 1198 | { |
1077 | struct sk_buff *msg; | 1199 | struct sk_buff *msg; |
1078 | struct cfg80211_registered_device *dev; | 1200 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1079 | struct net_device *netdev; | 1201 | struct net_device *netdev = info->user_ptr[1]; |
1080 | int err; | ||
1081 | |||
1082 | err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); | ||
1083 | if (err) | ||
1084 | return err; | ||
1085 | 1202 | ||
1086 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1203 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1087 | if (!msg) | 1204 | if (!msg) |
1088 | goto out_err; | 1205 | return -ENOMEM; |
1089 | 1206 | ||
1090 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, | 1207 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
1091 | dev, netdev) < 0) | 1208 | dev, netdev) < 0) { |
1092 | goto out_free; | 1209 | nlmsg_free(msg); |
1093 | 1210 | return -ENOBUFS; | |
1094 | dev_put(netdev); | 1211 | } |
1095 | cfg80211_unlock_rdev(dev); | ||
1096 | 1212 | ||
1097 | return genlmsg_reply(msg, info); | 1213 | return genlmsg_reply(msg, info); |
1098 | |||
1099 | out_free: | ||
1100 | nlmsg_free(msg); | ||
1101 | out_err: | ||
1102 | dev_put(netdev); | ||
1103 | cfg80211_unlock_rdev(dev); | ||
1104 | return -ENOBUFS; | ||
1105 | } | 1214 | } |
1106 | 1215 | ||
1107 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { | 1216 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { |
@@ -1161,39 +1270,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, | |||
1161 | 1270 | ||
1162 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | 1271 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) |
1163 | { | 1272 | { |
1164 | struct cfg80211_registered_device *rdev; | 1273 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1165 | struct vif_params params; | 1274 | struct vif_params params; |
1166 | int err; | 1275 | int err; |
1167 | enum nl80211_iftype otype, ntype; | 1276 | enum nl80211_iftype otype, ntype; |
1168 | struct net_device *dev; | 1277 | struct net_device *dev = info->user_ptr[1]; |
1169 | u32 _flags, *flags = NULL; | 1278 | u32 _flags, *flags = NULL; |
1170 | bool change = false; | 1279 | bool change = false; |
1171 | 1280 | ||
1172 | memset(¶ms, 0, sizeof(params)); | 1281 | memset(¶ms, 0, sizeof(params)); |
1173 | 1282 | ||
1174 | rtnl_lock(); | ||
1175 | |||
1176 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1177 | if (err) | ||
1178 | goto unlock_rtnl; | ||
1179 | |||
1180 | otype = ntype = dev->ieee80211_ptr->iftype; | 1283 | otype = ntype = dev->ieee80211_ptr->iftype; |
1181 | 1284 | ||
1182 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 1285 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
1183 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 1286 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
1184 | if (otype != ntype) | 1287 | if (otype != ntype) |
1185 | change = true; | 1288 | change = true; |
1186 | if (ntype > NL80211_IFTYPE_MAX) { | 1289 | if (ntype > NL80211_IFTYPE_MAX) |
1187 | err = -EINVAL; | 1290 | return -EINVAL; |
1188 | goto unlock; | ||
1189 | } | ||
1190 | } | 1291 | } |
1191 | 1292 | ||
1192 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 1293 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
1193 | if (ntype != NL80211_IFTYPE_MESH_POINT) { | 1294 | if (ntype != NL80211_IFTYPE_MESH_POINT) |
1194 | err = -EINVAL; | 1295 | return -EINVAL; |
1195 | goto unlock; | ||
1196 | } | ||
1197 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 1296 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
1198 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 1297 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
1199 | change = true; | 1298 | change = true; |
@@ -1204,20 +1303,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1204 | change = true; | 1303 | change = true; |
1205 | err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); | 1304 | err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); |
1206 | if (err) | 1305 | if (err) |
1207 | goto unlock; | 1306 | return err; |
1208 | } else { | 1307 | } else { |
1209 | params.use_4addr = -1; | 1308 | params.use_4addr = -1; |
1210 | } | 1309 | } |
1211 | 1310 | ||
1212 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 1311 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
1213 | if (ntype != NL80211_IFTYPE_MONITOR) { | 1312 | if (ntype != NL80211_IFTYPE_MONITOR) |
1214 | err = -EINVAL; | 1313 | return -EINVAL; |
1215 | goto unlock; | ||
1216 | } | ||
1217 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], | 1314 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], |
1218 | &_flags); | 1315 | &_flags); |
1219 | if (err) | 1316 | if (err) |
1220 | goto unlock; | 1317 | return err; |
1221 | 1318 | ||
1222 | flags = &_flags; | 1319 | flags = &_flags; |
1223 | change = true; | 1320 | change = true; |
@@ -1231,17 +1328,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1231 | if (!err && params.use_4addr != -1) | 1328 | if (!err && params.use_4addr != -1) |
1232 | dev->ieee80211_ptr->use_4addr = params.use_4addr; | 1329 | dev->ieee80211_ptr->use_4addr = params.use_4addr; |
1233 | 1330 | ||
1234 | unlock: | ||
1235 | dev_put(dev); | ||
1236 | cfg80211_unlock_rdev(rdev); | ||
1237 | unlock_rtnl: | ||
1238 | rtnl_unlock(); | ||
1239 | return err; | 1331 | return err; |
1240 | } | 1332 | } |
1241 | 1333 | ||
1242 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | 1334 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) |
1243 | { | 1335 | { |
1244 | struct cfg80211_registered_device *rdev; | 1336 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1245 | struct vif_params params; | 1337 | struct vif_params params; |
1246 | int err; | 1338 | int err; |
1247 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 1339 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
@@ -1258,19 +1350,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1258 | return -EINVAL; | 1350 | return -EINVAL; |
1259 | } | 1351 | } |
1260 | 1352 | ||
1261 | rtnl_lock(); | ||
1262 | |||
1263 | rdev = cfg80211_get_dev_from_info(info); | ||
1264 | if (IS_ERR(rdev)) { | ||
1265 | err = PTR_ERR(rdev); | ||
1266 | goto unlock_rtnl; | ||
1267 | } | ||
1268 | |||
1269 | if (!rdev->ops->add_virtual_intf || | 1353 | if (!rdev->ops->add_virtual_intf || |
1270 | !(rdev->wiphy.interface_modes & (1 << type))) { | 1354 | !(rdev->wiphy.interface_modes & (1 << type))) |
1271 | err = -EOPNOTSUPP; | 1355 | return -EOPNOTSUPP; |
1272 | goto unlock; | ||
1273 | } | ||
1274 | 1356 | ||
1275 | if (type == NL80211_IFTYPE_MESH_POINT && | 1357 | if (type == NL80211_IFTYPE_MESH_POINT && |
1276 | info->attrs[NL80211_ATTR_MESH_ID]) { | 1358 | info->attrs[NL80211_ATTR_MESH_ID]) { |
@@ -1282,7 +1364,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1282 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | 1364 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); |
1283 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); | 1365 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); |
1284 | if (err) | 1366 | if (err) |
1285 | goto unlock; | 1367 | return err; |
1286 | } | 1368 | } |
1287 | 1369 | ||
1288 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 1370 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
@@ -1292,38 +1374,18 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1292 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 1374 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
1293 | type, err ? NULL : &flags, ¶ms); | 1375 | type, err ? NULL : &flags, ¶ms); |
1294 | 1376 | ||
1295 | unlock: | ||
1296 | cfg80211_unlock_rdev(rdev); | ||
1297 | unlock_rtnl: | ||
1298 | rtnl_unlock(); | ||
1299 | return err; | 1377 | return err; |
1300 | } | 1378 | } |
1301 | 1379 | ||
1302 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 1380 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
1303 | { | 1381 | { |
1304 | struct cfg80211_registered_device *rdev; | 1382 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1305 | int err; | 1383 | struct net_device *dev = info->user_ptr[1]; |
1306 | struct net_device *dev; | ||
1307 | 1384 | ||
1308 | rtnl_lock(); | 1385 | if (!rdev->ops->del_virtual_intf) |
1309 | 1386 | return -EOPNOTSUPP; | |
1310 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1311 | if (err) | ||
1312 | goto unlock_rtnl; | ||
1313 | |||
1314 | if (!rdev->ops->del_virtual_intf) { | ||
1315 | err = -EOPNOTSUPP; | ||
1316 | goto out; | ||
1317 | } | ||
1318 | |||
1319 | err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); | ||
1320 | 1387 | ||
1321 | out: | 1388 | return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); |
1322 | cfg80211_unlock_rdev(rdev); | ||
1323 | dev_put(dev); | ||
1324 | unlock_rtnl: | ||
1325 | rtnl_unlock(); | ||
1326 | return err; | ||
1327 | } | 1389 | } |
1328 | 1390 | ||
1329 | struct get_key_cookie { | 1391 | struct get_key_cookie { |
@@ -1376,11 +1438,12 @@ static void get_key_callback(void *c, struct key_params *params) | |||
1376 | 1438 | ||
1377 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | 1439 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) |
1378 | { | 1440 | { |
1379 | struct cfg80211_registered_device *rdev; | 1441 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1380 | int err; | 1442 | int err; |
1381 | struct net_device *dev; | 1443 | struct net_device *dev = info->user_ptr[1]; |
1382 | u8 key_idx = 0; | 1444 | u8 key_idx = 0; |
1383 | u8 *mac_addr = NULL; | 1445 | const u8 *mac_addr = NULL; |
1446 | bool pairwise; | ||
1384 | struct get_key_cookie cookie = { | 1447 | struct get_key_cookie cookie = { |
1385 | .error = 0, | 1448 | .error = 0, |
1386 | }; | 1449 | }; |
@@ -1396,30 +1459,28 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1396 | if (info->attrs[NL80211_ATTR_MAC]) | 1459 | if (info->attrs[NL80211_ATTR_MAC]) |
1397 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1460 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1398 | 1461 | ||
1399 | rtnl_lock(); | 1462 | pairwise = !!mac_addr; |
1400 | 1463 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { | |
1401 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1464 | u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); |
1402 | if (err) | 1465 | if (kt >= NUM_NL80211_KEYTYPES) |
1403 | goto unlock_rtnl; | 1466 | return -EINVAL; |
1404 | 1467 | if (kt != NL80211_KEYTYPE_GROUP && | |
1405 | if (!rdev->ops->get_key) { | 1468 | kt != NL80211_KEYTYPE_PAIRWISE) |
1406 | err = -EOPNOTSUPP; | 1469 | return -EINVAL; |
1407 | goto out; | 1470 | pairwise = kt == NL80211_KEYTYPE_PAIRWISE; |
1408 | } | 1471 | } |
1409 | 1472 | ||
1473 | if (!rdev->ops->get_key) | ||
1474 | return -EOPNOTSUPP; | ||
1475 | |||
1410 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1476 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1411 | if (!msg) { | 1477 | if (!msg) |
1412 | err = -ENOMEM; | 1478 | return -ENOMEM; |
1413 | goto out; | ||
1414 | } | ||
1415 | 1479 | ||
1416 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 1480 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
1417 | NL80211_CMD_NEW_KEY); | 1481 | NL80211_CMD_NEW_KEY); |
1418 | 1482 | if (IS_ERR(hdr)) | |
1419 | if (IS_ERR(hdr)) { | 1483 | return PTR_ERR(hdr); |
1420 | err = PTR_ERR(hdr); | ||
1421 | goto free_msg; | ||
1422 | } | ||
1423 | 1484 | ||
1424 | cookie.msg = msg; | 1485 | cookie.msg = msg; |
1425 | cookie.idx = key_idx; | 1486 | cookie.idx = key_idx; |
@@ -1429,8 +1490,12 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1429 | if (mac_addr) | 1490 | if (mac_addr) |
1430 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 1491 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
1431 | 1492 | ||
1432 | err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr, | 1493 | if (pairwise && mac_addr && |
1433 | &cookie, get_key_callback); | 1494 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) |
1495 | return -ENOENT; | ||
1496 | |||
1497 | err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise, | ||
1498 | mac_addr, &cookie, get_key_callback); | ||
1434 | 1499 | ||
1435 | if (err) | 1500 | if (err) |
1436 | goto free_msg; | 1501 | goto free_msg; |
@@ -1439,28 +1504,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1439 | goto nla_put_failure; | 1504 | goto nla_put_failure; |
1440 | 1505 | ||
1441 | genlmsg_end(msg, hdr); | 1506 | genlmsg_end(msg, hdr); |
1442 | err = genlmsg_reply(msg, info); | 1507 | return genlmsg_reply(msg, info); |
1443 | goto out; | ||
1444 | 1508 | ||
1445 | nla_put_failure: | 1509 | nla_put_failure: |
1446 | err = -ENOBUFS; | 1510 | err = -ENOBUFS; |
1447 | free_msg: | 1511 | free_msg: |
1448 | nlmsg_free(msg); | 1512 | nlmsg_free(msg); |
1449 | out: | ||
1450 | cfg80211_unlock_rdev(rdev); | ||
1451 | dev_put(dev); | ||
1452 | unlock_rtnl: | ||
1453 | rtnl_unlock(); | ||
1454 | |||
1455 | return err; | 1513 | return err; |
1456 | } | 1514 | } |
1457 | 1515 | ||
1458 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | 1516 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) |
1459 | { | 1517 | { |
1460 | struct cfg80211_registered_device *rdev; | 1518 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1461 | struct key_parse key; | 1519 | struct key_parse key; |
1462 | int err; | 1520 | int err; |
1463 | struct net_device *dev; | 1521 | struct net_device *dev = info->user_ptr[1]; |
1464 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, | 1522 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, |
1465 | u8 key_index); | 1523 | u8 key_index); |
1466 | 1524 | ||
@@ -1475,21 +1533,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1475 | if (!key.def && !key.defmgmt) | 1533 | if (!key.def && !key.defmgmt) |
1476 | return -EINVAL; | 1534 | return -EINVAL; |
1477 | 1535 | ||
1478 | rtnl_lock(); | ||
1479 | |||
1480 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1481 | if (err) | ||
1482 | goto unlock_rtnl; | ||
1483 | |||
1484 | if (key.def) | 1536 | if (key.def) |
1485 | func = rdev->ops->set_default_key; | 1537 | func = rdev->ops->set_default_key; |
1486 | else | 1538 | else |
1487 | func = rdev->ops->set_default_mgmt_key; | 1539 | func = rdev->ops->set_default_mgmt_key; |
1488 | 1540 | ||
1489 | if (!func) { | 1541 | if (!func) |
1490 | err = -EOPNOTSUPP; | 1542 | return -EOPNOTSUPP; |
1491 | goto out; | ||
1492 | } | ||
1493 | 1543 | ||
1494 | wdev_lock(dev->ieee80211_ptr); | 1544 | wdev_lock(dev->ieee80211_ptr); |
1495 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1545 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
@@ -1506,23 +1556,16 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1506 | #endif | 1556 | #endif |
1507 | wdev_unlock(dev->ieee80211_ptr); | 1557 | wdev_unlock(dev->ieee80211_ptr); |
1508 | 1558 | ||
1509 | out: | ||
1510 | cfg80211_unlock_rdev(rdev); | ||
1511 | dev_put(dev); | ||
1512 | |||
1513 | unlock_rtnl: | ||
1514 | rtnl_unlock(); | ||
1515 | |||
1516 | return err; | 1559 | return err; |
1517 | } | 1560 | } |
1518 | 1561 | ||
1519 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | 1562 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) |
1520 | { | 1563 | { |
1521 | struct cfg80211_registered_device *rdev; | 1564 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1522 | int err; | 1565 | int err; |
1523 | struct net_device *dev; | 1566 | struct net_device *dev = info->user_ptr[1]; |
1524 | struct key_parse key; | 1567 | struct key_parse key; |
1525 | u8 *mac_addr = NULL; | 1568 | const u8 *mac_addr = NULL; |
1526 | 1569 | ||
1527 | err = nl80211_parse_key(info, &key); | 1570 | err = nl80211_parse_key(info, &key); |
1528 | if (err) | 1571 | if (err) |
@@ -1534,43 +1577,42 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1534 | if (info->attrs[NL80211_ATTR_MAC]) | 1577 | if (info->attrs[NL80211_ATTR_MAC]) |
1535 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1578 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1536 | 1579 | ||
1537 | rtnl_lock(); | 1580 | if (key.type == -1) { |
1581 | if (mac_addr) | ||
1582 | key.type = NL80211_KEYTYPE_PAIRWISE; | ||
1583 | else | ||
1584 | key.type = NL80211_KEYTYPE_GROUP; | ||
1585 | } | ||
1538 | 1586 | ||
1539 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1587 | /* for now */ |
1540 | if (err) | 1588 | if (key.type != NL80211_KEYTYPE_PAIRWISE && |
1541 | goto unlock_rtnl; | 1589 | key.type != NL80211_KEYTYPE_GROUP) |
1590 | return -EINVAL; | ||
1542 | 1591 | ||
1543 | if (!rdev->ops->add_key) { | 1592 | if (!rdev->ops->add_key) |
1544 | err = -EOPNOTSUPP; | 1593 | return -EOPNOTSUPP; |
1545 | goto out; | ||
1546 | } | ||
1547 | 1594 | ||
1548 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) { | 1595 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, |
1549 | err = -EINVAL; | 1596 | key.type == NL80211_KEYTYPE_PAIRWISE, |
1550 | goto out; | 1597 | mac_addr)) |
1551 | } | 1598 | return -EINVAL; |
1552 | 1599 | ||
1553 | wdev_lock(dev->ieee80211_ptr); | 1600 | wdev_lock(dev->ieee80211_ptr); |
1554 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1601 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1555 | if (!err) | 1602 | if (!err) |
1556 | err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, | 1603 | err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, |
1604 | key.type == NL80211_KEYTYPE_PAIRWISE, | ||
1557 | mac_addr, &key.p); | 1605 | mac_addr, &key.p); |
1558 | wdev_unlock(dev->ieee80211_ptr); | 1606 | wdev_unlock(dev->ieee80211_ptr); |
1559 | 1607 | ||
1560 | out: | ||
1561 | cfg80211_unlock_rdev(rdev); | ||
1562 | dev_put(dev); | ||
1563 | unlock_rtnl: | ||
1564 | rtnl_unlock(); | ||
1565 | |||
1566 | return err; | 1608 | return err; |
1567 | } | 1609 | } |
1568 | 1610 | ||
1569 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | 1611 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) |
1570 | { | 1612 | { |
1571 | struct cfg80211_registered_device *rdev; | 1613 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1572 | int err; | 1614 | int err; |
1573 | struct net_device *dev; | 1615 | struct net_device *dev = info->user_ptr[1]; |
1574 | u8 *mac_addr = NULL; | 1616 | u8 *mac_addr = NULL; |
1575 | struct key_parse key; | 1617 | struct key_parse key; |
1576 | 1618 | ||
@@ -1581,21 +1623,32 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1581 | if (info->attrs[NL80211_ATTR_MAC]) | 1623 | if (info->attrs[NL80211_ATTR_MAC]) |
1582 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1624 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1583 | 1625 | ||
1584 | rtnl_lock(); | 1626 | if (key.type == -1) { |
1627 | if (mac_addr) | ||
1628 | key.type = NL80211_KEYTYPE_PAIRWISE; | ||
1629 | else | ||
1630 | key.type = NL80211_KEYTYPE_GROUP; | ||
1631 | } | ||
1585 | 1632 | ||
1586 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1633 | /* for now */ |
1587 | if (err) | 1634 | if (key.type != NL80211_KEYTYPE_PAIRWISE && |
1588 | goto unlock_rtnl; | 1635 | key.type != NL80211_KEYTYPE_GROUP) |
1636 | return -EINVAL; | ||
1589 | 1637 | ||
1590 | if (!rdev->ops->del_key) { | 1638 | if (!rdev->ops->del_key) |
1591 | err = -EOPNOTSUPP; | 1639 | return -EOPNOTSUPP; |
1592 | goto out; | ||
1593 | } | ||
1594 | 1640 | ||
1595 | wdev_lock(dev->ieee80211_ptr); | 1641 | wdev_lock(dev->ieee80211_ptr); |
1596 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1642 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1643 | |||
1644 | if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr && | ||
1645 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
1646 | err = -ENOENT; | ||
1647 | |||
1597 | if (!err) | 1648 | if (!err) |
1598 | err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); | 1649 | err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, |
1650 | key.type == NL80211_KEYTYPE_PAIRWISE, | ||
1651 | mac_addr); | ||
1599 | 1652 | ||
1600 | #ifdef CONFIG_CFG80211_WEXT | 1653 | #ifdef CONFIG_CFG80211_WEXT |
1601 | if (!err) { | 1654 | if (!err) { |
@@ -1607,13 +1660,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1607 | #endif | 1660 | #endif |
1608 | wdev_unlock(dev->ieee80211_ptr); | 1661 | wdev_unlock(dev->ieee80211_ptr); |
1609 | 1662 | ||
1610 | out: | ||
1611 | cfg80211_unlock_rdev(rdev); | ||
1612 | dev_put(dev); | ||
1613 | |||
1614 | unlock_rtnl: | ||
1615 | rtnl_unlock(); | ||
1616 | |||
1617 | return err; | 1663 | return err; |
1618 | } | 1664 | } |
1619 | 1665 | ||
@@ -1621,35 +1667,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1621 | { | 1667 | { |
1622 | int (*call)(struct wiphy *wiphy, struct net_device *dev, | 1668 | int (*call)(struct wiphy *wiphy, struct net_device *dev, |
1623 | struct beacon_parameters *info); | 1669 | struct beacon_parameters *info); |
1624 | struct cfg80211_registered_device *rdev; | 1670 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1625 | int err; | 1671 | struct net_device *dev = info->user_ptr[1]; |
1626 | struct net_device *dev; | ||
1627 | struct beacon_parameters params; | 1672 | struct beacon_parameters params; |
1628 | int haveinfo = 0; | 1673 | int haveinfo = 0; |
1629 | 1674 | ||
1630 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) | 1675 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) |
1631 | return -EINVAL; | 1676 | return -EINVAL; |
1632 | 1677 | ||
1633 | rtnl_lock(); | 1678 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
1634 | 1679 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | |
1635 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1680 | return -EOPNOTSUPP; |
1636 | if (err) | ||
1637 | goto unlock_rtnl; | ||
1638 | |||
1639 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { | ||
1640 | err = -EOPNOTSUPP; | ||
1641 | goto out; | ||
1642 | } | ||
1643 | 1681 | ||
1644 | switch (info->genlhdr->cmd) { | 1682 | switch (info->genlhdr->cmd) { |
1645 | case NL80211_CMD_NEW_BEACON: | 1683 | case NL80211_CMD_NEW_BEACON: |
1646 | /* these are required for NEW_BEACON */ | 1684 | /* these are required for NEW_BEACON */ |
1647 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || | 1685 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || |
1648 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || | 1686 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || |
1649 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 1687 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) |
1650 | err = -EINVAL; | 1688 | return -EINVAL; |
1651 | goto out; | ||
1652 | } | ||
1653 | 1689 | ||
1654 | call = rdev->ops->add_beacon; | 1690 | call = rdev->ops->add_beacon; |
1655 | break; | 1691 | break; |
@@ -1658,14 +1694,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1658 | break; | 1694 | break; |
1659 | default: | 1695 | default: |
1660 | WARN_ON(1); | 1696 | WARN_ON(1); |
1661 | err = -EOPNOTSUPP; | 1697 | return -EOPNOTSUPP; |
1662 | goto out; | ||
1663 | } | 1698 | } |
1664 | 1699 | ||
1665 | if (!call) { | 1700 | if (!call) |
1666 | err = -EOPNOTSUPP; | 1701 | return -EOPNOTSUPP; |
1667 | goto out; | ||
1668 | } | ||
1669 | 1702 | ||
1670 | memset(¶ms, 0, sizeof(params)); | 1703 | memset(¶ms, 0, sizeof(params)); |
1671 | 1704 | ||
@@ -1695,52 +1728,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1695 | haveinfo = 1; | 1728 | haveinfo = 1; |
1696 | } | 1729 | } |
1697 | 1730 | ||
1698 | if (!haveinfo) { | 1731 | if (!haveinfo) |
1699 | err = -EINVAL; | 1732 | return -EINVAL; |
1700 | goto out; | ||
1701 | } | ||
1702 | |||
1703 | err = call(&rdev->wiphy, dev, ¶ms); | ||
1704 | |||
1705 | out: | ||
1706 | cfg80211_unlock_rdev(rdev); | ||
1707 | dev_put(dev); | ||
1708 | unlock_rtnl: | ||
1709 | rtnl_unlock(); | ||
1710 | 1733 | ||
1711 | return err; | 1734 | return call(&rdev->wiphy, dev, ¶ms); |
1712 | } | 1735 | } |
1713 | 1736 | ||
1714 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | 1737 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) |
1715 | { | 1738 | { |
1716 | struct cfg80211_registered_device *rdev; | 1739 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1717 | int err; | 1740 | struct net_device *dev = info->user_ptr[1]; |
1718 | struct net_device *dev; | ||
1719 | 1741 | ||
1720 | rtnl_lock(); | 1742 | if (!rdev->ops->del_beacon) |
1721 | 1743 | return -EOPNOTSUPP; | |
1722 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1723 | if (err) | ||
1724 | goto unlock_rtnl; | ||
1725 | |||
1726 | if (!rdev->ops->del_beacon) { | ||
1727 | err = -EOPNOTSUPP; | ||
1728 | goto out; | ||
1729 | } | ||
1730 | |||
1731 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { | ||
1732 | err = -EOPNOTSUPP; | ||
1733 | goto out; | ||
1734 | } | ||
1735 | err = rdev->ops->del_beacon(&rdev->wiphy, dev); | ||
1736 | 1744 | ||
1737 | out: | 1745 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
1738 | cfg80211_unlock_rdev(rdev); | 1746 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
1739 | dev_put(dev); | 1747 | return -EOPNOTSUPP; |
1740 | unlock_rtnl: | ||
1741 | rtnl_unlock(); | ||
1742 | 1748 | ||
1743 | return err; | 1749 | return rdev->ops->del_beacon(&rdev->wiphy, dev); |
1744 | } | 1750 | } |
1745 | 1751 | ||
1746 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 1752 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -1861,6 +1867,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1861 | if (sinfo->filled & STATION_INFO_TX_PACKETS) | 1867 | if (sinfo->filled & STATION_INFO_TX_PACKETS) |
1862 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, | 1868 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, |
1863 | sinfo->tx_packets); | 1869 | sinfo->tx_packets); |
1870 | if (sinfo->filled & STATION_INFO_TX_RETRIES) | ||
1871 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_RETRIES, | ||
1872 | sinfo->tx_retries); | ||
1873 | if (sinfo->filled & STATION_INFO_TX_FAILED) | ||
1874 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, | ||
1875 | sinfo->tx_failed); | ||
1864 | nla_nest_end(msg, sinfoattr); | 1876 | nla_nest_end(msg, sinfoattr); |
1865 | 1877 | ||
1866 | return genlmsg_end(msg, hdr); | 1878 | return genlmsg_end(msg, hdr); |
@@ -1877,28 +1889,12 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1877 | struct cfg80211_registered_device *dev; | 1889 | struct cfg80211_registered_device *dev; |
1878 | struct net_device *netdev; | 1890 | struct net_device *netdev; |
1879 | u8 mac_addr[ETH_ALEN]; | 1891 | u8 mac_addr[ETH_ALEN]; |
1880 | int ifidx = cb->args[0]; | ||
1881 | int sta_idx = cb->args[1]; | 1892 | int sta_idx = cb->args[1]; |
1882 | int err; | 1893 | int err; |
1883 | 1894 | ||
1884 | if (!ifidx) | 1895 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
1885 | ifidx = nl80211_get_ifidx(cb); | 1896 | if (err) |
1886 | if (ifidx < 0) | 1897 | return err; |
1887 | return ifidx; | ||
1888 | |||
1889 | rtnl_lock(); | ||
1890 | |||
1891 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1892 | if (!netdev) { | ||
1893 | err = -ENODEV; | ||
1894 | goto out_rtnl; | ||
1895 | } | ||
1896 | |||
1897 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
1898 | if (IS_ERR(dev)) { | ||
1899 | err = PTR_ERR(dev); | ||
1900 | goto out_rtnl; | ||
1901 | } | ||
1902 | 1898 | ||
1903 | if (!dev->ops->dump_station) { | 1899 | if (!dev->ops->dump_station) { |
1904 | err = -EOPNOTSUPP; | 1900 | err = -EOPNOTSUPP; |
@@ -1928,21 +1924,19 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1928 | cb->args[1] = sta_idx; | 1924 | cb->args[1] = sta_idx; |
1929 | err = skb->len; | 1925 | err = skb->len; |
1930 | out_err: | 1926 | out_err: |
1931 | cfg80211_unlock_rdev(dev); | 1927 | nl80211_finish_netdev_dump(dev); |
1932 | out_rtnl: | ||
1933 | rtnl_unlock(); | ||
1934 | 1928 | ||
1935 | return err; | 1929 | return err; |
1936 | } | 1930 | } |
1937 | 1931 | ||
1938 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | 1932 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) |
1939 | { | 1933 | { |
1940 | struct cfg80211_registered_device *rdev; | 1934 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1941 | int err; | 1935 | struct net_device *dev = info->user_ptr[1]; |
1942 | struct net_device *dev; | ||
1943 | struct station_info sinfo; | 1936 | struct station_info sinfo; |
1944 | struct sk_buff *msg; | 1937 | struct sk_buff *msg; |
1945 | u8 *mac_addr = NULL; | 1938 | u8 *mac_addr = NULL; |
1939 | int err; | ||
1946 | 1940 | ||
1947 | memset(&sinfo, 0, sizeof(sinfo)); | 1941 | memset(&sinfo, 0, sizeof(sinfo)); |
1948 | 1942 | ||
@@ -1951,41 +1945,24 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1951 | 1945 | ||
1952 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1946 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1953 | 1947 | ||
1954 | rtnl_lock(); | 1948 | if (!rdev->ops->get_station) |
1955 | 1949 | return -EOPNOTSUPP; | |
1956 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1957 | if (err) | ||
1958 | goto out_rtnl; | ||
1959 | |||
1960 | if (!rdev->ops->get_station) { | ||
1961 | err = -EOPNOTSUPP; | ||
1962 | goto out; | ||
1963 | } | ||
1964 | 1950 | ||
1965 | err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); | 1951 | err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); |
1966 | if (err) | 1952 | if (err) |
1967 | goto out; | 1953 | return err; |
1968 | 1954 | ||
1969 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1955 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1970 | if (!msg) | 1956 | if (!msg) |
1971 | goto out; | 1957 | return -ENOMEM; |
1972 | 1958 | ||
1973 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, | 1959 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, |
1974 | dev, mac_addr, &sinfo) < 0) | 1960 | dev, mac_addr, &sinfo) < 0) { |
1975 | goto out_free; | 1961 | nlmsg_free(msg); |
1976 | 1962 | return -ENOBUFS; | |
1977 | err = genlmsg_reply(msg, info); | 1963 | } |
1978 | goto out; | ||
1979 | |||
1980 | out_free: | ||
1981 | nlmsg_free(msg); | ||
1982 | out: | ||
1983 | cfg80211_unlock_rdev(rdev); | ||
1984 | dev_put(dev); | ||
1985 | out_rtnl: | ||
1986 | rtnl_unlock(); | ||
1987 | 1964 | ||
1988 | return err; | 1965 | return genlmsg_reply(msg, info); |
1989 | } | 1966 | } |
1990 | 1967 | ||
1991 | /* | 1968 | /* |
@@ -2015,9 +1992,9 @@ static int get_vlan(struct genl_info *info, | |||
2015 | 1992 | ||
2016 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 1993 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
2017 | { | 1994 | { |
2018 | struct cfg80211_registered_device *rdev; | 1995 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2019 | int err; | 1996 | int err; |
2020 | struct net_device *dev; | 1997 | struct net_device *dev = info->user_ptr[1]; |
2021 | struct station_parameters params; | 1998 | struct station_parameters params; |
2022 | u8 *mac_addr = NULL; | 1999 | u8 *mac_addr = NULL; |
2023 | 2000 | ||
@@ -2055,12 +2032,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2055 | params.plink_action = | 2032 | params.plink_action = |
2056 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 2033 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
2057 | 2034 | ||
2058 | rtnl_lock(); | ||
2059 | |||
2060 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2061 | if (err) | ||
2062 | goto out_rtnl; | ||
2063 | |||
2064 | err = get_vlan(info, rdev, ¶ms.vlan); | 2035 | err = get_vlan(info, rdev, ¶ms.vlan); |
2065 | if (err) | 2036 | if (err) |
2066 | goto out; | 2037 | goto out; |
@@ -2071,10 +2042,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2071 | switch (dev->ieee80211_ptr->iftype) { | 2042 | switch (dev->ieee80211_ptr->iftype) { |
2072 | case NL80211_IFTYPE_AP: | 2043 | case NL80211_IFTYPE_AP: |
2073 | case NL80211_IFTYPE_AP_VLAN: | 2044 | case NL80211_IFTYPE_AP_VLAN: |
2045 | case NL80211_IFTYPE_P2P_GO: | ||
2074 | /* disallow mesh-specific things */ | 2046 | /* disallow mesh-specific things */ |
2075 | if (params.plink_action) | 2047 | if (params.plink_action) |
2076 | err = -EINVAL; | 2048 | err = -EINVAL; |
2077 | break; | 2049 | break; |
2050 | case NL80211_IFTYPE_P2P_CLIENT: | ||
2078 | case NL80211_IFTYPE_STATION: | 2051 | case NL80211_IFTYPE_STATION: |
2079 | /* disallow everything but AUTHORIZED flag */ | 2052 | /* disallow everything but AUTHORIZED flag */ |
2080 | if (params.plink_action) | 2053 | if (params.plink_action) |
@@ -2120,19 +2093,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2120 | out: | 2093 | out: |
2121 | if (params.vlan) | 2094 | if (params.vlan) |
2122 | dev_put(params.vlan); | 2095 | dev_put(params.vlan); |
2123 | cfg80211_unlock_rdev(rdev); | ||
2124 | dev_put(dev); | ||
2125 | out_rtnl: | ||
2126 | rtnl_unlock(); | ||
2127 | 2096 | ||
2128 | return err; | 2097 | return err; |
2129 | } | 2098 | } |
2130 | 2099 | ||
2131 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | 2100 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) |
2132 | { | 2101 | { |
2133 | struct cfg80211_registered_device *rdev; | 2102 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2134 | int err; | 2103 | int err; |
2135 | struct net_device *dev; | 2104 | struct net_device *dev = info->user_ptr[1]; |
2136 | struct station_parameters params; | 2105 | struct station_parameters params; |
2137 | u8 *mac_addr = NULL; | 2106 | u8 *mac_addr = NULL; |
2138 | 2107 | ||
@@ -2169,17 +2138,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2169 | if (parse_station_flags(info, ¶ms)) | 2138 | if (parse_station_flags(info, ¶ms)) |
2170 | return -EINVAL; | 2139 | return -EINVAL; |
2171 | 2140 | ||
2172 | rtnl_lock(); | ||
2173 | |||
2174 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2175 | if (err) | ||
2176 | goto out_rtnl; | ||
2177 | |||
2178 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2141 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2179 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { | 2142 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2180 | err = -EINVAL; | 2143 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2181 | goto out; | 2144 | return -EINVAL; |
2182 | } | ||
2183 | 2145 | ||
2184 | err = get_vlan(info, rdev, ¶ms.vlan); | 2146 | err = get_vlan(info, rdev, ¶ms.vlan); |
2185 | if (err) | 2147 | if (err) |
@@ -2193,61 +2155,33 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2193 | goto out; | 2155 | goto out; |
2194 | } | 2156 | } |
2195 | 2157 | ||
2196 | if (!netif_running(dev)) { | ||
2197 | err = -ENETDOWN; | ||
2198 | goto out; | ||
2199 | } | ||
2200 | |||
2201 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); | 2158 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); |
2202 | 2159 | ||
2203 | out: | 2160 | out: |
2204 | if (params.vlan) | 2161 | if (params.vlan) |
2205 | dev_put(params.vlan); | 2162 | dev_put(params.vlan); |
2206 | cfg80211_unlock_rdev(rdev); | ||
2207 | dev_put(dev); | ||
2208 | out_rtnl: | ||
2209 | rtnl_unlock(); | ||
2210 | |||
2211 | return err; | 2163 | return err; |
2212 | } | 2164 | } |
2213 | 2165 | ||
2214 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | 2166 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) |
2215 | { | 2167 | { |
2216 | struct cfg80211_registered_device *rdev; | 2168 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2217 | int err; | 2169 | struct net_device *dev = info->user_ptr[1]; |
2218 | struct net_device *dev; | ||
2219 | u8 *mac_addr = NULL; | 2170 | u8 *mac_addr = NULL; |
2220 | 2171 | ||
2221 | if (info->attrs[NL80211_ATTR_MAC]) | 2172 | if (info->attrs[NL80211_ATTR_MAC]) |
2222 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2173 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2223 | 2174 | ||
2224 | rtnl_lock(); | ||
2225 | |||
2226 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2227 | if (err) | ||
2228 | goto out_rtnl; | ||
2229 | |||
2230 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2175 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2231 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 2176 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2232 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 2177 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && |
2233 | err = -EINVAL; | 2178 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2234 | goto out; | 2179 | return -EINVAL; |
2235 | } | ||
2236 | |||
2237 | if (!rdev->ops->del_station) { | ||
2238 | err = -EOPNOTSUPP; | ||
2239 | goto out; | ||
2240 | } | ||
2241 | |||
2242 | err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); | ||
2243 | 2180 | ||
2244 | out: | 2181 | if (!rdev->ops->del_station) |
2245 | cfg80211_unlock_rdev(rdev); | 2182 | return -EOPNOTSUPP; |
2246 | dev_put(dev); | ||
2247 | out_rtnl: | ||
2248 | rtnl_unlock(); | ||
2249 | 2183 | ||
2250 | return err; | 2184 | return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); |
2251 | } | 2185 | } |
2252 | 2186 | ||
2253 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | 2187 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, |
@@ -2310,28 +2244,12 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2310 | struct net_device *netdev; | 2244 | struct net_device *netdev; |
2311 | u8 dst[ETH_ALEN]; | 2245 | u8 dst[ETH_ALEN]; |
2312 | u8 next_hop[ETH_ALEN]; | 2246 | u8 next_hop[ETH_ALEN]; |
2313 | int ifidx = cb->args[0]; | ||
2314 | int path_idx = cb->args[1]; | 2247 | int path_idx = cb->args[1]; |
2315 | int err; | 2248 | int err; |
2316 | 2249 | ||
2317 | if (!ifidx) | 2250 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
2318 | ifidx = nl80211_get_ifidx(cb); | 2251 | if (err) |
2319 | if (ifidx < 0) | 2252 | return err; |
2320 | return ifidx; | ||
2321 | |||
2322 | rtnl_lock(); | ||
2323 | |||
2324 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
2325 | if (!netdev) { | ||
2326 | err = -ENODEV; | ||
2327 | goto out_rtnl; | ||
2328 | } | ||
2329 | |||
2330 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
2331 | if (IS_ERR(dev)) { | ||
2332 | err = PTR_ERR(dev); | ||
2333 | goto out_rtnl; | ||
2334 | } | ||
2335 | 2253 | ||
2336 | if (!dev->ops->dump_mpath) { | 2254 | if (!dev->ops->dump_mpath) { |
2337 | err = -EOPNOTSUPP; | 2255 | err = -EOPNOTSUPP; |
@@ -2365,18 +2283,15 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2365 | cb->args[1] = path_idx; | 2283 | cb->args[1] = path_idx; |
2366 | err = skb->len; | 2284 | err = skb->len; |
2367 | out_err: | 2285 | out_err: |
2368 | cfg80211_unlock_rdev(dev); | 2286 | nl80211_finish_netdev_dump(dev); |
2369 | out_rtnl: | ||
2370 | rtnl_unlock(); | ||
2371 | |||
2372 | return err; | 2287 | return err; |
2373 | } | 2288 | } |
2374 | 2289 | ||
2375 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | 2290 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) |
2376 | { | 2291 | { |
2377 | struct cfg80211_registered_device *rdev; | 2292 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2378 | int err; | 2293 | int err; |
2379 | struct net_device *dev; | 2294 | struct net_device *dev = info->user_ptr[1]; |
2380 | struct mpath_info pinfo; | 2295 | struct mpath_info pinfo; |
2381 | struct sk_buff *msg; | 2296 | struct sk_buff *msg; |
2382 | u8 *dst = NULL; | 2297 | u8 *dst = NULL; |
@@ -2389,53 +2304,33 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2389 | 2304 | ||
2390 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2305 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2391 | 2306 | ||
2392 | rtnl_lock(); | 2307 | if (!rdev->ops->get_mpath) |
2393 | 2308 | return -EOPNOTSUPP; | |
2394 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2395 | if (err) | ||
2396 | goto out_rtnl; | ||
2397 | |||
2398 | if (!rdev->ops->get_mpath) { | ||
2399 | err = -EOPNOTSUPP; | ||
2400 | goto out; | ||
2401 | } | ||
2402 | 2309 | ||
2403 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 2310 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2404 | err = -EOPNOTSUPP; | 2311 | return -EOPNOTSUPP; |
2405 | goto out; | ||
2406 | } | ||
2407 | 2312 | ||
2408 | err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); | 2313 | err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); |
2409 | if (err) | 2314 | if (err) |
2410 | goto out; | 2315 | return err; |
2411 | 2316 | ||
2412 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2317 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2413 | if (!msg) | 2318 | if (!msg) |
2414 | goto out; | 2319 | return -ENOMEM; |
2415 | 2320 | ||
2416 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, | 2321 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, |
2417 | dev, dst, next_hop, &pinfo) < 0) | 2322 | dev, dst, next_hop, &pinfo) < 0) { |
2418 | goto out_free; | 2323 | nlmsg_free(msg); |
2419 | 2324 | return -ENOBUFS; | |
2420 | err = genlmsg_reply(msg, info); | 2325 | } |
2421 | goto out; | ||
2422 | |||
2423 | out_free: | ||
2424 | nlmsg_free(msg); | ||
2425 | out: | ||
2426 | cfg80211_unlock_rdev(rdev); | ||
2427 | dev_put(dev); | ||
2428 | out_rtnl: | ||
2429 | rtnl_unlock(); | ||
2430 | 2326 | ||
2431 | return err; | 2327 | return genlmsg_reply(msg, info); |
2432 | } | 2328 | } |
2433 | 2329 | ||
2434 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | 2330 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) |
2435 | { | 2331 | { |
2436 | struct cfg80211_registered_device *rdev; | 2332 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2437 | int err; | 2333 | struct net_device *dev = info->user_ptr[1]; |
2438 | struct net_device *dev; | ||
2439 | u8 *dst = NULL; | 2334 | u8 *dst = NULL; |
2440 | u8 *next_hop = NULL; | 2335 | u8 *next_hop = NULL; |
2441 | 2336 | ||
@@ -2448,42 +2343,19 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2448 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2343 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2449 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 2344 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
2450 | 2345 | ||
2451 | rtnl_lock(); | 2346 | if (!rdev->ops->change_mpath) |
2452 | 2347 | return -EOPNOTSUPP; | |
2453 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2454 | if (err) | ||
2455 | goto out_rtnl; | ||
2456 | |||
2457 | if (!rdev->ops->change_mpath) { | ||
2458 | err = -EOPNOTSUPP; | ||
2459 | goto out; | ||
2460 | } | ||
2461 | |||
2462 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
2463 | err = -EOPNOTSUPP; | ||
2464 | goto out; | ||
2465 | } | ||
2466 | |||
2467 | if (!netif_running(dev)) { | ||
2468 | err = -ENETDOWN; | ||
2469 | goto out; | ||
2470 | } | ||
2471 | |||
2472 | err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); | ||
2473 | 2348 | ||
2474 | out: | 2349 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2475 | cfg80211_unlock_rdev(rdev); | 2350 | return -EOPNOTSUPP; |
2476 | dev_put(dev); | ||
2477 | out_rtnl: | ||
2478 | rtnl_unlock(); | ||
2479 | 2351 | ||
2480 | return err; | 2352 | return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); |
2481 | } | 2353 | } |
2354 | |||
2482 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | 2355 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) |
2483 | { | 2356 | { |
2484 | struct cfg80211_registered_device *rdev; | 2357 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2485 | int err; | 2358 | struct net_device *dev = info->user_ptr[1]; |
2486 | struct net_device *dev; | ||
2487 | u8 *dst = NULL; | 2359 | u8 *dst = NULL; |
2488 | u8 *next_hop = NULL; | 2360 | u8 *next_hop = NULL; |
2489 | 2361 | ||
@@ -2496,75 +2368,34 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2496 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2368 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2497 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 2369 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
2498 | 2370 | ||
2499 | rtnl_lock(); | 2371 | if (!rdev->ops->add_mpath) |
2500 | 2372 | return -EOPNOTSUPP; | |
2501 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2502 | if (err) | ||
2503 | goto out_rtnl; | ||
2504 | |||
2505 | if (!rdev->ops->add_mpath) { | ||
2506 | err = -EOPNOTSUPP; | ||
2507 | goto out; | ||
2508 | } | ||
2509 | |||
2510 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
2511 | err = -EOPNOTSUPP; | ||
2512 | goto out; | ||
2513 | } | ||
2514 | |||
2515 | if (!netif_running(dev)) { | ||
2516 | err = -ENETDOWN; | ||
2517 | goto out; | ||
2518 | } | ||
2519 | |||
2520 | err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); | ||
2521 | 2373 | ||
2522 | out: | 2374 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2523 | cfg80211_unlock_rdev(rdev); | 2375 | return -EOPNOTSUPP; |
2524 | dev_put(dev); | ||
2525 | out_rtnl: | ||
2526 | rtnl_unlock(); | ||
2527 | 2376 | ||
2528 | return err; | 2377 | return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); |
2529 | } | 2378 | } |
2530 | 2379 | ||
2531 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | 2380 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) |
2532 | { | 2381 | { |
2533 | struct cfg80211_registered_device *rdev; | 2382 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2534 | int err; | 2383 | struct net_device *dev = info->user_ptr[1]; |
2535 | struct net_device *dev; | ||
2536 | u8 *dst = NULL; | 2384 | u8 *dst = NULL; |
2537 | 2385 | ||
2538 | if (info->attrs[NL80211_ATTR_MAC]) | 2386 | if (info->attrs[NL80211_ATTR_MAC]) |
2539 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2387 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2540 | 2388 | ||
2541 | rtnl_lock(); | 2389 | if (!rdev->ops->del_mpath) |
2542 | 2390 | return -EOPNOTSUPP; | |
2543 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2544 | if (err) | ||
2545 | goto out_rtnl; | ||
2546 | |||
2547 | if (!rdev->ops->del_mpath) { | ||
2548 | err = -EOPNOTSUPP; | ||
2549 | goto out; | ||
2550 | } | ||
2551 | |||
2552 | err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst); | ||
2553 | |||
2554 | out: | ||
2555 | cfg80211_unlock_rdev(rdev); | ||
2556 | dev_put(dev); | ||
2557 | out_rtnl: | ||
2558 | rtnl_unlock(); | ||
2559 | 2391 | ||
2560 | return err; | 2392 | return rdev->ops->del_mpath(&rdev->wiphy, dev, dst); |
2561 | } | 2393 | } |
2562 | 2394 | ||
2563 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | 2395 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) |
2564 | { | 2396 | { |
2565 | struct cfg80211_registered_device *rdev; | 2397 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2566 | int err; | 2398 | struct net_device *dev = info->user_ptr[1]; |
2567 | struct net_device *dev; | ||
2568 | struct bss_parameters params; | 2399 | struct bss_parameters params; |
2569 | 2400 | ||
2570 | memset(¶ms, 0, sizeof(params)); | 2401 | memset(¶ms, 0, sizeof(params)); |
@@ -2592,31 +2423,14 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
2592 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) | 2423 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) |
2593 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); | 2424 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); |
2594 | 2425 | ||
2595 | rtnl_lock(); | 2426 | if (!rdev->ops->change_bss) |
2596 | 2427 | return -EOPNOTSUPP; | |
2597 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2598 | if (err) | ||
2599 | goto out_rtnl; | ||
2600 | |||
2601 | if (!rdev->ops->change_bss) { | ||
2602 | err = -EOPNOTSUPP; | ||
2603 | goto out; | ||
2604 | } | ||
2605 | |||
2606 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { | ||
2607 | err = -EOPNOTSUPP; | ||
2608 | goto out; | ||
2609 | } | ||
2610 | |||
2611 | err = rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); | ||
2612 | 2428 | ||
2613 | out: | 2429 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2614 | cfg80211_unlock_rdev(rdev); | 2430 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2615 | dev_put(dev); | 2431 | return -EOPNOTSUPP; |
2616 | out_rtnl: | ||
2617 | rtnl_unlock(); | ||
2618 | 2432 | ||
2619 | return err; | 2433 | return rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); |
2620 | } | 2434 | } |
2621 | 2435 | ||
2622 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { | 2436 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { |
@@ -2695,37 +2509,26 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2695 | static int nl80211_get_mesh_params(struct sk_buff *skb, | 2509 | static int nl80211_get_mesh_params(struct sk_buff *skb, |
2696 | struct genl_info *info) | 2510 | struct genl_info *info) |
2697 | { | 2511 | { |
2698 | struct cfg80211_registered_device *rdev; | 2512 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2699 | struct mesh_config cur_params; | 2513 | struct mesh_config cur_params; |
2700 | int err; | 2514 | int err; |
2701 | struct net_device *dev; | 2515 | struct net_device *dev = info->user_ptr[1]; |
2702 | void *hdr; | 2516 | void *hdr; |
2703 | struct nlattr *pinfoattr; | 2517 | struct nlattr *pinfoattr; |
2704 | struct sk_buff *msg; | 2518 | struct sk_buff *msg; |
2705 | 2519 | ||
2706 | rtnl_lock(); | 2520 | if (!rdev->ops->get_mesh_params) |
2707 | 2521 | return -EOPNOTSUPP; | |
2708 | /* Look up our device */ | ||
2709 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2710 | if (err) | ||
2711 | goto out_rtnl; | ||
2712 | |||
2713 | if (!rdev->ops->get_mesh_params) { | ||
2714 | err = -EOPNOTSUPP; | ||
2715 | goto out; | ||
2716 | } | ||
2717 | 2522 | ||
2718 | /* Get the mesh params */ | 2523 | /* Get the mesh params */ |
2719 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); | 2524 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); |
2720 | if (err) | 2525 | if (err) |
2721 | goto out; | 2526 | return err; |
2722 | 2527 | ||
2723 | /* Draw up a netlink message to send back */ | 2528 | /* Draw up a netlink message to send back */ |
2724 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2529 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2725 | if (!msg) { | 2530 | if (!msg) |
2726 | err = -ENOBUFS; | 2531 | return -ENOMEM; |
2727 | goto out; | ||
2728 | } | ||
2729 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 2532 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
2730 | NL80211_CMD_GET_MESH_PARAMS); | 2533 | NL80211_CMD_GET_MESH_PARAMS); |
2731 | if (!hdr) | 2534 | if (!hdr) |
@@ -2764,21 +2567,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2764 | cur_params.dot11MeshHWMPRootMode); | 2567 | cur_params.dot11MeshHWMPRootMode); |
2765 | nla_nest_end(msg, pinfoattr); | 2568 | nla_nest_end(msg, pinfoattr); |
2766 | genlmsg_end(msg, hdr); | 2569 | genlmsg_end(msg, hdr); |
2767 | err = genlmsg_reply(msg, info); | 2570 | return genlmsg_reply(msg, info); |
2768 | goto out; | ||
2769 | 2571 | ||
2770 | nla_put_failure: | 2572 | nla_put_failure: |
2771 | genlmsg_cancel(msg, hdr); | 2573 | genlmsg_cancel(msg, hdr); |
2772 | nlmsg_free(msg); | 2574 | nlmsg_free(msg); |
2773 | err = -EMSGSIZE; | 2575 | return -ENOBUFS; |
2774 | out: | ||
2775 | /* Cleanup */ | ||
2776 | cfg80211_unlock_rdev(rdev); | ||
2777 | dev_put(dev); | ||
2778 | out_rtnl: | ||
2779 | rtnl_unlock(); | ||
2780 | |||
2781 | return err; | ||
2782 | } | 2576 | } |
2783 | 2577 | ||
2784 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ | 2578 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ |
@@ -2808,10 +2602,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
2808 | 2602 | ||
2809 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | 2603 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) |
2810 | { | 2604 | { |
2811 | int err; | ||
2812 | u32 mask; | 2605 | u32 mask; |
2813 | struct cfg80211_registered_device *rdev; | 2606 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2814 | struct net_device *dev; | 2607 | struct net_device *dev = info->user_ptr[1]; |
2815 | struct mesh_config cfg; | 2608 | struct mesh_config cfg; |
2816 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; | 2609 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; |
2817 | struct nlattr *parent_attr; | 2610 | struct nlattr *parent_attr; |
@@ -2823,16 +2616,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2823 | parent_attr, nl80211_meshconf_params_policy)) | 2616 | parent_attr, nl80211_meshconf_params_policy)) |
2824 | return -EINVAL; | 2617 | return -EINVAL; |
2825 | 2618 | ||
2826 | rtnl_lock(); | 2619 | if (!rdev->ops->set_mesh_params) |
2827 | 2620 | return -EOPNOTSUPP; | |
2828 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2829 | if (err) | ||
2830 | goto out_rtnl; | ||
2831 | |||
2832 | if (!rdev->ops->set_mesh_params) { | ||
2833 | err = -EOPNOTSUPP; | ||
2834 | goto out; | ||
2835 | } | ||
2836 | 2621 | ||
2837 | /* This makes sure that there aren't more than 32 mesh config | 2622 | /* This makes sure that there aren't more than 32 mesh config |
2838 | * parameters (otherwise our bitfield scheme would not work.) */ | 2623 | * parameters (otherwise our bitfield scheme would not work.) */ |
@@ -2878,16 +2663,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2878 | nla_get_u8); | 2663 | nla_get_u8); |
2879 | 2664 | ||
2880 | /* Apply changes */ | 2665 | /* Apply changes */ |
2881 | err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); | 2666 | return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); |
2882 | |||
2883 | out: | ||
2884 | /* cleanup */ | ||
2885 | cfg80211_unlock_rdev(rdev); | ||
2886 | dev_put(dev); | ||
2887 | out_rtnl: | ||
2888 | rtnl_unlock(); | ||
2889 | |||
2890 | return err; | ||
2891 | } | 2667 | } |
2892 | 2668 | ||
2893 | #undef FILL_IN_MESH_PARAM_IF_SET | 2669 | #undef FILL_IN_MESH_PARAM_IF_SET |
@@ -3070,8 +2846,8 @@ static int validate_scan_freqs(struct nlattr *freqs) | |||
3070 | 2846 | ||
3071 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 2847 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
3072 | { | 2848 | { |
3073 | struct cfg80211_registered_device *rdev; | 2849 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3074 | struct net_device *dev; | 2850 | struct net_device *dev = info->user_ptr[1]; |
3075 | struct cfg80211_scan_request *request; | 2851 | struct cfg80211_scan_request *request; |
3076 | struct cfg80211_ssid *ssid; | 2852 | struct cfg80211_ssid *ssid; |
3077 | struct ieee80211_channel *channel; | 2853 | struct ieee80211_channel *channel; |
@@ -3084,36 +2860,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3084 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 2860 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3085 | return -EINVAL; | 2861 | return -EINVAL; |
3086 | 2862 | ||
3087 | rtnl_lock(); | ||
3088 | |||
3089 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3090 | if (err) | ||
3091 | goto out_rtnl; | ||
3092 | |||
3093 | wiphy = &rdev->wiphy; | 2863 | wiphy = &rdev->wiphy; |
3094 | 2864 | ||
3095 | if (!rdev->ops->scan) { | 2865 | if (!rdev->ops->scan) |
3096 | err = -EOPNOTSUPP; | 2866 | return -EOPNOTSUPP; |
3097 | goto out; | ||
3098 | } | ||
3099 | |||
3100 | if (!netif_running(dev)) { | ||
3101 | err = -ENETDOWN; | ||
3102 | goto out; | ||
3103 | } | ||
3104 | 2867 | ||
3105 | if (rdev->scan_req) { | 2868 | if (rdev->scan_req) |
3106 | err = -EBUSY; | 2869 | return -EBUSY; |
3107 | goto out; | ||
3108 | } | ||
3109 | 2870 | ||
3110 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 2871 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
3111 | n_channels = validate_scan_freqs( | 2872 | n_channels = validate_scan_freqs( |
3112 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); | 2873 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); |
3113 | if (!n_channels) { | 2874 | if (!n_channels) |
3114 | err = -EINVAL; | 2875 | return -EINVAL; |
3115 | goto out; | ||
3116 | } | ||
3117 | } else { | 2876 | } else { |
3118 | n_channels = 0; | 2877 | n_channels = 0; |
3119 | 2878 | ||
@@ -3126,29 +2885,23 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3126 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) | 2885 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) |
3127 | n_ssids++; | 2886 | n_ssids++; |
3128 | 2887 | ||
3129 | if (n_ssids > wiphy->max_scan_ssids) { | 2888 | if (n_ssids > wiphy->max_scan_ssids) |
3130 | err = -EINVAL; | 2889 | return -EINVAL; |
3131 | goto out; | ||
3132 | } | ||
3133 | 2890 | ||
3134 | if (info->attrs[NL80211_ATTR_IE]) | 2891 | if (info->attrs[NL80211_ATTR_IE]) |
3135 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2892 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3136 | else | 2893 | else |
3137 | ie_len = 0; | 2894 | ie_len = 0; |
3138 | 2895 | ||
3139 | if (ie_len > wiphy->max_scan_ie_len) { | 2896 | if (ie_len > wiphy->max_scan_ie_len) |
3140 | err = -EINVAL; | 2897 | return -EINVAL; |
3141 | goto out; | ||
3142 | } | ||
3143 | 2898 | ||
3144 | request = kzalloc(sizeof(*request) | 2899 | request = kzalloc(sizeof(*request) |
3145 | + sizeof(*ssid) * n_ssids | 2900 | + sizeof(*ssid) * n_ssids |
3146 | + sizeof(channel) * n_channels | 2901 | + sizeof(channel) * n_channels |
3147 | + ie_len, GFP_KERNEL); | 2902 | + ie_len, GFP_KERNEL); |
3148 | if (!request) { | 2903 | if (!request) |
3149 | err = -ENOMEM; | 2904 | return -ENOMEM; |
3150 | goto out; | ||
3151 | } | ||
3152 | 2905 | ||
3153 | if (n_ssids) | 2906 | if (n_ssids) |
3154 | request->ssids = (void *)&request->channels[n_channels]; | 2907 | request->ssids = (void *)&request->channels[n_channels]; |
@@ -3236,18 +2989,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3236 | if (!err) { | 2989 | if (!err) { |
3237 | nl80211_send_scan_start(rdev, dev); | 2990 | nl80211_send_scan_start(rdev, dev); |
3238 | dev_hold(dev); | 2991 | dev_hold(dev); |
3239 | } | 2992 | } else { |
3240 | |||
3241 | out_free: | 2993 | out_free: |
3242 | if (err) { | ||
3243 | rdev->scan_req = NULL; | 2994 | rdev->scan_req = NULL; |
3244 | kfree(request); | 2995 | kfree(request); |
3245 | } | 2996 | } |
3246 | out: | ||
3247 | cfg80211_unlock_rdev(rdev); | ||
3248 | dev_put(dev); | ||
3249 | out_rtnl: | ||
3250 | rtnl_unlock(); | ||
3251 | 2997 | ||
3252 | return err; | 2998 | return err; |
3253 | } | 2999 | } |
@@ -3306,6 +3052,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
3306 | } | 3052 | } |
3307 | 3053 | ||
3308 | switch (wdev->iftype) { | 3054 | switch (wdev->iftype) { |
3055 | case NL80211_IFTYPE_P2P_CLIENT: | ||
3309 | case NL80211_IFTYPE_STATION: | 3056 | case NL80211_IFTYPE_STATION: |
3310 | if (intbss == wdev->current_bss) | 3057 | if (intbss == wdev->current_bss) |
3311 | NLA_PUT_U32(msg, NL80211_BSS_STATUS, | 3058 | NLA_PUT_U32(msg, NL80211_BSS_STATUS, |
@@ -3343,25 +3090,12 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3343 | struct net_device *dev; | 3090 | struct net_device *dev; |
3344 | struct cfg80211_internal_bss *scan; | 3091 | struct cfg80211_internal_bss *scan; |
3345 | struct wireless_dev *wdev; | 3092 | struct wireless_dev *wdev; |
3346 | int ifidx = cb->args[0]; | ||
3347 | int start = cb->args[1], idx = 0; | 3093 | int start = cb->args[1], idx = 0; |
3348 | int err; | 3094 | int err; |
3349 | 3095 | ||
3350 | if (!ifidx) | 3096 | err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev); |
3351 | ifidx = nl80211_get_ifidx(cb); | 3097 | if (err) |
3352 | if (ifidx < 0) | 3098 | return err; |
3353 | return ifidx; | ||
3354 | cb->args[0] = ifidx; | ||
3355 | |||
3356 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
3357 | if (!dev) | ||
3358 | return -ENODEV; | ||
3359 | |||
3360 | rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
3361 | if (IS_ERR(rdev)) { | ||
3362 | err = PTR_ERR(rdev); | ||
3363 | goto out_put_netdev; | ||
3364 | } | ||
3365 | 3099 | ||
3366 | wdev = dev->ieee80211_ptr; | 3100 | wdev = dev->ieee80211_ptr; |
3367 | 3101 | ||
@@ -3377,21 +3111,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3377 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3111 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3378 | rdev, wdev, scan) < 0) { | 3112 | rdev, wdev, scan) < 0) { |
3379 | idx--; | 3113 | idx--; |
3380 | goto out; | 3114 | break; |
3381 | } | 3115 | } |
3382 | } | 3116 | } |
3383 | 3117 | ||
3384 | out: | ||
3385 | spin_unlock_bh(&rdev->bss_lock); | 3118 | spin_unlock_bh(&rdev->bss_lock); |
3386 | wdev_unlock(wdev); | 3119 | wdev_unlock(wdev); |
3387 | 3120 | ||
3388 | cb->args[1] = idx; | 3121 | cb->args[1] = idx; |
3389 | err = skb->len; | 3122 | nl80211_finish_netdev_dump(rdev); |
3390 | cfg80211_unlock_rdev(rdev); | ||
3391 | out_put_netdev: | ||
3392 | dev_put(dev); | ||
3393 | 3123 | ||
3394 | return err; | 3124 | return skb->len; |
3395 | } | 3125 | } |
3396 | 3126 | ||
3397 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | 3127 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, |
@@ -3421,6 +3151,23 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | |||
3421 | if (survey->filled & SURVEY_INFO_NOISE_DBM) | 3151 | if (survey->filled & SURVEY_INFO_NOISE_DBM) |
3422 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, | 3152 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, |
3423 | survey->noise); | 3153 | survey->noise); |
3154 | if (survey->filled & SURVEY_INFO_IN_USE) | ||
3155 | NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE); | ||
3156 | if (survey->filled & SURVEY_INFO_CHANNEL_TIME) | ||
3157 | NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME, | ||
3158 | survey->channel_time); | ||
3159 | if (survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY) | ||
3160 | NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, | ||
3161 | survey->channel_time_busy); | ||
3162 | if (survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) | ||
3163 | NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, | ||
3164 | survey->channel_time_ext_busy); | ||
3165 | if (survey->filled & SURVEY_INFO_CHANNEL_TIME_RX) | ||
3166 | NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX, | ||
3167 | survey->channel_time_rx); | ||
3168 | if (survey->filled & SURVEY_INFO_CHANNEL_TIME_TX) | ||
3169 | NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX, | ||
3170 | survey->channel_time_tx); | ||
3424 | 3171 | ||
3425 | nla_nest_end(msg, infoattr); | 3172 | nla_nest_end(msg, infoattr); |
3426 | 3173 | ||
@@ -3437,29 +3184,12 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3437 | struct survey_info survey; | 3184 | struct survey_info survey; |
3438 | struct cfg80211_registered_device *dev; | 3185 | struct cfg80211_registered_device *dev; |
3439 | struct net_device *netdev; | 3186 | struct net_device *netdev; |
3440 | int ifidx = cb->args[0]; | ||
3441 | int survey_idx = cb->args[1]; | 3187 | int survey_idx = cb->args[1]; |
3442 | int res; | 3188 | int res; |
3443 | 3189 | ||
3444 | if (!ifidx) | 3190 | res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
3445 | ifidx = nl80211_get_ifidx(cb); | 3191 | if (res) |
3446 | if (ifidx < 0) | 3192 | return res; |
3447 | return ifidx; | ||
3448 | cb->args[0] = ifidx; | ||
3449 | |||
3450 | rtnl_lock(); | ||
3451 | |||
3452 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
3453 | if (!netdev) { | ||
3454 | res = -ENODEV; | ||
3455 | goto out_rtnl; | ||
3456 | } | ||
3457 | |||
3458 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
3459 | if (IS_ERR(dev)) { | ||
3460 | res = PTR_ERR(dev); | ||
3461 | goto out_rtnl; | ||
3462 | } | ||
3463 | 3193 | ||
3464 | if (!dev->ops->dump_survey) { | 3194 | if (!dev->ops->dump_survey) { |
3465 | res = -EOPNOTSUPP; | 3195 | res = -EOPNOTSUPP; |
@@ -3487,10 +3217,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3487 | cb->args[1] = survey_idx; | 3217 | cb->args[1] = survey_idx; |
3488 | res = skb->len; | 3218 | res = skb->len; |
3489 | out_err: | 3219 | out_err: |
3490 | cfg80211_unlock_rdev(dev); | 3220 | nl80211_finish_netdev_dump(dev); |
3491 | out_rtnl: | ||
3492 | rtnl_unlock(); | ||
3493 | |||
3494 | return res; | 3221 | return res; |
3495 | } | 3222 | } |
3496 | 3223 | ||
@@ -3523,8 +3250,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher) | |||
3523 | 3250 | ||
3524 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | 3251 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) |
3525 | { | 3252 | { |
3526 | struct cfg80211_registered_device *rdev; | 3253 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3527 | struct net_device *dev; | 3254 | struct net_device *dev = info->user_ptr[1]; |
3528 | struct ieee80211_channel *chan; | 3255 | struct ieee80211_channel *chan; |
3529 | const u8 *bssid, *ssid, *ie = NULL; | 3256 | const u8 *bssid, *ssid, *ie = NULL; |
3530 | int err, ssid_len, ie_len = 0; | 3257 | int err, ssid_len, ie_len = 0; |
@@ -3552,6 +3279,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3552 | return err; | 3279 | return err; |
3553 | 3280 | ||
3554 | if (key.idx >= 0) { | 3281 | if (key.idx >= 0) { |
3282 | if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP) | ||
3283 | return -EINVAL; | ||
3555 | if (!key.p.key || !key.p.key_len) | 3284 | if (!key.p.key || !key.p.key_len) |
3556 | return -EINVAL; | 3285 | return -EINVAL; |
3557 | if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || | 3286 | if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || |
@@ -3566,34 +3295,31 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3566 | key.p.key = NULL; | 3295 | key.p.key = NULL; |
3567 | } | 3296 | } |
3568 | 3297 | ||
3569 | rtnl_lock(); | 3298 | if (key.idx >= 0) { |
3570 | 3299 | int i; | |
3571 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3300 | bool ok = false; |
3572 | if (err) | 3301 | for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) { |
3573 | goto unlock_rtnl; | 3302 | if (key.p.cipher == rdev->wiphy.cipher_suites[i]) { |
3574 | 3303 | ok = true; | |
3575 | if (!rdev->ops->auth) { | 3304 | break; |
3576 | err = -EOPNOTSUPP; | 3305 | } |
3577 | goto out; | 3306 | } |
3307 | if (!ok) | ||
3308 | return -EINVAL; | ||
3578 | } | 3309 | } |
3579 | 3310 | ||
3580 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 3311 | if (!rdev->ops->auth) |
3581 | err = -EOPNOTSUPP; | 3312 | return -EOPNOTSUPP; |
3582 | goto out; | ||
3583 | } | ||
3584 | 3313 | ||
3585 | if (!netif_running(dev)) { | 3314 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3586 | err = -ENETDOWN; | 3315 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3587 | goto out; | 3316 | return -EOPNOTSUPP; |
3588 | } | ||
3589 | 3317 | ||
3590 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3318 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3591 | chan = ieee80211_get_channel(&rdev->wiphy, | 3319 | chan = ieee80211_get_channel(&rdev->wiphy, |
3592 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3320 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3593 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { | 3321 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) |
3594 | err = -EINVAL; | 3322 | return -EINVAL; |
3595 | goto out; | ||
3596 | } | ||
3597 | 3323 | ||
3598 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3324 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3599 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3325 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
@@ -3604,27 +3330,19 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3604 | } | 3330 | } |
3605 | 3331 | ||
3606 | auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | 3332 | auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); |
3607 | if (!nl80211_valid_auth_type(auth_type)) { | 3333 | if (!nl80211_valid_auth_type(auth_type)) |
3608 | err = -EINVAL; | 3334 | return -EINVAL; |
3609 | goto out; | ||
3610 | } | ||
3611 | 3335 | ||
3612 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3336 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3613 | 3337 | ||
3614 | err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | 3338 | return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
3615 | ssid, ssid_len, ie, ie_len, | 3339 | ssid, ssid_len, ie, ie_len, |
3616 | key.p.key, key.p.key_len, key.idx, | 3340 | key.p.key, key.p.key_len, key.idx, |
3617 | local_state_change); | 3341 | local_state_change); |
3618 | |||
3619 | out: | ||
3620 | cfg80211_unlock_rdev(rdev); | ||
3621 | dev_put(dev); | ||
3622 | unlock_rtnl: | ||
3623 | rtnl_unlock(); | ||
3624 | return err; | ||
3625 | } | 3342 | } |
3626 | 3343 | ||
3627 | static int nl80211_crypto_settings(struct genl_info *info, | 3344 | static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, |
3345 | struct genl_info *info, | ||
3628 | struct cfg80211_crypto_settings *settings, | 3346 | struct cfg80211_crypto_settings *settings, |
3629 | int cipher_limit) | 3347 | int cipher_limit) |
3630 | { | 3348 | { |
@@ -3632,6 +3350,19 @@ static int nl80211_crypto_settings(struct genl_info *info, | |||
3632 | 3350 | ||
3633 | settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; | 3351 | settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; |
3634 | 3352 | ||
3353 | if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) { | ||
3354 | u16 proto; | ||
3355 | proto = nla_get_u16( | ||
3356 | info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]); | ||
3357 | settings->control_port_ethertype = cpu_to_be16(proto); | ||
3358 | if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && | ||
3359 | proto != ETH_P_PAE) | ||
3360 | return -EINVAL; | ||
3361 | if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]) | ||
3362 | settings->control_port_no_encrypt = true; | ||
3363 | } else | ||
3364 | settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE); | ||
3365 | |||
3635 | if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { | 3366 | if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { |
3636 | void *data; | 3367 | void *data; |
3637 | int len, i; | 3368 | int len, i; |
@@ -3691,8 +3422,8 @@ static int nl80211_crypto_settings(struct genl_info *info, | |||
3691 | 3422 | ||
3692 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | 3423 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) |
3693 | { | 3424 | { |
3694 | struct cfg80211_registered_device *rdev; | 3425 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3695 | struct net_device *dev; | 3426 | struct net_device *dev = info->user_ptr[1]; |
3696 | struct cfg80211_crypto_settings crypto; | 3427 | struct cfg80211_crypto_settings crypto; |
3697 | struct ieee80211_channel *chan; | 3428 | struct ieee80211_channel *chan; |
3698 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 3429 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
@@ -3707,35 +3438,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3707 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 3438 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
3708 | return -EINVAL; | 3439 | return -EINVAL; |
3709 | 3440 | ||
3710 | rtnl_lock(); | 3441 | if (!rdev->ops->assoc) |
3711 | 3442 | return -EOPNOTSUPP; | |
3712 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3713 | if (err) | ||
3714 | goto unlock_rtnl; | ||
3715 | |||
3716 | if (!rdev->ops->assoc) { | ||
3717 | err = -EOPNOTSUPP; | ||
3718 | goto out; | ||
3719 | } | ||
3720 | |||
3721 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
3722 | err = -EOPNOTSUPP; | ||
3723 | goto out; | ||
3724 | } | ||
3725 | 3443 | ||
3726 | if (!netif_running(dev)) { | 3444 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3727 | err = -ENETDOWN; | 3445 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3728 | goto out; | 3446 | return -EOPNOTSUPP; |
3729 | } | ||
3730 | 3447 | ||
3731 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3448 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3732 | 3449 | ||
3733 | chan = ieee80211_get_channel(&rdev->wiphy, | 3450 | chan = ieee80211_get_channel(&rdev->wiphy, |
3734 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3451 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3735 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { | 3452 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) |
3736 | err = -EINVAL; | 3453 | return -EINVAL; |
3737 | goto out; | ||
3738 | } | ||
3739 | 3454 | ||
3740 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3455 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3741 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3456 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
@@ -3750,35 +3465,28 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3750 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); | 3465 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); |
3751 | if (mfp == NL80211_MFP_REQUIRED) | 3466 | if (mfp == NL80211_MFP_REQUIRED) |
3752 | use_mfp = true; | 3467 | use_mfp = true; |
3753 | else if (mfp != NL80211_MFP_NO) { | 3468 | else if (mfp != NL80211_MFP_NO) |
3754 | err = -EINVAL; | 3469 | return -EINVAL; |
3755 | goto out; | ||
3756 | } | ||
3757 | } | 3470 | } |
3758 | 3471 | ||
3759 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) | 3472 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) |
3760 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); | 3473 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); |
3761 | 3474 | ||
3762 | err = nl80211_crypto_settings(info, &crypto, 1); | 3475 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); |
3763 | if (!err) | 3476 | if (!err) |
3764 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 3477 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
3765 | ssid, ssid_len, ie, ie_len, use_mfp, | 3478 | ssid, ssid_len, ie, ie_len, use_mfp, |
3766 | &crypto); | 3479 | &crypto); |
3767 | 3480 | ||
3768 | out: | ||
3769 | cfg80211_unlock_rdev(rdev); | ||
3770 | dev_put(dev); | ||
3771 | unlock_rtnl: | ||
3772 | rtnl_unlock(); | ||
3773 | return err; | 3481 | return err; |
3774 | } | 3482 | } |
3775 | 3483 | ||
3776 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | 3484 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) |
3777 | { | 3485 | { |
3778 | struct cfg80211_registered_device *rdev; | 3486 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3779 | struct net_device *dev; | 3487 | struct net_device *dev = info->user_ptr[1]; |
3780 | const u8 *ie = NULL, *bssid; | 3488 | const u8 *ie = NULL, *bssid; |
3781 | int err, ie_len = 0; | 3489 | int ie_len = 0; |
3782 | u16 reason_code; | 3490 | u16 reason_code; |
3783 | bool local_state_change; | 3491 | bool local_state_change; |
3784 | 3492 | ||
@@ -3791,34 +3499,19 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3791 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3499 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
3792 | return -EINVAL; | 3500 | return -EINVAL; |
3793 | 3501 | ||
3794 | rtnl_lock(); | 3502 | if (!rdev->ops->deauth) |
3795 | 3503 | return -EOPNOTSUPP; | |
3796 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3797 | if (err) | ||
3798 | goto unlock_rtnl; | ||
3799 | |||
3800 | if (!rdev->ops->deauth) { | ||
3801 | err = -EOPNOTSUPP; | ||
3802 | goto out; | ||
3803 | } | ||
3804 | |||
3805 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
3806 | err = -EOPNOTSUPP; | ||
3807 | goto out; | ||
3808 | } | ||
3809 | 3504 | ||
3810 | if (!netif_running(dev)) { | 3505 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3811 | err = -ENETDOWN; | 3506 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3812 | goto out; | 3507 | return -EOPNOTSUPP; |
3813 | } | ||
3814 | 3508 | ||
3815 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3509 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3816 | 3510 | ||
3817 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3511 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3818 | if (reason_code == 0) { | 3512 | if (reason_code == 0) { |
3819 | /* Reason Code 0 is reserved */ | 3513 | /* Reason Code 0 is reserved */ |
3820 | err = -EINVAL; | 3514 | return -EINVAL; |
3821 | goto out; | ||
3822 | } | 3515 | } |
3823 | 3516 | ||
3824 | if (info->attrs[NL80211_ATTR_IE]) { | 3517 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -3828,23 +3521,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3828 | 3521 | ||
3829 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3522 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3830 | 3523 | ||
3831 | err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, | 3524 | return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, |
3832 | local_state_change); | 3525 | local_state_change); |
3833 | |||
3834 | out: | ||
3835 | cfg80211_unlock_rdev(rdev); | ||
3836 | dev_put(dev); | ||
3837 | unlock_rtnl: | ||
3838 | rtnl_unlock(); | ||
3839 | return err; | ||
3840 | } | 3526 | } |
3841 | 3527 | ||
3842 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | 3528 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) |
3843 | { | 3529 | { |
3844 | struct cfg80211_registered_device *rdev; | 3530 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3845 | struct net_device *dev; | 3531 | struct net_device *dev = info->user_ptr[1]; |
3846 | const u8 *ie = NULL, *bssid; | 3532 | const u8 *ie = NULL, *bssid; |
3847 | int err, ie_len = 0; | 3533 | int ie_len = 0; |
3848 | u16 reason_code; | 3534 | u16 reason_code; |
3849 | bool local_state_change; | 3535 | bool local_state_change; |
3850 | 3536 | ||
@@ -3857,34 +3543,19 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3857 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3543 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
3858 | return -EINVAL; | 3544 | return -EINVAL; |
3859 | 3545 | ||
3860 | rtnl_lock(); | 3546 | if (!rdev->ops->disassoc) |
3861 | 3547 | return -EOPNOTSUPP; | |
3862 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3863 | if (err) | ||
3864 | goto unlock_rtnl; | ||
3865 | |||
3866 | if (!rdev->ops->disassoc) { | ||
3867 | err = -EOPNOTSUPP; | ||
3868 | goto out; | ||
3869 | } | ||
3870 | |||
3871 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
3872 | err = -EOPNOTSUPP; | ||
3873 | goto out; | ||
3874 | } | ||
3875 | 3548 | ||
3876 | if (!netif_running(dev)) { | 3549 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3877 | err = -ENETDOWN; | 3550 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3878 | goto out; | 3551 | return -EOPNOTSUPP; |
3879 | } | ||
3880 | 3552 | ||
3881 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3553 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3882 | 3554 | ||
3883 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3555 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3884 | if (reason_code == 0) { | 3556 | if (reason_code == 0) { |
3885 | /* Reason Code 0 is reserved */ | 3557 | /* Reason Code 0 is reserved */ |
3886 | err = -EINVAL; | 3558 | return -EINVAL; |
3887 | goto out; | ||
3888 | } | 3559 | } |
3889 | 3560 | ||
3890 | if (info->attrs[NL80211_ATTR_IE]) { | 3561 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -3894,21 +3565,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3894 | 3565 | ||
3895 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3566 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3896 | 3567 | ||
3897 | err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, | 3568 | return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, |
3898 | local_state_change); | 3569 | local_state_change); |
3899 | |||
3900 | out: | ||
3901 | cfg80211_unlock_rdev(rdev); | ||
3902 | dev_put(dev); | ||
3903 | unlock_rtnl: | ||
3904 | rtnl_unlock(); | ||
3905 | return err; | ||
3906 | } | 3570 | } |
3907 | 3571 | ||
3908 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | 3572 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) |
3909 | { | 3573 | { |
3910 | struct cfg80211_registered_device *rdev; | 3574 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3911 | struct net_device *dev; | 3575 | struct net_device *dev = info->user_ptr[1]; |
3912 | struct cfg80211_ibss_params ibss; | 3576 | struct cfg80211_ibss_params ibss; |
3913 | struct wiphy *wiphy; | 3577 | struct wiphy *wiphy; |
3914 | struct cfg80211_cached_keys *connkeys = NULL; | 3578 | struct cfg80211_cached_keys *connkeys = NULL; |
@@ -3933,26 +3597,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3933 | return -EINVAL; | 3597 | return -EINVAL; |
3934 | } | 3598 | } |
3935 | 3599 | ||
3936 | rtnl_lock(); | 3600 | if (!rdev->ops->join_ibss) |
3937 | 3601 | return -EOPNOTSUPP; | |
3938 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3939 | if (err) | ||
3940 | goto unlock_rtnl; | ||
3941 | |||
3942 | if (!rdev->ops->join_ibss) { | ||
3943 | err = -EOPNOTSUPP; | ||
3944 | goto out; | ||
3945 | } | ||
3946 | |||
3947 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
3948 | err = -EOPNOTSUPP; | ||
3949 | goto out; | ||
3950 | } | ||
3951 | 3602 | ||
3952 | if (!netif_running(dev)) { | 3603 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) |
3953 | err = -ENETDOWN; | 3604 | return -EOPNOTSUPP; |
3954 | goto out; | ||
3955 | } | ||
3956 | 3605 | ||
3957 | wiphy = &rdev->wiphy; | 3606 | wiphy = &rdev->wiphy; |
3958 | 3607 | ||
@@ -3970,24 +3619,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3970 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3619 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3971 | if (!ibss.channel || | 3620 | if (!ibss.channel || |
3972 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || | 3621 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || |
3973 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) { | 3622 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) |
3974 | err = -EINVAL; | 3623 | return -EINVAL; |
3975 | goto out; | ||
3976 | } | ||
3977 | 3624 | ||
3978 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | 3625 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; |
3979 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; | 3626 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; |
3980 | 3627 | ||
3981 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { | ||
3982 | connkeys = nl80211_parse_connkeys(rdev, | ||
3983 | info->attrs[NL80211_ATTR_KEYS]); | ||
3984 | if (IS_ERR(connkeys)) { | ||
3985 | err = PTR_ERR(connkeys); | ||
3986 | connkeys = NULL; | ||
3987 | goto out; | ||
3988 | } | ||
3989 | } | ||
3990 | |||
3991 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { | 3628 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { |
3992 | u8 *rates = | 3629 | u8 *rates = |
3993 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 3630 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
@@ -3997,10 +3634,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3997 | wiphy->bands[ibss.channel->band]; | 3634 | wiphy->bands[ibss.channel->band]; |
3998 | int i, j; | 3635 | int i, j; |
3999 | 3636 | ||
4000 | if (n_rates == 0) { | 3637 | if (n_rates == 0) |
4001 | err = -EINVAL; | 3638 | return -EINVAL; |
4002 | goto out; | ||
4003 | } | ||
4004 | 3639 | ||
4005 | for (i = 0; i < n_rates; i++) { | 3640 | for (i = 0; i < n_rates; i++) { |
4006 | int rate = (rates[i] & 0x7f) * 5; | 3641 | int rate = (rates[i] & 0x7f) * 5; |
@@ -4013,77 +3648,36 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4013 | break; | 3648 | break; |
4014 | } | 3649 | } |
4015 | } | 3650 | } |
4016 | if (!found) { | 3651 | if (!found) |
4017 | err = -EINVAL; | 3652 | return -EINVAL; |
4018 | goto out; | ||
4019 | } | ||
4020 | } | ||
4021 | } else { | ||
4022 | /* | ||
4023 | * If no rates were explicitly configured, | ||
4024 | * use the mandatory rate set for 11b or | ||
4025 | * 11a for maximum compatibility. | ||
4026 | */ | ||
4027 | struct ieee80211_supported_band *sband = | ||
4028 | wiphy->bands[ibss.channel->band]; | ||
4029 | int j; | ||
4030 | u32 flag = ibss.channel->band == IEEE80211_BAND_5GHZ ? | ||
4031 | IEEE80211_RATE_MANDATORY_A : | ||
4032 | IEEE80211_RATE_MANDATORY_B; | ||
4033 | |||
4034 | for (j = 0; j < sband->n_bitrates; j++) { | ||
4035 | if (sband->bitrates[j].flags & flag) | ||
4036 | ibss.basic_rates |= BIT(j); | ||
4037 | } | 3653 | } |
4038 | } | 3654 | } |
4039 | 3655 | ||
4040 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); | 3656 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { |
3657 | connkeys = nl80211_parse_connkeys(rdev, | ||
3658 | info->attrs[NL80211_ATTR_KEYS]); | ||
3659 | if (IS_ERR(connkeys)) | ||
3660 | return PTR_ERR(connkeys); | ||
3661 | } | ||
4041 | 3662 | ||
4042 | out: | 3663 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); |
4043 | cfg80211_unlock_rdev(rdev); | ||
4044 | dev_put(dev); | ||
4045 | unlock_rtnl: | ||
4046 | if (err) | 3664 | if (err) |
4047 | kfree(connkeys); | 3665 | kfree(connkeys); |
4048 | rtnl_unlock(); | ||
4049 | return err; | 3666 | return err; |
4050 | } | 3667 | } |
4051 | 3668 | ||
4052 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | 3669 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) |
4053 | { | 3670 | { |
4054 | struct cfg80211_registered_device *rdev; | 3671 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4055 | struct net_device *dev; | 3672 | struct net_device *dev = info->user_ptr[1]; |
4056 | int err; | ||
4057 | |||
4058 | rtnl_lock(); | ||
4059 | |||
4060 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4061 | if (err) | ||
4062 | goto unlock_rtnl; | ||
4063 | |||
4064 | if (!rdev->ops->leave_ibss) { | ||
4065 | err = -EOPNOTSUPP; | ||
4066 | goto out; | ||
4067 | } | ||
4068 | 3673 | ||
4069 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | 3674 | if (!rdev->ops->leave_ibss) |
4070 | err = -EOPNOTSUPP; | 3675 | return -EOPNOTSUPP; |
4071 | goto out; | ||
4072 | } | ||
4073 | |||
4074 | if (!netif_running(dev)) { | ||
4075 | err = -ENETDOWN; | ||
4076 | goto out; | ||
4077 | } | ||
4078 | 3676 | ||
4079 | err = cfg80211_leave_ibss(rdev, dev, false); | 3677 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) |
3678 | return -EOPNOTSUPP; | ||
4080 | 3679 | ||
4081 | out: | 3680 | return cfg80211_leave_ibss(rdev, dev, false); |
4082 | cfg80211_unlock_rdev(rdev); | ||
4083 | dev_put(dev); | ||
4084 | unlock_rtnl: | ||
4085 | rtnl_unlock(); | ||
4086 | return err; | ||
4087 | } | 3681 | } |
4088 | 3682 | ||
4089 | #ifdef CONFIG_NL80211_TESTMODE | 3683 | #ifdef CONFIG_NL80211_TESTMODE |
@@ -4093,20 +3687,12 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = { | |||
4093 | 3687 | ||
4094 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | 3688 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) |
4095 | { | 3689 | { |
4096 | struct cfg80211_registered_device *rdev; | 3690 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4097 | int err; | 3691 | int err; |
4098 | 3692 | ||
4099 | if (!info->attrs[NL80211_ATTR_TESTDATA]) | 3693 | if (!info->attrs[NL80211_ATTR_TESTDATA]) |
4100 | return -EINVAL; | 3694 | return -EINVAL; |
4101 | 3695 | ||
4102 | rtnl_lock(); | ||
4103 | |||
4104 | rdev = cfg80211_get_dev_from_info(info); | ||
4105 | if (IS_ERR(rdev)) { | ||
4106 | err = PTR_ERR(rdev); | ||
4107 | goto unlock_rtnl; | ||
4108 | } | ||
4109 | |||
4110 | err = -EOPNOTSUPP; | 3696 | err = -EOPNOTSUPP; |
4111 | if (rdev->ops->testmode_cmd) { | 3697 | if (rdev->ops->testmode_cmd) { |
4112 | rdev->testmode_info = info; | 3698 | rdev->testmode_info = info; |
@@ -4116,10 +3702,6 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | |||
4116 | rdev->testmode_info = NULL; | 3702 | rdev->testmode_info = NULL; |
4117 | } | 3703 | } |
4118 | 3704 | ||
4119 | cfg80211_unlock_rdev(rdev); | ||
4120 | |||
4121 | unlock_rtnl: | ||
4122 | rtnl_unlock(); | ||
4123 | return err; | 3705 | return err; |
4124 | } | 3706 | } |
4125 | 3707 | ||
@@ -4210,8 +3792,8 @@ EXPORT_SYMBOL(cfg80211_testmode_event); | |||
4210 | 3792 | ||
4211 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | 3793 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) |
4212 | { | 3794 | { |
4213 | struct cfg80211_registered_device *rdev; | 3795 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4214 | struct net_device *dev; | 3796 | struct net_device *dev = info->user_ptr[1]; |
4215 | struct cfg80211_connect_params connect; | 3797 | struct cfg80211_connect_params connect; |
4216 | struct wiphy *wiphy; | 3798 | struct wiphy *wiphy; |
4217 | struct cfg80211_cached_keys *connkeys = NULL; | 3799 | struct cfg80211_cached_keys *connkeys = NULL; |
@@ -4236,25 +3818,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
4236 | 3818 | ||
4237 | connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; | 3819 | connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; |
4238 | 3820 | ||
4239 | err = nl80211_crypto_settings(info, &connect.crypto, | 3821 | err = nl80211_crypto_settings(rdev, info, &connect.crypto, |
4240 | NL80211_MAX_NR_CIPHER_SUITES); | 3822 | NL80211_MAX_NR_CIPHER_SUITES); |
4241 | if (err) | 3823 | if (err) |
4242 | return err; | 3824 | return err; |
4243 | rtnl_lock(); | ||
4244 | 3825 | ||
4245 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3826 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4246 | if (err) | 3827 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4247 | goto unlock_rtnl; | 3828 | return -EOPNOTSUPP; |
4248 | |||
4249 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
4250 | err = -EOPNOTSUPP; | ||
4251 | goto out; | ||
4252 | } | ||
4253 | |||
4254 | if (!netif_running(dev)) { | ||
4255 | err = -ENETDOWN; | ||
4256 | goto out; | ||
4257 | } | ||
4258 | 3829 | ||
4259 | wiphy = &rdev->wiphy; | 3830 | wiphy = &rdev->wiphy; |
4260 | 3831 | ||
@@ -4273,39 +3844,27 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
4273 | ieee80211_get_channel(wiphy, | 3844 | ieee80211_get_channel(wiphy, |
4274 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3845 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
4275 | if (!connect.channel || | 3846 | if (!connect.channel || |
4276 | connect.channel->flags & IEEE80211_CHAN_DISABLED) { | 3847 | connect.channel->flags & IEEE80211_CHAN_DISABLED) |
4277 | err = -EINVAL; | 3848 | return -EINVAL; |
4278 | goto out; | ||
4279 | } | ||
4280 | } | 3849 | } |
4281 | 3850 | ||
4282 | if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { | 3851 | if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { |
4283 | connkeys = nl80211_parse_connkeys(rdev, | 3852 | connkeys = nl80211_parse_connkeys(rdev, |
4284 | info->attrs[NL80211_ATTR_KEYS]); | 3853 | info->attrs[NL80211_ATTR_KEYS]); |
4285 | if (IS_ERR(connkeys)) { | 3854 | if (IS_ERR(connkeys)) |
4286 | err = PTR_ERR(connkeys); | 3855 | return PTR_ERR(connkeys); |
4287 | connkeys = NULL; | ||
4288 | goto out; | ||
4289 | } | ||
4290 | } | 3856 | } |
4291 | 3857 | ||
4292 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 3858 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
4293 | |||
4294 | out: | ||
4295 | cfg80211_unlock_rdev(rdev); | ||
4296 | dev_put(dev); | ||
4297 | unlock_rtnl: | ||
4298 | if (err) | 3859 | if (err) |
4299 | kfree(connkeys); | 3860 | kfree(connkeys); |
4300 | rtnl_unlock(); | ||
4301 | return err; | 3861 | return err; |
4302 | } | 3862 | } |
4303 | 3863 | ||
4304 | static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | 3864 | static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) |
4305 | { | 3865 | { |
4306 | struct cfg80211_registered_device *rdev; | 3866 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4307 | struct net_device *dev; | 3867 | struct net_device *dev = info->user_ptr[1]; |
4308 | int err; | ||
4309 | u16 reason; | 3868 | u16 reason; |
4310 | 3869 | ||
4311 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3870 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
@@ -4316,35 +3875,16 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | |||
4316 | if (reason == 0) | 3875 | if (reason == 0) |
4317 | return -EINVAL; | 3876 | return -EINVAL; |
4318 | 3877 | ||
4319 | rtnl_lock(); | 3878 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4320 | 3879 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) | |
4321 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3880 | return -EOPNOTSUPP; |
4322 | if (err) | ||
4323 | goto unlock_rtnl; | ||
4324 | |||
4325 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
4326 | err = -EOPNOTSUPP; | ||
4327 | goto out; | ||
4328 | } | ||
4329 | |||
4330 | if (!netif_running(dev)) { | ||
4331 | err = -ENETDOWN; | ||
4332 | goto out; | ||
4333 | } | ||
4334 | |||
4335 | err = cfg80211_disconnect(rdev, dev, reason, true); | ||
4336 | 3881 | ||
4337 | out: | 3882 | return cfg80211_disconnect(rdev, dev, reason, true); |
4338 | cfg80211_unlock_rdev(rdev); | ||
4339 | dev_put(dev); | ||
4340 | unlock_rtnl: | ||
4341 | rtnl_unlock(); | ||
4342 | return err; | ||
4343 | } | 3883 | } |
4344 | 3884 | ||
4345 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | 3885 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) |
4346 | { | 3886 | { |
4347 | struct cfg80211_registered_device *rdev; | 3887 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4348 | struct net *net; | 3888 | struct net *net; |
4349 | int err; | 3889 | int err; |
4350 | u32 pid; | 3890 | u32 pid; |
@@ -4354,43 +3894,26 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | |||
4354 | 3894 | ||
4355 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); | 3895 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); |
4356 | 3896 | ||
4357 | rtnl_lock(); | ||
4358 | |||
4359 | rdev = cfg80211_get_dev_from_info(info); | ||
4360 | if (IS_ERR(rdev)) { | ||
4361 | err = PTR_ERR(rdev); | ||
4362 | goto out_rtnl; | ||
4363 | } | ||
4364 | |||
4365 | net = get_net_ns_by_pid(pid); | 3897 | net = get_net_ns_by_pid(pid); |
4366 | if (IS_ERR(net)) { | 3898 | if (IS_ERR(net)) |
4367 | err = PTR_ERR(net); | 3899 | return PTR_ERR(net); |
4368 | goto out; | ||
4369 | } | ||
4370 | 3900 | ||
4371 | err = 0; | 3901 | err = 0; |
4372 | 3902 | ||
4373 | /* check if anything to do */ | 3903 | /* check if anything to do */ |
4374 | if (net_eq(wiphy_net(&rdev->wiphy), net)) | 3904 | if (!net_eq(wiphy_net(&rdev->wiphy), net)) |
4375 | goto out_put_net; | 3905 | err = cfg80211_switch_netns(rdev, net); |
4376 | 3906 | ||
4377 | err = cfg80211_switch_netns(rdev, net); | ||
4378 | out_put_net: | ||
4379 | put_net(net); | 3907 | put_net(net); |
4380 | out: | ||
4381 | cfg80211_unlock_rdev(rdev); | ||
4382 | out_rtnl: | ||
4383 | rtnl_unlock(); | ||
4384 | return err; | 3908 | return err; |
4385 | } | 3909 | } |
4386 | 3910 | ||
4387 | static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | 3911 | static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) |
4388 | { | 3912 | { |
4389 | struct cfg80211_registered_device *rdev; | 3913 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4390 | int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, | 3914 | int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, |
4391 | struct cfg80211_pmksa *pmksa) = NULL; | 3915 | struct cfg80211_pmksa *pmksa) = NULL; |
4392 | int err; | 3916 | struct net_device *dev = info->user_ptr[1]; |
4393 | struct net_device *dev; | ||
4394 | struct cfg80211_pmksa pmksa; | 3917 | struct cfg80211_pmksa pmksa; |
4395 | 3918 | ||
4396 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); | 3919 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); |
@@ -4401,19 +3924,12 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4401 | if (!info->attrs[NL80211_ATTR_PMKID]) | 3924 | if (!info->attrs[NL80211_ATTR_PMKID]) |
4402 | return -EINVAL; | 3925 | return -EINVAL; |
4403 | 3926 | ||
4404 | rtnl_lock(); | ||
4405 | |||
4406 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4407 | if (err) | ||
4408 | goto out_rtnl; | ||
4409 | |||
4410 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); | 3927 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); |
4411 | pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3928 | pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
4412 | 3929 | ||
4413 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 3930 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4414 | err = -EOPNOTSUPP; | 3931 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4415 | goto out; | 3932 | return -EOPNOTSUPP; |
4416 | } | ||
4417 | 3933 | ||
4418 | switch (info->genlhdr->cmd) { | 3934 | switch (info->genlhdr->cmd) { |
4419 | case NL80211_CMD_SET_PMKSA: | 3935 | case NL80211_CMD_SET_PMKSA: |
@@ -4427,61 +3943,32 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4427 | break; | 3943 | break; |
4428 | } | 3944 | } |
4429 | 3945 | ||
4430 | if (!rdev_ops) { | 3946 | if (!rdev_ops) |
4431 | err = -EOPNOTSUPP; | 3947 | return -EOPNOTSUPP; |
4432 | goto out; | ||
4433 | } | ||
4434 | |||
4435 | err = rdev_ops(&rdev->wiphy, dev, &pmksa); | ||
4436 | |||
4437 | out: | ||
4438 | cfg80211_unlock_rdev(rdev); | ||
4439 | dev_put(dev); | ||
4440 | out_rtnl: | ||
4441 | rtnl_unlock(); | ||
4442 | 3948 | ||
4443 | return err; | 3949 | return rdev_ops(&rdev->wiphy, dev, &pmksa); |
4444 | } | 3950 | } |
4445 | 3951 | ||
4446 | static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) | 3952 | static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) |
4447 | { | 3953 | { |
4448 | struct cfg80211_registered_device *rdev; | 3954 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4449 | int err; | 3955 | struct net_device *dev = info->user_ptr[1]; |
4450 | struct net_device *dev; | ||
4451 | |||
4452 | rtnl_lock(); | ||
4453 | |||
4454 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4455 | if (err) | ||
4456 | goto out_rtnl; | ||
4457 | |||
4458 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
4459 | err = -EOPNOTSUPP; | ||
4460 | goto out; | ||
4461 | } | ||
4462 | |||
4463 | if (!rdev->ops->flush_pmksa) { | ||
4464 | err = -EOPNOTSUPP; | ||
4465 | goto out; | ||
4466 | } | ||
4467 | |||
4468 | err = rdev->ops->flush_pmksa(&rdev->wiphy, dev); | ||
4469 | 3956 | ||
4470 | out: | 3957 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4471 | cfg80211_unlock_rdev(rdev); | 3958 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4472 | dev_put(dev); | 3959 | return -EOPNOTSUPP; |
4473 | out_rtnl: | ||
4474 | rtnl_unlock(); | ||
4475 | 3960 | ||
4476 | return err; | 3961 | if (!rdev->ops->flush_pmksa) |
3962 | return -EOPNOTSUPP; | ||
4477 | 3963 | ||
3964 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); | ||
4478 | } | 3965 | } |
4479 | 3966 | ||
4480 | static int nl80211_remain_on_channel(struct sk_buff *skb, | 3967 | static int nl80211_remain_on_channel(struct sk_buff *skb, |
4481 | struct genl_info *info) | 3968 | struct genl_info *info) |
4482 | { | 3969 | { |
4483 | struct cfg80211_registered_device *rdev; | 3970 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4484 | struct net_device *dev; | 3971 | struct net_device *dev = info->user_ptr[1]; |
4485 | struct ieee80211_channel *chan; | 3972 | struct ieee80211_channel *chan; |
4486 | struct sk_buff *msg; | 3973 | struct sk_buff *msg; |
4487 | void *hdr; | 3974 | void *hdr; |
@@ -4503,21 +3990,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4503 | if (!duration || !msecs_to_jiffies(duration) || duration > 5000) | 3990 | if (!duration || !msecs_to_jiffies(duration) || duration > 5000) |
4504 | return -EINVAL; | 3991 | return -EINVAL; |
4505 | 3992 | ||
4506 | rtnl_lock(); | 3993 | if (!rdev->ops->remain_on_channel) |
4507 | 3994 | return -EOPNOTSUPP; | |
4508 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4509 | if (err) | ||
4510 | goto unlock_rtnl; | ||
4511 | |||
4512 | if (!rdev->ops->remain_on_channel) { | ||
4513 | err = -EOPNOTSUPP; | ||
4514 | goto out; | ||
4515 | } | ||
4516 | |||
4517 | if (!netif_running(dev)) { | ||
4518 | err = -ENETDOWN; | ||
4519 | goto out; | ||
4520 | } | ||
4521 | 3995 | ||
4522 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 3996 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
4523 | channel_type = nla_get_u32( | 3997 | channel_type = nla_get_u32( |
@@ -4525,24 +3999,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4525 | if (channel_type != NL80211_CHAN_NO_HT && | 3999 | if (channel_type != NL80211_CHAN_NO_HT && |
4526 | channel_type != NL80211_CHAN_HT20 && | 4000 | channel_type != NL80211_CHAN_HT20 && |
4527 | channel_type != NL80211_CHAN_HT40PLUS && | 4001 | channel_type != NL80211_CHAN_HT40PLUS && |
4528 | channel_type != NL80211_CHAN_HT40MINUS) { | 4002 | channel_type != NL80211_CHAN_HT40MINUS) |
4529 | err = -EINVAL; | 4003 | return -EINVAL; |
4530 | goto out; | ||
4531 | } | ||
4532 | } | 4004 | } |
4533 | 4005 | ||
4534 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 4006 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
4535 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | 4007 | chan = rdev_freq_to_chan(rdev, freq, channel_type); |
4536 | if (chan == NULL) { | 4008 | if (chan == NULL) |
4537 | err = -EINVAL; | 4009 | return -EINVAL; |
4538 | goto out; | ||
4539 | } | ||
4540 | 4010 | ||
4541 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4011 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4542 | if (!msg) { | 4012 | if (!msg) |
4543 | err = -ENOMEM; | 4013 | return -ENOMEM; |
4544 | goto out; | ||
4545 | } | ||
4546 | 4014 | ||
4547 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4015 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
4548 | NL80211_CMD_REMAIN_ON_CHANNEL); | 4016 | NL80211_CMD_REMAIN_ON_CHANNEL); |
@@ -4561,58 +4029,32 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4561 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | 4029 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); |
4562 | 4030 | ||
4563 | genlmsg_end(msg, hdr); | 4031 | genlmsg_end(msg, hdr); |
4564 | err = genlmsg_reply(msg, info); | 4032 | |
4565 | goto out; | 4033 | return genlmsg_reply(msg, info); |
4566 | 4034 | ||
4567 | nla_put_failure: | 4035 | nla_put_failure: |
4568 | err = -ENOBUFS; | 4036 | err = -ENOBUFS; |
4569 | free_msg: | 4037 | free_msg: |
4570 | nlmsg_free(msg); | 4038 | nlmsg_free(msg); |
4571 | out: | ||
4572 | cfg80211_unlock_rdev(rdev); | ||
4573 | dev_put(dev); | ||
4574 | unlock_rtnl: | ||
4575 | rtnl_unlock(); | ||
4576 | return err; | 4039 | return err; |
4577 | } | 4040 | } |
4578 | 4041 | ||
4579 | static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | 4042 | static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, |
4580 | struct genl_info *info) | 4043 | struct genl_info *info) |
4581 | { | 4044 | { |
4582 | struct cfg80211_registered_device *rdev; | 4045 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4583 | struct net_device *dev; | 4046 | struct net_device *dev = info->user_ptr[1]; |
4584 | u64 cookie; | 4047 | u64 cookie; |
4585 | int err; | ||
4586 | 4048 | ||
4587 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 4049 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
4588 | return -EINVAL; | 4050 | return -EINVAL; |
4589 | 4051 | ||
4590 | rtnl_lock(); | 4052 | if (!rdev->ops->cancel_remain_on_channel) |
4591 | 4053 | return -EOPNOTSUPP; | |
4592 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4593 | if (err) | ||
4594 | goto unlock_rtnl; | ||
4595 | |||
4596 | if (!rdev->ops->cancel_remain_on_channel) { | ||
4597 | err = -EOPNOTSUPP; | ||
4598 | goto out; | ||
4599 | } | ||
4600 | |||
4601 | if (!netif_running(dev)) { | ||
4602 | err = -ENETDOWN; | ||
4603 | goto out; | ||
4604 | } | ||
4605 | 4054 | ||
4606 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 4055 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
4607 | 4056 | ||
4608 | err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); | 4057 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); |
4609 | |||
4610 | out: | ||
4611 | cfg80211_unlock_rdev(rdev); | ||
4612 | dev_put(dev); | ||
4613 | unlock_rtnl: | ||
4614 | rtnl_unlock(); | ||
4615 | return err; | ||
4616 | } | 4058 | } |
4617 | 4059 | ||
4618 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | 4060 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, |
@@ -4648,26 +4090,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4648 | struct genl_info *info) | 4090 | struct genl_info *info) |
4649 | { | 4091 | { |
4650 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; | 4092 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; |
4651 | struct cfg80211_registered_device *rdev; | 4093 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4652 | struct cfg80211_bitrate_mask mask; | 4094 | struct cfg80211_bitrate_mask mask; |
4653 | int err, rem, i; | 4095 | int rem, i; |
4654 | struct net_device *dev; | 4096 | struct net_device *dev = info->user_ptr[1]; |
4655 | struct nlattr *tx_rates; | 4097 | struct nlattr *tx_rates; |
4656 | struct ieee80211_supported_band *sband; | 4098 | struct ieee80211_supported_band *sband; |
4657 | 4099 | ||
4658 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) | 4100 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) |
4659 | return -EINVAL; | 4101 | return -EINVAL; |
4660 | 4102 | ||
4661 | rtnl_lock(); | 4103 | if (!rdev->ops->set_bitrate_mask) |
4662 | 4104 | return -EOPNOTSUPP; | |
4663 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4664 | if (err) | ||
4665 | goto unlock_rtnl; | ||
4666 | |||
4667 | if (!rdev->ops->set_bitrate_mask) { | ||
4668 | err = -EOPNOTSUPP; | ||
4669 | goto unlock; | ||
4670 | } | ||
4671 | 4105 | ||
4672 | memset(&mask, 0, sizeof(mask)); | 4106 | memset(&mask, 0, sizeof(mask)); |
4673 | /* Default to all rates enabled */ | 4107 | /* Default to all rates enabled */ |
@@ -4684,15 +4118,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4684 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) | 4118 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) |
4685 | { | 4119 | { |
4686 | enum ieee80211_band band = nla_type(tx_rates); | 4120 | enum ieee80211_band band = nla_type(tx_rates); |
4687 | if (band < 0 || band >= IEEE80211_NUM_BANDS) { | 4121 | if (band < 0 || band >= IEEE80211_NUM_BANDS) |
4688 | err = -EINVAL; | 4122 | return -EINVAL; |
4689 | goto unlock; | ||
4690 | } | ||
4691 | sband = rdev->wiphy.bands[band]; | 4123 | sband = rdev->wiphy.bands[band]; |
4692 | if (sband == NULL) { | 4124 | if (sband == NULL) |
4693 | err = -EINVAL; | 4125 | return -EINVAL; |
4694 | goto unlock; | ||
4695 | } | ||
4696 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), | 4126 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), |
4697 | nla_len(tx_rates), nl80211_txattr_policy); | 4127 | nla_len(tx_rates), nl80211_txattr_policy); |
4698 | if (tb[NL80211_TXRATE_LEGACY]) { | 4128 | if (tb[NL80211_TXRATE_LEGACY]) { |
@@ -4700,68 +4130,48 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4700 | sband, | 4130 | sband, |
4701 | nla_data(tb[NL80211_TXRATE_LEGACY]), | 4131 | nla_data(tb[NL80211_TXRATE_LEGACY]), |
4702 | nla_len(tb[NL80211_TXRATE_LEGACY])); | 4132 | nla_len(tb[NL80211_TXRATE_LEGACY])); |
4703 | if (mask.control[band].legacy == 0) { | 4133 | if (mask.control[band].legacy == 0) |
4704 | err = -EINVAL; | 4134 | return -EINVAL; |
4705 | goto unlock; | ||
4706 | } | ||
4707 | } | 4135 | } |
4708 | } | 4136 | } |
4709 | 4137 | ||
4710 | err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); | 4138 | return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); |
4711 | |||
4712 | unlock: | ||
4713 | dev_put(dev); | ||
4714 | cfg80211_unlock_rdev(rdev); | ||
4715 | unlock_rtnl: | ||
4716 | rtnl_unlock(); | ||
4717 | return err; | ||
4718 | } | 4139 | } |
4719 | 4140 | ||
4720 | static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) | 4141 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) |
4721 | { | 4142 | { |
4722 | struct cfg80211_registered_device *rdev; | 4143 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4723 | struct net_device *dev; | 4144 | struct net_device *dev = info->user_ptr[1]; |
4724 | int err; | 4145 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; |
4725 | 4146 | ||
4726 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) | 4147 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) |
4727 | return -EINVAL; | 4148 | return -EINVAL; |
4728 | 4149 | ||
4729 | if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1) | 4150 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) |
4730 | return -EINVAL; | 4151 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); |
4731 | |||
4732 | rtnl_lock(); | ||
4733 | |||
4734 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4735 | if (err) | ||
4736 | goto unlock_rtnl; | ||
4737 | 4152 | ||
4738 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 4153 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4739 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | 4154 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && |
4740 | err = -EOPNOTSUPP; | 4155 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4741 | goto out; | 4156 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4742 | } | 4157 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4158 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
4159 | return -EOPNOTSUPP; | ||
4743 | 4160 | ||
4744 | /* not much point in registering if we can't reply */ | 4161 | /* not much point in registering if we can't reply */ |
4745 | if (!rdev->ops->action) { | 4162 | if (!rdev->ops->mgmt_tx) |
4746 | err = -EOPNOTSUPP; | 4163 | return -EOPNOTSUPP; |
4747 | goto out; | ||
4748 | } | ||
4749 | 4164 | ||
4750 | err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid, | 4165 | return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, |
4166 | frame_type, | ||
4751 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), | 4167 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), |
4752 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); | 4168 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); |
4753 | out: | ||
4754 | cfg80211_unlock_rdev(rdev); | ||
4755 | dev_put(dev); | ||
4756 | unlock_rtnl: | ||
4757 | rtnl_unlock(); | ||
4758 | return err; | ||
4759 | } | 4169 | } |
4760 | 4170 | ||
4761 | static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | 4171 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) |
4762 | { | 4172 | { |
4763 | struct cfg80211_registered_device *rdev; | 4173 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4764 | struct net_device *dev; | 4174 | struct net_device *dev = info->user_ptr[1]; |
4765 | struct ieee80211_channel *chan; | 4175 | struct ieee80211_channel *chan; |
4766 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 4176 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
4767 | bool channel_type_valid = false; | 4177 | bool channel_type_valid = false; |
@@ -4775,27 +4185,16 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
4775 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 4185 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
4776 | return -EINVAL; | 4186 | return -EINVAL; |
4777 | 4187 | ||
4778 | rtnl_lock(); | 4188 | if (!rdev->ops->mgmt_tx) |
4779 | 4189 | return -EOPNOTSUPP; | |
4780 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4781 | if (err) | ||
4782 | goto unlock_rtnl; | ||
4783 | |||
4784 | if (!rdev->ops->action) { | ||
4785 | err = -EOPNOTSUPP; | ||
4786 | goto out; | ||
4787 | } | ||
4788 | 4190 | ||
4789 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 4191 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4790 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | 4192 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && |
4791 | err = -EOPNOTSUPP; | 4193 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4792 | goto out; | 4194 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4793 | } | 4195 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4794 | 4196 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | |
4795 | if (!netif_running(dev)) { | 4197 | return -EOPNOTSUPP; |
4796 | err = -ENETDOWN; | ||
4797 | goto out; | ||
4798 | } | ||
4799 | 4198 | ||
4800 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 4199 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
4801 | channel_type = nla_get_u32( | 4200 | channel_type = nla_get_u32( |
@@ -4803,147 +4202,104 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
4803 | if (channel_type != NL80211_CHAN_NO_HT && | 4202 | if (channel_type != NL80211_CHAN_NO_HT && |
4804 | channel_type != NL80211_CHAN_HT20 && | 4203 | channel_type != NL80211_CHAN_HT20 && |
4805 | channel_type != NL80211_CHAN_HT40PLUS && | 4204 | channel_type != NL80211_CHAN_HT40PLUS && |
4806 | channel_type != NL80211_CHAN_HT40MINUS) { | 4205 | channel_type != NL80211_CHAN_HT40MINUS) |
4807 | err = -EINVAL; | 4206 | return -EINVAL; |
4808 | goto out; | ||
4809 | } | ||
4810 | channel_type_valid = true; | 4207 | channel_type_valid = true; |
4811 | } | 4208 | } |
4812 | 4209 | ||
4813 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 4210 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
4814 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | 4211 | chan = rdev_freq_to_chan(rdev, freq, channel_type); |
4815 | if (chan == NULL) { | 4212 | if (chan == NULL) |
4816 | err = -EINVAL; | 4213 | return -EINVAL; |
4817 | goto out; | ||
4818 | } | ||
4819 | 4214 | ||
4820 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4215 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4821 | if (!msg) { | 4216 | if (!msg) |
4822 | err = -ENOMEM; | 4217 | return -ENOMEM; |
4823 | goto out; | ||
4824 | } | ||
4825 | 4218 | ||
4826 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4219 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
4827 | NL80211_CMD_ACTION); | 4220 | NL80211_CMD_FRAME); |
4828 | 4221 | ||
4829 | if (IS_ERR(hdr)) { | 4222 | if (IS_ERR(hdr)) { |
4830 | err = PTR_ERR(hdr); | 4223 | err = PTR_ERR(hdr); |
4831 | goto free_msg; | 4224 | goto free_msg; |
4832 | } | 4225 | } |
4833 | err = cfg80211_mlme_action(rdev, dev, chan, channel_type, | 4226 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type, |
4834 | channel_type_valid, | 4227 | channel_type_valid, |
4835 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 4228 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
4836 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 4229 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
4837 | &cookie); | 4230 | &cookie); |
4838 | if (err) | 4231 | if (err) |
4839 | goto free_msg; | 4232 | goto free_msg; |
4840 | 4233 | ||
4841 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | 4234 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); |
4842 | 4235 | ||
4843 | genlmsg_end(msg, hdr); | 4236 | genlmsg_end(msg, hdr); |
4844 | err = genlmsg_reply(msg, info); | 4237 | return genlmsg_reply(msg, info); |
4845 | goto out; | ||
4846 | 4238 | ||
4847 | nla_put_failure: | 4239 | nla_put_failure: |
4848 | err = -ENOBUFS; | 4240 | err = -ENOBUFS; |
4849 | free_msg: | 4241 | free_msg: |
4850 | nlmsg_free(msg); | 4242 | nlmsg_free(msg); |
4851 | out: | ||
4852 | cfg80211_unlock_rdev(rdev); | ||
4853 | dev_put(dev); | ||
4854 | unlock_rtnl: | ||
4855 | rtnl_unlock(); | ||
4856 | return err; | 4243 | return err; |
4857 | } | 4244 | } |
4858 | 4245 | ||
4859 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) | 4246 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) |
4860 | { | 4247 | { |
4861 | struct cfg80211_registered_device *rdev; | 4248 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4862 | struct wireless_dev *wdev; | 4249 | struct wireless_dev *wdev; |
4863 | struct net_device *dev; | 4250 | struct net_device *dev = info->user_ptr[1]; |
4864 | u8 ps_state; | 4251 | u8 ps_state; |
4865 | bool state; | 4252 | bool state; |
4866 | int err; | 4253 | int err; |
4867 | 4254 | ||
4868 | if (!info->attrs[NL80211_ATTR_PS_STATE]) { | 4255 | if (!info->attrs[NL80211_ATTR_PS_STATE]) |
4869 | err = -EINVAL; | 4256 | return -EINVAL; |
4870 | goto out; | ||
4871 | } | ||
4872 | 4257 | ||
4873 | ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); | 4258 | ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); |
4874 | 4259 | ||
4875 | if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) { | 4260 | if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) |
4876 | err = -EINVAL; | 4261 | return -EINVAL; |
4877 | goto out; | ||
4878 | } | ||
4879 | |||
4880 | rtnl_lock(); | ||
4881 | |||
4882 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4883 | if (err) | ||
4884 | goto unlock_rdev; | ||
4885 | 4262 | ||
4886 | wdev = dev->ieee80211_ptr; | 4263 | wdev = dev->ieee80211_ptr; |
4887 | 4264 | ||
4888 | if (!rdev->ops->set_power_mgmt) { | 4265 | if (!rdev->ops->set_power_mgmt) |
4889 | err = -EOPNOTSUPP; | 4266 | return -EOPNOTSUPP; |
4890 | goto unlock_rdev; | ||
4891 | } | ||
4892 | 4267 | ||
4893 | state = (ps_state == NL80211_PS_ENABLED) ? true : false; | 4268 | state = (ps_state == NL80211_PS_ENABLED) ? true : false; |
4894 | 4269 | ||
4895 | if (state == wdev->ps) | 4270 | if (state == wdev->ps) |
4896 | goto unlock_rdev; | 4271 | return 0; |
4897 | |||
4898 | wdev->ps = state; | ||
4899 | |||
4900 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps, | ||
4901 | wdev->ps_timeout)) | ||
4902 | /* assume this means it's off */ | ||
4903 | wdev->ps = false; | ||
4904 | |||
4905 | unlock_rdev: | ||
4906 | cfg80211_unlock_rdev(rdev); | ||
4907 | dev_put(dev); | ||
4908 | rtnl_unlock(); | ||
4909 | 4272 | ||
4910 | out: | 4273 | err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state, |
4274 | wdev->ps_timeout); | ||
4275 | if (!err) | ||
4276 | wdev->ps = state; | ||
4911 | return err; | 4277 | return err; |
4912 | } | 4278 | } |
4913 | 4279 | ||
4914 | static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) | 4280 | static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) |
4915 | { | 4281 | { |
4916 | struct cfg80211_registered_device *rdev; | 4282 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4917 | enum nl80211_ps_state ps_state; | 4283 | enum nl80211_ps_state ps_state; |
4918 | struct wireless_dev *wdev; | 4284 | struct wireless_dev *wdev; |
4919 | struct net_device *dev; | 4285 | struct net_device *dev = info->user_ptr[1]; |
4920 | struct sk_buff *msg; | 4286 | struct sk_buff *msg; |
4921 | void *hdr; | 4287 | void *hdr; |
4922 | int err; | 4288 | int err; |
4923 | 4289 | ||
4924 | rtnl_lock(); | ||
4925 | |||
4926 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4927 | if (err) | ||
4928 | goto unlock_rtnl; | ||
4929 | |||
4930 | wdev = dev->ieee80211_ptr; | 4290 | wdev = dev->ieee80211_ptr; |
4931 | 4291 | ||
4932 | if (!rdev->ops->set_power_mgmt) { | 4292 | if (!rdev->ops->set_power_mgmt) |
4933 | err = -EOPNOTSUPP; | 4293 | return -EOPNOTSUPP; |
4934 | goto out; | ||
4935 | } | ||
4936 | 4294 | ||
4937 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4295 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4938 | if (!msg) { | 4296 | if (!msg) |
4939 | err = -ENOMEM; | 4297 | return -ENOMEM; |
4940 | goto out; | ||
4941 | } | ||
4942 | 4298 | ||
4943 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4299 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
4944 | NL80211_CMD_GET_POWER_SAVE); | 4300 | NL80211_CMD_GET_POWER_SAVE); |
4945 | if (!hdr) { | 4301 | if (!hdr) { |
4946 | err = -ENOMEM; | 4302 | err = -ENOBUFS; |
4947 | goto free_msg; | 4303 | goto free_msg; |
4948 | } | 4304 | } |
4949 | 4305 | ||
@@ -4955,22 +4311,12 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) | |||
4955 | NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); | 4311 | NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); |
4956 | 4312 | ||
4957 | genlmsg_end(msg, hdr); | 4313 | genlmsg_end(msg, hdr); |
4958 | err = genlmsg_reply(msg, info); | 4314 | return genlmsg_reply(msg, info); |
4959 | goto out; | ||
4960 | 4315 | ||
4961 | nla_put_failure: | 4316 | nla_put_failure: |
4962 | err = -ENOBUFS; | 4317 | err = -ENOBUFS; |
4963 | 4318 | free_msg: | |
4964 | free_msg: | ||
4965 | nlmsg_free(msg); | 4319 | nlmsg_free(msg); |
4966 | |||
4967 | out: | ||
4968 | cfg80211_unlock_rdev(rdev); | ||
4969 | dev_put(dev); | ||
4970 | |||
4971 | unlock_rtnl: | ||
4972 | rtnl_unlock(); | ||
4973 | |||
4974 | return err; | 4320 | return err; |
4975 | } | 4321 | } |
4976 | 4322 | ||
@@ -4984,41 +4330,24 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | |||
4984 | static int nl80211_set_cqm_rssi(struct genl_info *info, | 4330 | static int nl80211_set_cqm_rssi(struct genl_info *info, |
4985 | s32 threshold, u32 hysteresis) | 4331 | s32 threshold, u32 hysteresis) |
4986 | { | 4332 | { |
4987 | struct cfg80211_registered_device *rdev; | 4333 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4988 | struct wireless_dev *wdev; | 4334 | struct wireless_dev *wdev; |
4989 | struct net_device *dev; | 4335 | struct net_device *dev = info->user_ptr[1]; |
4990 | int err; | ||
4991 | 4336 | ||
4992 | if (threshold > 0) | 4337 | if (threshold > 0) |
4993 | return -EINVAL; | 4338 | return -EINVAL; |
4994 | 4339 | ||
4995 | rtnl_lock(); | ||
4996 | |||
4997 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4998 | if (err) | ||
4999 | goto unlock_rdev; | ||
5000 | |||
5001 | wdev = dev->ieee80211_ptr; | 4340 | wdev = dev->ieee80211_ptr; |
5002 | 4341 | ||
5003 | if (!rdev->ops->set_cqm_rssi_config) { | 4342 | if (!rdev->ops->set_cqm_rssi_config) |
5004 | err = -EOPNOTSUPP; | 4343 | return -EOPNOTSUPP; |
5005 | goto unlock_rdev; | ||
5006 | } | ||
5007 | |||
5008 | if (wdev->iftype != NL80211_IFTYPE_STATION) { | ||
5009 | err = -EOPNOTSUPP; | ||
5010 | goto unlock_rdev; | ||
5011 | } | ||
5012 | |||
5013 | err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, | ||
5014 | threshold, hysteresis); | ||
5015 | 4344 | ||
5016 | unlock_rdev: | 4345 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
5017 | cfg80211_unlock_rdev(rdev); | 4346 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) |
5018 | dev_put(dev); | 4347 | return -EOPNOTSUPP; |
5019 | rtnl_unlock(); | ||
5020 | 4348 | ||
5021 | return err; | 4349 | return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, |
4350 | threshold, hysteresis); | ||
5022 | } | 4351 | } |
5023 | 4352 | ||
5024 | static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | 4353 | static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) |
@@ -5052,6 +4381,65 @@ out: | |||
5052 | return err; | 4381 | return err; |
5053 | } | 4382 | } |
5054 | 4383 | ||
4384 | #define NL80211_FLAG_NEED_WIPHY 0x01 | ||
4385 | #define NL80211_FLAG_NEED_NETDEV 0x02 | ||
4386 | #define NL80211_FLAG_NEED_RTNL 0x04 | ||
4387 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 | ||
4388 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ | ||
4389 | NL80211_FLAG_CHECK_NETDEV_UP) | ||
4390 | |||
4391 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
4392 | struct genl_info *info) | ||
4393 | { | ||
4394 | struct cfg80211_registered_device *rdev; | ||
4395 | struct net_device *dev; | ||
4396 | int err; | ||
4397 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; | ||
4398 | |||
4399 | if (rtnl) | ||
4400 | rtnl_lock(); | ||
4401 | |||
4402 | if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { | ||
4403 | rdev = cfg80211_get_dev_from_info(info); | ||
4404 | if (IS_ERR(rdev)) { | ||
4405 | if (rtnl) | ||
4406 | rtnl_unlock(); | ||
4407 | return PTR_ERR(rdev); | ||
4408 | } | ||
4409 | info->user_ptr[0] = rdev; | ||
4410 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { | ||
4411 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4412 | if (err) { | ||
4413 | if (rtnl) | ||
4414 | rtnl_unlock(); | ||
4415 | return err; | ||
4416 | } | ||
4417 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | ||
4418 | !netif_running(dev)) { | ||
4419 | cfg80211_unlock_rdev(rdev); | ||
4420 | dev_put(dev); | ||
4421 | if (rtnl) | ||
4422 | rtnl_unlock(); | ||
4423 | return -ENETDOWN; | ||
4424 | } | ||
4425 | info->user_ptr[0] = rdev; | ||
4426 | info->user_ptr[1] = dev; | ||
4427 | } | ||
4428 | |||
4429 | return 0; | ||
4430 | } | ||
4431 | |||
4432 | static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
4433 | struct genl_info *info) | ||
4434 | { | ||
4435 | if (info->user_ptr[0]) | ||
4436 | cfg80211_unlock_rdev(info->user_ptr[0]); | ||
4437 | if (info->user_ptr[1]) | ||
4438 | dev_put(info->user_ptr[1]); | ||
4439 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) | ||
4440 | rtnl_unlock(); | ||
4441 | } | ||
4442 | |||
5055 | static struct genl_ops nl80211_ops[] = { | 4443 | static struct genl_ops nl80211_ops[] = { |
5056 | { | 4444 | { |
5057 | .cmd = NL80211_CMD_GET_WIPHY, | 4445 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -5059,12 +4447,14 @@ static struct genl_ops nl80211_ops[] = { | |||
5059 | .dumpit = nl80211_dump_wiphy, | 4447 | .dumpit = nl80211_dump_wiphy, |
5060 | .policy = nl80211_policy, | 4448 | .policy = nl80211_policy, |
5061 | /* can be retrieved by unprivileged users */ | 4449 | /* can be retrieved by unprivileged users */ |
4450 | .internal_flags = NL80211_FLAG_NEED_WIPHY, | ||
5062 | }, | 4451 | }, |
5063 | { | 4452 | { |
5064 | .cmd = NL80211_CMD_SET_WIPHY, | 4453 | .cmd = NL80211_CMD_SET_WIPHY, |
5065 | .doit = nl80211_set_wiphy, | 4454 | .doit = nl80211_set_wiphy, |
5066 | .policy = nl80211_policy, | 4455 | .policy = nl80211_policy, |
5067 | .flags = GENL_ADMIN_PERM, | 4456 | .flags = GENL_ADMIN_PERM, |
4457 | .internal_flags = NL80211_FLAG_NEED_RTNL, | ||
5068 | }, | 4458 | }, |
5069 | { | 4459 | { |
5070 | .cmd = NL80211_CMD_GET_INTERFACE, | 4460 | .cmd = NL80211_CMD_GET_INTERFACE, |
@@ -5072,90 +4462,119 @@ static struct genl_ops nl80211_ops[] = { | |||
5072 | .dumpit = nl80211_dump_interface, | 4462 | .dumpit = nl80211_dump_interface, |
5073 | .policy = nl80211_policy, | 4463 | .policy = nl80211_policy, |
5074 | /* can be retrieved by unprivileged users */ | 4464 | /* can be retrieved by unprivileged users */ |
4465 | .internal_flags = NL80211_FLAG_NEED_NETDEV, | ||
5075 | }, | 4466 | }, |
5076 | { | 4467 | { |
5077 | .cmd = NL80211_CMD_SET_INTERFACE, | 4468 | .cmd = NL80211_CMD_SET_INTERFACE, |
5078 | .doit = nl80211_set_interface, | 4469 | .doit = nl80211_set_interface, |
5079 | .policy = nl80211_policy, | 4470 | .policy = nl80211_policy, |
5080 | .flags = GENL_ADMIN_PERM, | 4471 | .flags = GENL_ADMIN_PERM, |
4472 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4473 | NL80211_FLAG_NEED_RTNL, | ||
5081 | }, | 4474 | }, |
5082 | { | 4475 | { |
5083 | .cmd = NL80211_CMD_NEW_INTERFACE, | 4476 | .cmd = NL80211_CMD_NEW_INTERFACE, |
5084 | .doit = nl80211_new_interface, | 4477 | .doit = nl80211_new_interface, |
5085 | .policy = nl80211_policy, | 4478 | .policy = nl80211_policy, |
5086 | .flags = GENL_ADMIN_PERM, | 4479 | .flags = GENL_ADMIN_PERM, |
4480 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4481 | NL80211_FLAG_NEED_RTNL, | ||
5087 | }, | 4482 | }, |
5088 | { | 4483 | { |
5089 | .cmd = NL80211_CMD_DEL_INTERFACE, | 4484 | .cmd = NL80211_CMD_DEL_INTERFACE, |
5090 | .doit = nl80211_del_interface, | 4485 | .doit = nl80211_del_interface, |
5091 | .policy = nl80211_policy, | 4486 | .policy = nl80211_policy, |
5092 | .flags = GENL_ADMIN_PERM, | 4487 | .flags = GENL_ADMIN_PERM, |
4488 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4489 | NL80211_FLAG_NEED_RTNL, | ||
5093 | }, | 4490 | }, |
5094 | { | 4491 | { |
5095 | .cmd = NL80211_CMD_GET_KEY, | 4492 | .cmd = NL80211_CMD_GET_KEY, |
5096 | .doit = nl80211_get_key, | 4493 | .doit = nl80211_get_key, |
5097 | .policy = nl80211_policy, | 4494 | .policy = nl80211_policy, |
5098 | .flags = GENL_ADMIN_PERM, | 4495 | .flags = GENL_ADMIN_PERM, |
4496 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4497 | NL80211_FLAG_NEED_RTNL, | ||
5099 | }, | 4498 | }, |
5100 | { | 4499 | { |
5101 | .cmd = NL80211_CMD_SET_KEY, | 4500 | .cmd = NL80211_CMD_SET_KEY, |
5102 | .doit = nl80211_set_key, | 4501 | .doit = nl80211_set_key, |
5103 | .policy = nl80211_policy, | 4502 | .policy = nl80211_policy, |
5104 | .flags = GENL_ADMIN_PERM, | 4503 | .flags = GENL_ADMIN_PERM, |
4504 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4505 | NL80211_FLAG_NEED_RTNL, | ||
5105 | }, | 4506 | }, |
5106 | { | 4507 | { |
5107 | .cmd = NL80211_CMD_NEW_KEY, | 4508 | .cmd = NL80211_CMD_NEW_KEY, |
5108 | .doit = nl80211_new_key, | 4509 | .doit = nl80211_new_key, |
5109 | .policy = nl80211_policy, | 4510 | .policy = nl80211_policy, |
5110 | .flags = GENL_ADMIN_PERM, | 4511 | .flags = GENL_ADMIN_PERM, |
4512 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4513 | NL80211_FLAG_NEED_RTNL, | ||
5111 | }, | 4514 | }, |
5112 | { | 4515 | { |
5113 | .cmd = NL80211_CMD_DEL_KEY, | 4516 | .cmd = NL80211_CMD_DEL_KEY, |
5114 | .doit = nl80211_del_key, | 4517 | .doit = nl80211_del_key, |
5115 | .policy = nl80211_policy, | 4518 | .policy = nl80211_policy, |
5116 | .flags = GENL_ADMIN_PERM, | 4519 | .flags = GENL_ADMIN_PERM, |
4520 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4521 | NL80211_FLAG_NEED_RTNL, | ||
5117 | }, | 4522 | }, |
5118 | { | 4523 | { |
5119 | .cmd = NL80211_CMD_SET_BEACON, | 4524 | .cmd = NL80211_CMD_SET_BEACON, |
5120 | .policy = nl80211_policy, | 4525 | .policy = nl80211_policy, |
5121 | .flags = GENL_ADMIN_PERM, | 4526 | .flags = GENL_ADMIN_PERM, |
5122 | .doit = nl80211_addset_beacon, | 4527 | .doit = nl80211_addset_beacon, |
4528 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4529 | NL80211_FLAG_NEED_RTNL, | ||
5123 | }, | 4530 | }, |
5124 | { | 4531 | { |
5125 | .cmd = NL80211_CMD_NEW_BEACON, | 4532 | .cmd = NL80211_CMD_NEW_BEACON, |
5126 | .policy = nl80211_policy, | 4533 | .policy = nl80211_policy, |
5127 | .flags = GENL_ADMIN_PERM, | 4534 | .flags = GENL_ADMIN_PERM, |
5128 | .doit = nl80211_addset_beacon, | 4535 | .doit = nl80211_addset_beacon, |
4536 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4537 | NL80211_FLAG_NEED_RTNL, | ||
5129 | }, | 4538 | }, |
5130 | { | 4539 | { |
5131 | .cmd = NL80211_CMD_DEL_BEACON, | 4540 | .cmd = NL80211_CMD_DEL_BEACON, |
5132 | .policy = nl80211_policy, | 4541 | .policy = nl80211_policy, |
5133 | .flags = GENL_ADMIN_PERM, | 4542 | .flags = GENL_ADMIN_PERM, |
5134 | .doit = nl80211_del_beacon, | 4543 | .doit = nl80211_del_beacon, |
4544 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4545 | NL80211_FLAG_NEED_RTNL, | ||
5135 | }, | 4546 | }, |
5136 | { | 4547 | { |
5137 | .cmd = NL80211_CMD_GET_STATION, | 4548 | .cmd = NL80211_CMD_GET_STATION, |
5138 | .doit = nl80211_get_station, | 4549 | .doit = nl80211_get_station, |
5139 | .dumpit = nl80211_dump_station, | 4550 | .dumpit = nl80211_dump_station, |
5140 | .policy = nl80211_policy, | 4551 | .policy = nl80211_policy, |
4552 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4553 | NL80211_FLAG_NEED_RTNL, | ||
5141 | }, | 4554 | }, |
5142 | { | 4555 | { |
5143 | .cmd = NL80211_CMD_SET_STATION, | 4556 | .cmd = NL80211_CMD_SET_STATION, |
5144 | .doit = nl80211_set_station, | 4557 | .doit = nl80211_set_station, |
5145 | .policy = nl80211_policy, | 4558 | .policy = nl80211_policy, |
5146 | .flags = GENL_ADMIN_PERM, | 4559 | .flags = GENL_ADMIN_PERM, |
4560 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4561 | NL80211_FLAG_NEED_RTNL, | ||
5147 | }, | 4562 | }, |
5148 | { | 4563 | { |
5149 | .cmd = NL80211_CMD_NEW_STATION, | 4564 | .cmd = NL80211_CMD_NEW_STATION, |
5150 | .doit = nl80211_new_station, | 4565 | .doit = nl80211_new_station, |
5151 | .policy = nl80211_policy, | 4566 | .policy = nl80211_policy, |
5152 | .flags = GENL_ADMIN_PERM, | 4567 | .flags = GENL_ADMIN_PERM, |
4568 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4569 | NL80211_FLAG_NEED_RTNL, | ||
5153 | }, | 4570 | }, |
5154 | { | 4571 | { |
5155 | .cmd = NL80211_CMD_DEL_STATION, | 4572 | .cmd = NL80211_CMD_DEL_STATION, |
5156 | .doit = nl80211_del_station, | 4573 | .doit = nl80211_del_station, |
5157 | .policy = nl80211_policy, | 4574 | .policy = nl80211_policy, |
5158 | .flags = GENL_ADMIN_PERM, | 4575 | .flags = GENL_ADMIN_PERM, |
4576 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4577 | NL80211_FLAG_NEED_RTNL, | ||
5159 | }, | 4578 | }, |
5160 | { | 4579 | { |
5161 | .cmd = NL80211_CMD_GET_MPATH, | 4580 | .cmd = NL80211_CMD_GET_MPATH, |
@@ -5163,30 +4582,40 @@ static struct genl_ops nl80211_ops[] = { | |||
5163 | .dumpit = nl80211_dump_mpath, | 4582 | .dumpit = nl80211_dump_mpath, |
5164 | .policy = nl80211_policy, | 4583 | .policy = nl80211_policy, |
5165 | .flags = GENL_ADMIN_PERM, | 4584 | .flags = GENL_ADMIN_PERM, |
4585 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4586 | NL80211_FLAG_NEED_RTNL, | ||
5166 | }, | 4587 | }, |
5167 | { | 4588 | { |
5168 | .cmd = NL80211_CMD_SET_MPATH, | 4589 | .cmd = NL80211_CMD_SET_MPATH, |
5169 | .doit = nl80211_set_mpath, | 4590 | .doit = nl80211_set_mpath, |
5170 | .policy = nl80211_policy, | 4591 | .policy = nl80211_policy, |
5171 | .flags = GENL_ADMIN_PERM, | 4592 | .flags = GENL_ADMIN_PERM, |
4593 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4594 | NL80211_FLAG_NEED_RTNL, | ||
5172 | }, | 4595 | }, |
5173 | { | 4596 | { |
5174 | .cmd = NL80211_CMD_NEW_MPATH, | 4597 | .cmd = NL80211_CMD_NEW_MPATH, |
5175 | .doit = nl80211_new_mpath, | 4598 | .doit = nl80211_new_mpath, |
5176 | .policy = nl80211_policy, | 4599 | .policy = nl80211_policy, |
5177 | .flags = GENL_ADMIN_PERM, | 4600 | .flags = GENL_ADMIN_PERM, |
4601 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4602 | NL80211_FLAG_NEED_RTNL, | ||
5178 | }, | 4603 | }, |
5179 | { | 4604 | { |
5180 | .cmd = NL80211_CMD_DEL_MPATH, | 4605 | .cmd = NL80211_CMD_DEL_MPATH, |
5181 | .doit = nl80211_del_mpath, | 4606 | .doit = nl80211_del_mpath, |
5182 | .policy = nl80211_policy, | 4607 | .policy = nl80211_policy, |
5183 | .flags = GENL_ADMIN_PERM, | 4608 | .flags = GENL_ADMIN_PERM, |
4609 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4610 | NL80211_FLAG_NEED_RTNL, | ||
5184 | }, | 4611 | }, |
5185 | { | 4612 | { |
5186 | .cmd = NL80211_CMD_SET_BSS, | 4613 | .cmd = NL80211_CMD_SET_BSS, |
5187 | .doit = nl80211_set_bss, | 4614 | .doit = nl80211_set_bss, |
5188 | .policy = nl80211_policy, | 4615 | .policy = nl80211_policy, |
5189 | .flags = GENL_ADMIN_PERM, | 4616 | .flags = GENL_ADMIN_PERM, |
4617 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4618 | NL80211_FLAG_NEED_RTNL, | ||
5190 | }, | 4619 | }, |
5191 | { | 4620 | { |
5192 | .cmd = NL80211_CMD_GET_REG, | 4621 | .cmd = NL80211_CMD_GET_REG, |
@@ -5211,18 +4640,24 @@ static struct genl_ops nl80211_ops[] = { | |||
5211 | .doit = nl80211_get_mesh_params, | 4640 | .doit = nl80211_get_mesh_params, |
5212 | .policy = nl80211_policy, | 4641 | .policy = nl80211_policy, |
5213 | /* can be retrieved by unprivileged users */ | 4642 | /* can be retrieved by unprivileged users */ |
4643 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4644 | NL80211_FLAG_NEED_RTNL, | ||
5214 | }, | 4645 | }, |
5215 | { | 4646 | { |
5216 | .cmd = NL80211_CMD_SET_MESH_PARAMS, | 4647 | .cmd = NL80211_CMD_SET_MESH_PARAMS, |
5217 | .doit = nl80211_set_mesh_params, | 4648 | .doit = nl80211_set_mesh_params, |
5218 | .policy = nl80211_policy, | 4649 | .policy = nl80211_policy, |
5219 | .flags = GENL_ADMIN_PERM, | 4650 | .flags = GENL_ADMIN_PERM, |
4651 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4652 | NL80211_FLAG_NEED_RTNL, | ||
5220 | }, | 4653 | }, |
5221 | { | 4654 | { |
5222 | .cmd = NL80211_CMD_TRIGGER_SCAN, | 4655 | .cmd = NL80211_CMD_TRIGGER_SCAN, |
5223 | .doit = nl80211_trigger_scan, | 4656 | .doit = nl80211_trigger_scan, |
5224 | .policy = nl80211_policy, | 4657 | .policy = nl80211_policy, |
5225 | .flags = GENL_ADMIN_PERM, | 4658 | .flags = GENL_ADMIN_PERM, |
4659 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4660 | NL80211_FLAG_NEED_RTNL, | ||
5226 | }, | 4661 | }, |
5227 | { | 4662 | { |
5228 | .cmd = NL80211_CMD_GET_SCAN, | 4663 | .cmd = NL80211_CMD_GET_SCAN, |
@@ -5234,36 +4669,48 @@ static struct genl_ops nl80211_ops[] = { | |||
5234 | .doit = nl80211_authenticate, | 4669 | .doit = nl80211_authenticate, |
5235 | .policy = nl80211_policy, | 4670 | .policy = nl80211_policy, |
5236 | .flags = GENL_ADMIN_PERM, | 4671 | .flags = GENL_ADMIN_PERM, |
4672 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4673 | NL80211_FLAG_NEED_RTNL, | ||
5237 | }, | 4674 | }, |
5238 | { | 4675 | { |
5239 | .cmd = NL80211_CMD_ASSOCIATE, | 4676 | .cmd = NL80211_CMD_ASSOCIATE, |
5240 | .doit = nl80211_associate, | 4677 | .doit = nl80211_associate, |
5241 | .policy = nl80211_policy, | 4678 | .policy = nl80211_policy, |
5242 | .flags = GENL_ADMIN_PERM, | 4679 | .flags = GENL_ADMIN_PERM, |
4680 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4681 | NL80211_FLAG_NEED_RTNL, | ||
5243 | }, | 4682 | }, |
5244 | { | 4683 | { |
5245 | .cmd = NL80211_CMD_DEAUTHENTICATE, | 4684 | .cmd = NL80211_CMD_DEAUTHENTICATE, |
5246 | .doit = nl80211_deauthenticate, | 4685 | .doit = nl80211_deauthenticate, |
5247 | .policy = nl80211_policy, | 4686 | .policy = nl80211_policy, |
5248 | .flags = GENL_ADMIN_PERM, | 4687 | .flags = GENL_ADMIN_PERM, |
4688 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4689 | NL80211_FLAG_NEED_RTNL, | ||
5249 | }, | 4690 | }, |
5250 | { | 4691 | { |
5251 | .cmd = NL80211_CMD_DISASSOCIATE, | 4692 | .cmd = NL80211_CMD_DISASSOCIATE, |
5252 | .doit = nl80211_disassociate, | 4693 | .doit = nl80211_disassociate, |
5253 | .policy = nl80211_policy, | 4694 | .policy = nl80211_policy, |
5254 | .flags = GENL_ADMIN_PERM, | 4695 | .flags = GENL_ADMIN_PERM, |
4696 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4697 | NL80211_FLAG_NEED_RTNL, | ||
5255 | }, | 4698 | }, |
5256 | { | 4699 | { |
5257 | .cmd = NL80211_CMD_JOIN_IBSS, | 4700 | .cmd = NL80211_CMD_JOIN_IBSS, |
5258 | .doit = nl80211_join_ibss, | 4701 | .doit = nl80211_join_ibss, |
5259 | .policy = nl80211_policy, | 4702 | .policy = nl80211_policy, |
5260 | .flags = GENL_ADMIN_PERM, | 4703 | .flags = GENL_ADMIN_PERM, |
4704 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4705 | NL80211_FLAG_NEED_RTNL, | ||
5261 | }, | 4706 | }, |
5262 | { | 4707 | { |
5263 | .cmd = NL80211_CMD_LEAVE_IBSS, | 4708 | .cmd = NL80211_CMD_LEAVE_IBSS, |
5264 | .doit = nl80211_leave_ibss, | 4709 | .doit = nl80211_leave_ibss, |
5265 | .policy = nl80211_policy, | 4710 | .policy = nl80211_policy, |
5266 | .flags = GENL_ADMIN_PERM, | 4711 | .flags = GENL_ADMIN_PERM, |
4712 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4713 | NL80211_FLAG_NEED_RTNL, | ||
5267 | }, | 4714 | }, |
5268 | #ifdef CONFIG_NL80211_TESTMODE | 4715 | #ifdef CONFIG_NL80211_TESTMODE |
5269 | { | 4716 | { |
@@ -5271,6 +4718,8 @@ static struct genl_ops nl80211_ops[] = { | |||
5271 | .doit = nl80211_testmode_do, | 4718 | .doit = nl80211_testmode_do, |
5272 | .policy = nl80211_policy, | 4719 | .policy = nl80211_policy, |
5273 | .flags = GENL_ADMIN_PERM, | 4720 | .flags = GENL_ADMIN_PERM, |
4721 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4722 | NL80211_FLAG_NEED_RTNL, | ||
5274 | }, | 4723 | }, |
5275 | #endif | 4724 | #endif |
5276 | { | 4725 | { |
@@ -5278,18 +4727,24 @@ static struct genl_ops nl80211_ops[] = { | |||
5278 | .doit = nl80211_connect, | 4727 | .doit = nl80211_connect, |
5279 | .policy = nl80211_policy, | 4728 | .policy = nl80211_policy, |
5280 | .flags = GENL_ADMIN_PERM, | 4729 | .flags = GENL_ADMIN_PERM, |
4730 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4731 | NL80211_FLAG_NEED_RTNL, | ||
5281 | }, | 4732 | }, |
5282 | { | 4733 | { |
5283 | .cmd = NL80211_CMD_DISCONNECT, | 4734 | .cmd = NL80211_CMD_DISCONNECT, |
5284 | .doit = nl80211_disconnect, | 4735 | .doit = nl80211_disconnect, |
5285 | .policy = nl80211_policy, | 4736 | .policy = nl80211_policy, |
5286 | .flags = GENL_ADMIN_PERM, | 4737 | .flags = GENL_ADMIN_PERM, |
4738 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4739 | NL80211_FLAG_NEED_RTNL, | ||
5287 | }, | 4740 | }, |
5288 | { | 4741 | { |
5289 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, | 4742 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, |
5290 | .doit = nl80211_wiphy_netns, | 4743 | .doit = nl80211_wiphy_netns, |
5291 | .policy = nl80211_policy, | 4744 | .policy = nl80211_policy, |
5292 | .flags = GENL_ADMIN_PERM, | 4745 | .flags = GENL_ADMIN_PERM, |
4746 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4747 | NL80211_FLAG_NEED_RTNL, | ||
5293 | }, | 4748 | }, |
5294 | { | 4749 | { |
5295 | .cmd = NL80211_CMD_GET_SURVEY, | 4750 | .cmd = NL80211_CMD_GET_SURVEY, |
@@ -5301,72 +4756,104 @@ static struct genl_ops nl80211_ops[] = { | |||
5301 | .doit = nl80211_setdel_pmksa, | 4756 | .doit = nl80211_setdel_pmksa, |
5302 | .policy = nl80211_policy, | 4757 | .policy = nl80211_policy, |
5303 | .flags = GENL_ADMIN_PERM, | 4758 | .flags = GENL_ADMIN_PERM, |
4759 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4760 | NL80211_FLAG_NEED_RTNL, | ||
5304 | }, | 4761 | }, |
5305 | { | 4762 | { |
5306 | .cmd = NL80211_CMD_DEL_PMKSA, | 4763 | .cmd = NL80211_CMD_DEL_PMKSA, |
5307 | .doit = nl80211_setdel_pmksa, | 4764 | .doit = nl80211_setdel_pmksa, |
5308 | .policy = nl80211_policy, | 4765 | .policy = nl80211_policy, |
5309 | .flags = GENL_ADMIN_PERM, | 4766 | .flags = GENL_ADMIN_PERM, |
4767 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4768 | NL80211_FLAG_NEED_RTNL, | ||
5310 | }, | 4769 | }, |
5311 | { | 4770 | { |
5312 | .cmd = NL80211_CMD_FLUSH_PMKSA, | 4771 | .cmd = NL80211_CMD_FLUSH_PMKSA, |
5313 | .doit = nl80211_flush_pmksa, | 4772 | .doit = nl80211_flush_pmksa, |
5314 | .policy = nl80211_policy, | 4773 | .policy = nl80211_policy, |
5315 | .flags = GENL_ADMIN_PERM, | 4774 | .flags = GENL_ADMIN_PERM, |
4775 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4776 | NL80211_FLAG_NEED_RTNL, | ||
5316 | }, | 4777 | }, |
5317 | { | 4778 | { |
5318 | .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, | 4779 | .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, |
5319 | .doit = nl80211_remain_on_channel, | 4780 | .doit = nl80211_remain_on_channel, |
5320 | .policy = nl80211_policy, | 4781 | .policy = nl80211_policy, |
5321 | .flags = GENL_ADMIN_PERM, | 4782 | .flags = GENL_ADMIN_PERM, |
4783 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4784 | NL80211_FLAG_NEED_RTNL, | ||
5322 | }, | 4785 | }, |
5323 | { | 4786 | { |
5324 | .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 4787 | .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
5325 | .doit = nl80211_cancel_remain_on_channel, | 4788 | .doit = nl80211_cancel_remain_on_channel, |
5326 | .policy = nl80211_policy, | 4789 | .policy = nl80211_policy, |
5327 | .flags = GENL_ADMIN_PERM, | 4790 | .flags = GENL_ADMIN_PERM, |
4791 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4792 | NL80211_FLAG_NEED_RTNL, | ||
5328 | }, | 4793 | }, |
5329 | { | 4794 | { |
5330 | .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, | 4795 | .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, |
5331 | .doit = nl80211_set_tx_bitrate_mask, | 4796 | .doit = nl80211_set_tx_bitrate_mask, |
5332 | .policy = nl80211_policy, | 4797 | .policy = nl80211_policy, |
5333 | .flags = GENL_ADMIN_PERM, | 4798 | .flags = GENL_ADMIN_PERM, |
4799 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4800 | NL80211_FLAG_NEED_RTNL, | ||
5334 | }, | 4801 | }, |
5335 | { | 4802 | { |
5336 | .cmd = NL80211_CMD_REGISTER_ACTION, | 4803 | .cmd = NL80211_CMD_REGISTER_FRAME, |
5337 | .doit = nl80211_register_action, | 4804 | .doit = nl80211_register_mgmt, |
5338 | .policy = nl80211_policy, | 4805 | .policy = nl80211_policy, |
5339 | .flags = GENL_ADMIN_PERM, | 4806 | .flags = GENL_ADMIN_PERM, |
4807 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4808 | NL80211_FLAG_NEED_RTNL, | ||
5340 | }, | 4809 | }, |
5341 | { | 4810 | { |
5342 | .cmd = NL80211_CMD_ACTION, | 4811 | .cmd = NL80211_CMD_FRAME, |
5343 | .doit = nl80211_action, | 4812 | .doit = nl80211_tx_mgmt, |
5344 | .policy = nl80211_policy, | 4813 | .policy = nl80211_policy, |
5345 | .flags = GENL_ADMIN_PERM, | 4814 | .flags = GENL_ADMIN_PERM, |
4815 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4816 | NL80211_FLAG_NEED_RTNL, | ||
5346 | }, | 4817 | }, |
5347 | { | 4818 | { |
5348 | .cmd = NL80211_CMD_SET_POWER_SAVE, | 4819 | .cmd = NL80211_CMD_SET_POWER_SAVE, |
5349 | .doit = nl80211_set_power_save, | 4820 | .doit = nl80211_set_power_save, |
5350 | .policy = nl80211_policy, | 4821 | .policy = nl80211_policy, |
5351 | .flags = GENL_ADMIN_PERM, | 4822 | .flags = GENL_ADMIN_PERM, |
4823 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4824 | NL80211_FLAG_NEED_RTNL, | ||
5352 | }, | 4825 | }, |
5353 | { | 4826 | { |
5354 | .cmd = NL80211_CMD_GET_POWER_SAVE, | 4827 | .cmd = NL80211_CMD_GET_POWER_SAVE, |
5355 | .doit = nl80211_get_power_save, | 4828 | .doit = nl80211_get_power_save, |
5356 | .policy = nl80211_policy, | 4829 | .policy = nl80211_policy, |
5357 | /* can be retrieved by unprivileged users */ | 4830 | /* can be retrieved by unprivileged users */ |
4831 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4832 | NL80211_FLAG_NEED_RTNL, | ||
5358 | }, | 4833 | }, |
5359 | { | 4834 | { |
5360 | .cmd = NL80211_CMD_SET_CQM, | 4835 | .cmd = NL80211_CMD_SET_CQM, |
5361 | .doit = nl80211_set_cqm, | 4836 | .doit = nl80211_set_cqm, |
5362 | .policy = nl80211_policy, | 4837 | .policy = nl80211_policy, |
5363 | .flags = GENL_ADMIN_PERM, | 4838 | .flags = GENL_ADMIN_PERM, |
4839 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4840 | NL80211_FLAG_NEED_RTNL, | ||
5364 | }, | 4841 | }, |
5365 | { | 4842 | { |
5366 | .cmd = NL80211_CMD_SET_CHANNEL, | 4843 | .cmd = NL80211_CMD_SET_CHANNEL, |
5367 | .doit = nl80211_set_channel, | 4844 | .doit = nl80211_set_channel, |
5368 | .policy = nl80211_policy, | 4845 | .policy = nl80211_policy, |
5369 | .flags = GENL_ADMIN_PERM, | 4846 | .flags = GENL_ADMIN_PERM, |
4847 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4848 | NL80211_FLAG_NEED_RTNL, | ||
4849 | }, | ||
4850 | { | ||
4851 | .cmd = NL80211_CMD_SET_WDS_PEER, | ||
4852 | .doit = nl80211_set_wds_peer, | ||
4853 | .policy = nl80211_policy, | ||
4854 | .flags = GENL_ADMIN_PERM, | ||
4855 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4856 | NL80211_FLAG_NEED_RTNL, | ||
5370 | }, | 4857 | }, |
5371 | }; | 4858 | }; |
5372 | 4859 | ||
@@ -6040,9 +5527,9 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
6040 | nl80211_mlme_mcgrp.id, gfp); | 5527 | nl80211_mlme_mcgrp.id, gfp); |
6041 | } | 5528 | } |
6042 | 5529 | ||
6043 | int nl80211_send_action(struct cfg80211_registered_device *rdev, | 5530 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
6044 | struct net_device *netdev, u32 nlpid, | 5531 | struct net_device *netdev, u32 nlpid, |
6045 | int freq, const u8 *buf, size_t len, gfp_t gfp) | 5532 | int freq, const u8 *buf, size_t len, gfp_t gfp) |
6046 | { | 5533 | { |
6047 | struct sk_buff *msg; | 5534 | struct sk_buff *msg; |
6048 | void *hdr; | 5535 | void *hdr; |
@@ -6052,7 +5539,7 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev, | |||
6052 | if (!msg) | 5539 | if (!msg) |
6053 | return -ENOMEM; | 5540 | return -ENOMEM; |
6054 | 5541 | ||
6055 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION); | 5542 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); |
6056 | if (!hdr) { | 5543 | if (!hdr) { |
6057 | nlmsg_free(msg); | 5544 | nlmsg_free(msg); |
6058 | return -ENOMEM; | 5545 | return -ENOMEM; |
@@ -6080,10 +5567,10 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev, | |||
6080 | return -ENOBUFS; | 5567 | return -ENOBUFS; |
6081 | } | 5568 | } |
6082 | 5569 | ||
6083 | void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | 5570 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
6084 | struct net_device *netdev, u64 cookie, | 5571 | struct net_device *netdev, u64 cookie, |
6085 | const u8 *buf, size_t len, bool ack, | 5572 | const u8 *buf, size_t len, bool ack, |
6086 | gfp_t gfp) | 5573 | gfp_t gfp) |
6087 | { | 5574 | { |
6088 | struct sk_buff *msg; | 5575 | struct sk_buff *msg; |
6089 | void *hdr; | 5576 | void *hdr; |
@@ -6092,7 +5579,7 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | |||
6092 | if (!msg) | 5579 | if (!msg) |
6093 | return; | 5580 | return; |
6094 | 5581 | ||
6095 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS); | 5582 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS); |
6096 | if (!hdr) { | 5583 | if (!hdr) { |
6097 | nlmsg_free(msg); | 5584 | nlmsg_free(msg); |
6098 | return; | 5585 | return; |
@@ -6179,7 +5666,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
6179 | 5666 | ||
6180 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) | 5667 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) |
6181 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) | 5668 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) |
6182 | cfg80211_mlme_unregister_actions(wdev, notify->pid); | 5669 | cfg80211_mlme_unregister_socket(wdev, notify->pid); |
6183 | 5670 | ||
6184 | rcu_read_unlock(); | 5671 | rcu_read_unlock(); |
6185 | 5672 | ||
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 2ad7fbc7d9f1..30d2f939150d 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -74,13 +74,13 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
74 | struct net_device *dev, const u8 *mac_addr, | 74 | struct net_device *dev, const u8 *mac_addr, |
75 | struct station_info *sinfo, gfp_t gfp); | 75 | struct station_info *sinfo, gfp_t gfp); |
76 | 76 | ||
77 | int nl80211_send_action(struct cfg80211_registered_device *rdev, | 77 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
78 | struct net_device *netdev, u32 nlpid, int freq, | 78 | struct net_device *netdev, u32 nlpid, int freq, |
79 | const u8 *buf, size_t len, gfp_t gfp); | 79 | const u8 *buf, size_t len, gfp_t gfp); |
80 | void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | 80 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
81 | struct net_device *netdev, u64 cookie, | 81 | struct net_device *netdev, u64 cookie, |
82 | const u8 *buf, size_t len, bool ack, | 82 | const u8 *buf, size_t len, bool ack, |
83 | gfp_t gfp); | 83 | gfp_t gfp); |
84 | 84 | ||
85 | void | 85 | void |
86 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | 86 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c index 1332c445d1c7..dbe35e138e94 100644 --- a/net/wireless/radiotap.c +++ b/net/wireless/radiotap.c | |||
@@ -14,6 +14,7 @@ | |||
14 | * See COPYING for more details. | 14 | * See COPYING for more details. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/kernel.h> | ||
17 | #include <net/cfg80211.h> | 18 | #include <net/cfg80211.h> |
18 | #include <net/ieee80211_radiotap.h> | 19 | #include <net/ieee80211_radiotap.h> |
19 | #include <asm/unaligned.h> | 20 | #include <asm/unaligned.h> |
@@ -45,7 +46,7 @@ static const struct radiotap_align_size rtap_namespace_sizes[] = { | |||
45 | }; | 46 | }; |
46 | 47 | ||
47 | static const struct ieee80211_radiotap_namespace radiotap_ns = { | 48 | static const struct ieee80211_radiotap_namespace radiotap_ns = { |
48 | .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), | 49 | .n_bits = ARRAY_SIZE(rtap_namespace_sizes), |
49 | .align_size = rtap_namespace_sizes, | 50 | .align_size = rtap_namespace_sizes, |
50 | }; | 51 | }; |
51 | 52 | ||
@@ -200,7 +201,7 @@ int ieee80211_radiotap_iterator_next( | |||
200 | { | 201 | { |
201 | while (1) { | 202 | while (1) { |
202 | int hit = 0; | 203 | int hit = 0; |
203 | int pad, align, size, subns, vnslen; | 204 | int pad, align, size, subns; |
204 | uint32_t oui; | 205 | uint32_t oui; |
205 | 206 | ||
206 | /* if no more EXT bits, that's it */ | 207 | /* if no more EXT bits, that's it */ |
@@ -260,6 +261,27 @@ int ieee80211_radiotap_iterator_next( | |||
260 | if (pad) | 261 | if (pad) |
261 | iterator->_arg += align - pad; | 262 | iterator->_arg += align - pad; |
262 | 263 | ||
264 | if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { | ||
265 | int vnslen; | ||
266 | |||
267 | if ((unsigned long)iterator->_arg + size - | ||
268 | (unsigned long)iterator->_rtheader > | ||
269 | (unsigned long)iterator->_max_length) | ||
270 | return -EINVAL; | ||
271 | |||
272 | oui = (*iterator->_arg << 16) | | ||
273 | (*(iterator->_arg + 1) << 8) | | ||
274 | *(iterator->_arg + 2); | ||
275 | subns = *(iterator->_arg + 3); | ||
276 | |||
277 | find_ns(iterator, oui, subns); | ||
278 | |||
279 | vnslen = get_unaligned_le16(iterator->_arg + 4); | ||
280 | iterator->_next_ns_data = iterator->_arg + size + vnslen; | ||
281 | if (!iterator->current_namespace) | ||
282 | size += vnslen; | ||
283 | } | ||
284 | |||
263 | /* | 285 | /* |
264 | * this is what we will return to user, but we need to | 286 | * this is what we will return to user, but we need to |
265 | * move on first so next call has something fresh to test | 287 | * move on first so next call has something fresh to test |
@@ -286,40 +308,25 @@ int ieee80211_radiotap_iterator_next( | |||
286 | /* these special ones are valid in each bitmap word */ | 308 | /* these special ones are valid in each bitmap word */ |
287 | switch (iterator->_arg_index % 32) { | 309 | switch (iterator->_arg_index % 32) { |
288 | case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: | 310 | case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: |
289 | iterator->_bitmap_shifter >>= 1; | ||
290 | iterator->_arg_index++; | ||
291 | |||
292 | iterator->_reset_on_ext = 1; | 311 | iterator->_reset_on_ext = 1; |
293 | 312 | ||
294 | vnslen = get_unaligned_le16(iterator->this_arg + 4); | ||
295 | iterator->_next_ns_data = iterator->_arg + vnslen; | ||
296 | oui = (*iterator->this_arg << 16) | | ||
297 | (*(iterator->this_arg + 1) << 8) | | ||
298 | *(iterator->this_arg + 2); | ||
299 | subns = *(iterator->this_arg + 3); | ||
300 | |||
301 | find_ns(iterator, oui, subns); | ||
302 | |||
303 | iterator->is_radiotap_ns = 0; | 313 | iterator->is_radiotap_ns = 0; |
304 | /* allow parsers to show this information */ | 314 | /* |
315 | * If parser didn't register this vendor | ||
316 | * namespace with us, allow it to show it | ||
317 | * as 'raw. Do do that, set argument index | ||
318 | * to vendor namespace. | ||
319 | */ | ||
305 | iterator->this_arg_index = | 320 | iterator->this_arg_index = |
306 | IEEE80211_RADIOTAP_VENDOR_NAMESPACE; | 321 | IEEE80211_RADIOTAP_VENDOR_NAMESPACE; |
307 | iterator->this_arg_size += vnslen; | 322 | if (!iterator->current_namespace) |
308 | if ((unsigned long)iterator->this_arg + | 323 | hit = 1; |
309 | iterator->this_arg_size - | 324 | goto next_entry; |
310 | (unsigned long)iterator->_rtheader > | ||
311 | (unsigned long)(unsigned long)iterator->_max_length) | ||
312 | return -EINVAL; | ||
313 | hit = 1; | ||
314 | break; | ||
315 | case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: | 325 | case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: |
316 | iterator->_bitmap_shifter >>= 1; | ||
317 | iterator->_arg_index++; | ||
318 | |||
319 | iterator->_reset_on_ext = 1; | 326 | iterator->_reset_on_ext = 1; |
320 | iterator->current_namespace = &radiotap_ns; | 327 | iterator->current_namespace = &radiotap_ns; |
321 | iterator->is_radiotap_ns = 1; | 328 | iterator->is_radiotap_ns = 1; |
322 | break; | 329 | goto next_entry; |
323 | case IEEE80211_RADIOTAP_EXT: | 330 | case IEEE80211_RADIOTAP_EXT: |
324 | /* | 331 | /* |
325 | * bit 31 was set, there is more | 332 | * bit 31 was set, there is more |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f180db0de66c..d14bbf960c18 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | #include <linux/list.h> | 37 | #include <linux/list.h> |
38 | #include <linux/random.h> | 38 | #include <linux/random.h> |
39 | #include <linux/ctype.h> | ||
39 | #include <linux/nl80211.h> | 40 | #include <linux/nl80211.h> |
40 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
41 | #include <net/cfg80211.h> | 42 | #include <net/cfg80211.h> |
@@ -73,7 +74,11 @@ const struct ieee80211_regdomain *cfg80211_regdomain; | |||
73 | * - last_request | 74 | * - last_request |
74 | */ | 75 | */ |
75 | static DEFINE_MUTEX(reg_mutex); | 76 | static DEFINE_MUTEX(reg_mutex); |
76 | #define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) | 77 | |
78 | static inline void assert_reg_lock(void) | ||
79 | { | ||
80 | lockdep_assert_held(®_mutex); | ||
81 | } | ||
77 | 82 | ||
78 | /* Used to queue up regulatory hints */ | 83 | /* Used to queue up regulatory hints */ |
79 | static LIST_HEAD(reg_requests_list); | 84 | static LIST_HEAD(reg_requests_list); |
@@ -181,14 +186,6 @@ static bool is_alpha2_set(const char *alpha2) | |||
181 | return false; | 186 | return false; |
182 | } | 187 | } |
183 | 188 | ||
184 | static bool is_alpha_upper(char letter) | ||
185 | { | ||
186 | /* ASCII A - Z */ | ||
187 | if (letter >= 65 && letter <= 90) | ||
188 | return true; | ||
189 | return false; | ||
190 | } | ||
191 | |||
192 | static bool is_unknown_alpha2(const char *alpha2) | 189 | static bool is_unknown_alpha2(const char *alpha2) |
193 | { | 190 | { |
194 | if (!alpha2) | 191 | if (!alpha2) |
@@ -220,7 +217,7 @@ static bool is_an_alpha2(const char *alpha2) | |||
220 | { | 217 | { |
221 | if (!alpha2) | 218 | if (!alpha2) |
222 | return false; | 219 | return false; |
223 | if (is_alpha_upper(alpha2[0]) && is_alpha_upper(alpha2[1])) | 220 | if (isalpha(alpha2[0]) && isalpha(alpha2[1])) |
224 | return true; | 221 | return true; |
225 | return false; | 222 | return false; |
226 | } | 223 | } |
@@ -1399,6 +1396,11 @@ static DECLARE_WORK(reg_work, reg_todo); | |||
1399 | 1396 | ||
1400 | static void queue_regulatory_request(struct regulatory_request *request) | 1397 | static void queue_regulatory_request(struct regulatory_request *request) |
1401 | { | 1398 | { |
1399 | if (isalpha(request->alpha2[0])) | ||
1400 | request->alpha2[0] = toupper(request->alpha2[0]); | ||
1401 | if (isalpha(request->alpha2[1])) | ||
1402 | request->alpha2[1] = toupper(request->alpha2[1]); | ||
1403 | |||
1402 | spin_lock(®_requests_lock); | 1404 | spin_lock(®_requests_lock); |
1403 | list_add_tail(&request->list, ®_requests_list); | 1405 | list_add_tail(&request->list, ®_requests_list); |
1404 | spin_unlock(®_requests_lock); | 1406 | spin_unlock(®_requests_lock); |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 5ca8c7180141..503ebb86ba18 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -650,14 +650,14 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
650 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | 650 | bss = container_of(pub, struct cfg80211_internal_bss, pub); |
651 | 651 | ||
652 | spin_lock_bh(&dev->bss_lock); | 652 | spin_lock_bh(&dev->bss_lock); |
653 | if (!list_empty(&bss->list)) { | ||
654 | list_del_init(&bss->list); | ||
655 | dev->bss_generation++; | ||
656 | rb_erase(&bss->rbn, &dev->bss_tree); | ||
653 | 657 | ||
654 | list_del(&bss->list); | 658 | kref_put(&bss->ref, bss_release); |
655 | dev->bss_generation++; | 659 | } |
656 | rb_erase(&bss->rbn, &dev->bss_tree); | ||
657 | |||
658 | spin_unlock_bh(&dev->bss_lock); | 660 | spin_unlock_bh(&dev->bss_lock); |
659 | |||
660 | kref_put(&bss->ref, bss_release); | ||
661 | } | 661 | } |
662 | EXPORT_SYMBOL(cfg80211_unlink_bss); | 662 | EXPORT_SYMBOL(cfg80211_unlink_bss); |
663 | 663 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index a8c2d6b877ae..e17b0bee6bdc 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -411,7 +411,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
411 | 411 | ||
412 | ASSERT_WDEV_LOCK(wdev); | 412 | ASSERT_WDEV_LOCK(wdev); |
413 | 413 | ||
414 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 414 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && |
415 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | ||
415 | return; | 416 | return; |
416 | 417 | ||
417 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | 418 | if (wdev->sme_state != CFG80211_SME_CONNECTING) |
@@ -548,7 +549,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, | |||
548 | 549 | ||
549 | ASSERT_WDEV_LOCK(wdev); | 550 | ASSERT_WDEV_LOCK(wdev); |
550 | 551 | ||
551 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 552 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && |
553 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | ||
552 | return; | 554 | return; |
553 | 555 | ||
554 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 556 | if (wdev->sme_state != CFG80211_SME_CONNECTED) |
@@ -644,7 +646,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
644 | 646 | ||
645 | ASSERT_WDEV_LOCK(wdev); | 647 | ASSERT_WDEV_LOCK(wdev); |
646 | 648 | ||
647 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 649 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && |
650 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | ||
648 | return; | 651 | return; |
649 | 652 | ||
650 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 653 | if (wdev->sme_state != CFG80211_SME_CONNECTED) |
@@ -695,7 +698,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
695 | */ | 698 | */ |
696 | if (rdev->ops->del_key) | 699 | if (rdev->ops->del_key) |
697 | for (i = 0; i < 6; i++) | 700 | for (i = 0; i < 6; i++) |
698 | rdev->ops->del_key(wdev->wiphy, dev, i, NULL); | 701 | rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); |
699 | 702 | ||
700 | #ifdef CONFIG_CFG80211_WEXT | 703 | #ifdef CONFIG_CFG80211_WEXT |
701 | memset(&wrqu, 0, sizeof(wrqu)); | 704 | memset(&wrqu, 0, sizeof(wrqu)); |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 9f2cef3e0ca0..4294fa22bb2d 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -35,6 +35,14 @@ SHOW_FMT(index, "%d", wiphy_idx); | |||
35 | SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); | 35 | SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); |
36 | SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); | 36 | SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); |
37 | 37 | ||
38 | static ssize_t name_show(struct device *dev, | ||
39 | struct device_attribute *attr, | ||
40 | char *buf) { | ||
41 | struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy; | ||
42 | return sprintf(buf, "%s\n", dev_name(&wiphy->dev)); | ||
43 | } | ||
44 | |||
45 | |||
38 | static ssize_t addresses_show(struct device *dev, | 46 | static ssize_t addresses_show(struct device *dev, |
39 | struct device_attribute *attr, | 47 | struct device_attribute *attr, |
40 | char *buf) | 48 | char *buf) |
@@ -57,6 +65,7 @@ static struct device_attribute ieee80211_dev_attrs[] = { | |||
57 | __ATTR_RO(macaddress), | 65 | __ATTR_RO(macaddress), |
58 | __ATTR_RO(address_mask), | 66 | __ATTR_RO(address_mask), |
59 | __ATTR_RO(addresses), | 67 | __ATTR_RO(addresses), |
68 | __ATTR_RO(name), | ||
60 | {} | 69 | {} |
61 | }; | 70 | }; |
62 | 71 | ||
@@ -110,6 +119,13 @@ static int wiphy_resume(struct device *dev) | |||
110 | return ret; | 119 | return ret; |
111 | } | 120 | } |
112 | 121 | ||
122 | static const void *wiphy_namespace(struct device *d) | ||
123 | { | ||
124 | struct wiphy *wiphy = container_of(d, struct wiphy, dev); | ||
125 | |||
126 | return wiphy_net(wiphy); | ||
127 | } | ||
128 | |||
113 | struct class ieee80211_class = { | 129 | struct class ieee80211_class = { |
114 | .name = "ieee80211", | 130 | .name = "ieee80211", |
115 | .owner = THIS_MODULE, | 131 | .owner = THIS_MODULE, |
@@ -120,6 +136,8 @@ struct class ieee80211_class = { | |||
120 | #endif | 136 | #endif |
121 | .suspend = wiphy_suspend, | 137 | .suspend = wiphy_suspend, |
122 | .resume = wiphy_resume, | 138 | .resume = wiphy_resume, |
139 | .ns_type = &net_ns_type_operations, | ||
140 | .namespace = wiphy_namespace, | ||
123 | }; | 141 | }; |
124 | 142 | ||
125 | int wiphy_sysfs_init(void) | 143 | int wiphy_sysfs_init(void) |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 0c8a1e8b7690..76120aeda57d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -144,19 +144,25 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) | |||
144 | 144 | ||
145 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 145 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
146 | struct key_params *params, int key_idx, | 146 | struct key_params *params, int key_idx, |
147 | const u8 *mac_addr) | 147 | bool pairwise, const u8 *mac_addr) |
148 | { | 148 | { |
149 | int i; | 149 | int i; |
150 | 150 | ||
151 | if (key_idx > 5) | 151 | if (key_idx > 5) |
152 | return -EINVAL; | 152 | return -EINVAL; |
153 | 153 | ||
154 | if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
155 | return -EINVAL; | ||
156 | |||
157 | if (pairwise && !mac_addr) | ||
158 | return -EINVAL; | ||
159 | |||
154 | /* | 160 | /* |
155 | * Disallow pairwise keys with non-zero index unless it's WEP | 161 | * Disallow pairwise keys with non-zero index unless it's WEP |
156 | * (because current deployments use pairwise WEP keys with | 162 | * (because current deployments use pairwise WEP keys with |
157 | * non-zero indizes but 802.11i clearly specifies to use zero) | 163 | * non-zero indizes but 802.11i clearly specifies to use zero) |
158 | */ | 164 | */ |
159 | if (mac_addr && key_idx && | 165 | if (pairwise && key_idx && |
160 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && | 166 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && |
161 | params->cipher != WLAN_CIPHER_SUITE_WEP104) | 167 | params->cipher != WLAN_CIPHER_SUITE_WEP104) |
162 | return -EINVAL; | 168 | return -EINVAL; |
@@ -183,7 +189,14 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | |||
183 | return -EINVAL; | 189 | return -EINVAL; |
184 | break; | 190 | break; |
185 | default: | 191 | default: |
186 | return -EINVAL; | 192 | /* |
193 | * We don't know anything about this algorithm, | ||
194 | * allow using it -- but the driver must check | ||
195 | * all parameters! We still check below whether | ||
196 | * or not the driver supports this algorithm, | ||
197 | * of course. | ||
198 | */ | ||
199 | break; | ||
187 | } | 200 | } |
188 | 201 | ||
189 | if (params->seq) { | 202 | if (params->seq) { |
@@ -221,7 +234,7 @@ const unsigned char bridge_tunnel_header[] __aligned(2) = | |||
221 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | 234 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; |
222 | EXPORT_SYMBOL(bridge_tunnel_header); | 235 | EXPORT_SYMBOL(bridge_tunnel_header); |
223 | 236 | ||
224 | unsigned int ieee80211_hdrlen(__le16 fc) | 237 | unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) |
225 | { | 238 | { |
226 | unsigned int hdrlen = 24; | 239 | unsigned int hdrlen = 24; |
227 | 240 | ||
@@ -319,7 +332,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
319 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { | 332 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { |
320 | case cpu_to_le16(IEEE80211_FCTL_TODS): | 333 | case cpu_to_le16(IEEE80211_FCTL_TODS): |
321 | if (unlikely(iftype != NL80211_IFTYPE_AP && | 334 | if (unlikely(iftype != NL80211_IFTYPE_AP && |
322 | iftype != NL80211_IFTYPE_AP_VLAN)) | 335 | iftype != NL80211_IFTYPE_AP_VLAN && |
336 | iftype != NL80211_IFTYPE_P2P_GO)) | ||
323 | return -1; | 337 | return -1; |
324 | break; | 338 | break; |
325 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): | 339 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): |
@@ -347,7 +361,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
347 | break; | 361 | break; |
348 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | 362 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): |
349 | if ((iftype != NL80211_IFTYPE_STATION && | 363 | if ((iftype != NL80211_IFTYPE_STATION && |
350 | iftype != NL80211_IFTYPE_MESH_POINT) || | 364 | iftype != NL80211_IFTYPE_P2P_CLIENT && |
365 | iftype != NL80211_IFTYPE_MESH_POINT) || | ||
351 | (is_multicast_ether_addr(dst) && | 366 | (is_multicast_ether_addr(dst) && |
352 | !compare_ether_addr(src, addr))) | 367 | !compare_ether_addr(src, addr))) |
353 | return -1; | 368 | return -1; |
@@ -424,6 +439,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
424 | switch (iftype) { | 439 | switch (iftype) { |
425 | case NL80211_IFTYPE_AP: | 440 | case NL80211_IFTYPE_AP: |
426 | case NL80211_IFTYPE_AP_VLAN: | 441 | case NL80211_IFTYPE_AP_VLAN: |
442 | case NL80211_IFTYPE_P2P_GO: | ||
427 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 443 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
428 | /* DA BSSID SA */ | 444 | /* DA BSSID SA */ |
429 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 445 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -432,6 +448,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
432 | hdrlen = 24; | 448 | hdrlen = 24; |
433 | break; | 449 | break; |
434 | case NL80211_IFTYPE_STATION: | 450 | case NL80211_IFTYPE_STATION: |
451 | case NL80211_IFTYPE_P2P_CLIENT: | ||
435 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | 452 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
436 | /* BSSID SA DA */ | 453 | /* BSSID SA DA */ |
437 | memcpy(hdr.addr1, bssid, ETH_ALEN); | 454 | memcpy(hdr.addr1, bssid, ETH_ALEN); |
@@ -666,7 +683,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | |||
666 | for (i = 0; i < 6; i++) { | 683 | for (i = 0; i < 6; i++) { |
667 | if (!wdev->connect_keys->params[i].cipher) | 684 | if (!wdev->connect_keys->params[i].cipher) |
668 | continue; | 685 | continue; |
669 | if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, | 686 | if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, |
670 | &wdev->connect_keys->params[i])) { | 687 | &wdev->connect_keys->params[i])) { |
671 | printk(KERN_ERR "%s: failed to set key %d\n", | 688 | printk(KERN_ERR "%s: failed to set key %d\n", |
672 | dev->name, i); | 689 | dev->name, i); |
@@ -771,7 +788,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
771 | 788 | ||
772 | /* if it's part of a bridge, reject changing type to station/ibss */ | 789 | /* if it's part of a bridge, reject changing type to station/ibss */ |
773 | if ((dev->priv_flags & IFF_BRIDGE_PORT) && | 790 | if ((dev->priv_flags & IFF_BRIDGE_PORT) && |
774 | (ntype == NL80211_IFTYPE_ADHOC || ntype == NL80211_IFTYPE_STATION)) | 791 | (ntype == NL80211_IFTYPE_ADHOC || |
792 | ntype == NL80211_IFTYPE_STATION || | ||
793 | ntype == NL80211_IFTYPE_P2P_CLIENT)) | ||
775 | return -EBUSY; | 794 | return -EBUSY; |
776 | 795 | ||
777 | if (ntype != otype) { | 796 | if (ntype != otype) { |
@@ -782,6 +801,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
782 | cfg80211_leave_ibss(rdev, dev, false); | 801 | cfg80211_leave_ibss(rdev, dev, false); |
783 | break; | 802 | break; |
784 | case NL80211_IFTYPE_STATION: | 803 | case NL80211_IFTYPE_STATION: |
804 | case NL80211_IFTYPE_P2P_CLIENT: | ||
785 | cfg80211_disconnect(rdev, dev, | 805 | cfg80211_disconnect(rdev, dev, |
786 | WLAN_REASON_DEAUTH_LEAVING, true); | 806 | WLAN_REASON_DEAUTH_LEAVING, true); |
787 | break; | 807 | break; |
@@ -810,9 +830,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
810 | if (dev->ieee80211_ptr->use_4addr) | 830 | if (dev->ieee80211_ptr->use_4addr) |
811 | break; | 831 | break; |
812 | /* fall through */ | 832 | /* fall through */ |
833 | case NL80211_IFTYPE_P2P_CLIENT: | ||
813 | case NL80211_IFTYPE_ADHOC: | 834 | case NL80211_IFTYPE_ADHOC: |
814 | dev->priv_flags |= IFF_DONT_BRIDGE; | 835 | dev->priv_flags |= IFF_DONT_BRIDGE; |
815 | break; | 836 | break; |
837 | case NL80211_IFTYPE_P2P_GO: | ||
816 | case NL80211_IFTYPE_AP: | 838 | case NL80211_IFTYPE_AP: |
817 | case NL80211_IFTYPE_AP_VLAN: | 839 | case NL80211_IFTYPE_AP_VLAN: |
818 | case NL80211_IFTYPE_WDS: | 840 | case NL80211_IFTYPE_WDS: |
@@ -823,7 +845,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
823 | /* monitor can't bridge anyway */ | 845 | /* monitor can't bridge anyway */ |
824 | break; | 846 | break; |
825 | case NL80211_IFTYPE_UNSPECIFIED: | 847 | case NL80211_IFTYPE_UNSPECIFIED: |
826 | case __NL80211_IFTYPE_AFTER_LAST: | 848 | case NUM_NL80211_IFTYPES: |
827 | /* not happening */ | 849 | /* not happening */ |
828 | break; | 850 | break; |
829 | } | 851 | } |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 7e5c3a45f811..12222ee6ebf2 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -432,14 +432,17 @@ int cfg80211_wext_giwretry(struct net_device *dev, | |||
432 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); | 432 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); |
433 | 433 | ||
434 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 434 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
435 | struct net_device *dev, const u8 *addr, | 435 | struct net_device *dev, bool pairwise, |
436 | bool remove, bool tx_key, int idx, | 436 | const u8 *addr, bool remove, bool tx_key, |
437 | struct key_params *params) | 437 | int idx, struct key_params *params) |
438 | { | 438 | { |
439 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 439 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
440 | int err, i; | 440 | int err, i; |
441 | bool rejoin = false; | 441 | bool rejoin = false; |
442 | 442 | ||
443 | if (pairwise && !addr) | ||
444 | return -EINVAL; | ||
445 | |||
443 | if (!wdev->wext.keys) { | 446 | if (!wdev->wext.keys) { |
444 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), | 447 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), |
445 | GFP_KERNEL); | 448 | GFP_KERNEL); |
@@ -478,7 +481,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
478 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); | 481 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); |
479 | rejoin = true; | 482 | rejoin = true; |
480 | } | 483 | } |
481 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); | 484 | |
485 | if (!pairwise && addr && | ||
486 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
487 | err = -ENOENT; | ||
488 | else | ||
489 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, | ||
490 | pairwise, addr); | ||
482 | } | 491 | } |
483 | wdev->wext.connect.privacy = false; | 492 | wdev->wext.connect.privacy = false; |
484 | /* | 493 | /* |
@@ -507,12 +516,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
507 | if (addr) | 516 | if (addr) |
508 | tx_key = false; | 517 | tx_key = false; |
509 | 518 | ||
510 | if (cfg80211_validate_key_settings(rdev, params, idx, addr)) | 519 | if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr)) |
511 | return -EINVAL; | 520 | return -EINVAL; |
512 | 521 | ||
513 | err = 0; | 522 | err = 0; |
514 | if (wdev->current_bss) | 523 | if (wdev->current_bss) |
515 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); | 524 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, |
525 | pairwise, addr, params); | ||
516 | if (err) | 526 | if (err) |
517 | return err; | 527 | return err; |
518 | 528 | ||
@@ -563,17 +573,17 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
563 | } | 573 | } |
564 | 574 | ||
565 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 575 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
566 | struct net_device *dev, const u8 *addr, | 576 | struct net_device *dev, bool pairwise, |
567 | bool remove, bool tx_key, int idx, | 577 | const u8 *addr, bool remove, bool tx_key, |
568 | struct key_params *params) | 578 | int idx, struct key_params *params) |
569 | { | 579 | { |
570 | int err; | 580 | int err; |
571 | 581 | ||
572 | /* devlist mutex needed for possible IBSS re-join */ | 582 | /* devlist mutex needed for possible IBSS re-join */ |
573 | mutex_lock(&rdev->devlist_mtx); | 583 | mutex_lock(&rdev->devlist_mtx); |
574 | wdev_lock(dev->ieee80211_ptr); | 584 | wdev_lock(dev->ieee80211_ptr); |
575 | err = __cfg80211_set_encryption(rdev, dev, addr, remove, | 585 | err = __cfg80211_set_encryption(rdev, dev, pairwise, addr, |
576 | tx_key, idx, params); | 586 | remove, tx_key, idx, params); |
577 | wdev_unlock(dev->ieee80211_ptr); | 587 | wdev_unlock(dev->ieee80211_ptr); |
578 | mutex_unlock(&rdev->devlist_mtx); | 588 | mutex_unlock(&rdev->devlist_mtx); |
579 | 589 | ||
@@ -635,7 +645,7 @@ int cfg80211_wext_siwencode(struct net_device *dev, | |||
635 | else if (!remove) | 645 | else if (!remove) |
636 | return -EINVAL; | 646 | return -EINVAL; |
637 | 647 | ||
638 | return cfg80211_set_encryption(rdev, dev, NULL, remove, | 648 | return cfg80211_set_encryption(rdev, dev, false, NULL, remove, |
639 | wdev->wext.default_key == -1, | 649 | wdev->wext.default_key == -1, |
640 | idx, ¶ms); | 650 | idx, ¶ms); |
641 | } | 651 | } |
@@ -725,7 +735,9 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, | |||
725 | } | 735 | } |
726 | 736 | ||
727 | return cfg80211_set_encryption( | 737 | return cfg80211_set_encryption( |
728 | rdev, dev, addr, remove, | 738 | rdev, dev, |
739 | !(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY), | ||
740 | addr, remove, | ||
729 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, | 741 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, |
730 | idx, ¶ms); | 742 | idx, ¶ms); |
731 | } | 743 | } |
@@ -1354,6 +1366,10 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) | |||
1354 | } | 1366 | } |
1355 | 1367 | ||
1356 | wstats.qual.updated |= IW_QUAL_NOISE_INVALID; | 1368 | wstats.qual.updated |= IW_QUAL_NOISE_INVALID; |
1369 | if (sinfo.filled & STATION_INFO_RX_DROP_MISC) | ||
1370 | wstats.discard.misc = sinfo.rx_dropped_misc; | ||
1371 | if (sinfo.filled & STATION_INFO_TX_FAILED) | ||
1372 | wstats.discard.retries = sinfo.tx_failed; | ||
1357 | 1373 | ||
1358 | return &wstats; | 1374 | return &wstats; |
1359 | } | 1375 | } |
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index 8f5116f5af19..dc675a3daa3d 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c | |||
@@ -611,7 +611,7 @@ struct iw_statistics *get_wireless_stats(struct net_device *dev) | |||
611 | #endif | 611 | #endif |
612 | 612 | ||
613 | #ifdef CONFIG_CFG80211_WEXT | 613 | #ifdef CONFIG_CFG80211_WEXT |
614 | if (dev->ieee80211_ptr && dev->ieee80211_ptr && | 614 | if (dev->ieee80211_ptr && |
615 | dev->ieee80211_ptr->wiphy && | 615 | dev->ieee80211_ptr->wiphy && |
616 | dev->ieee80211_ptr->wiphy->wext && | 616 | dev->ieee80211_ptr->wiphy->wext && |
617 | dev->ieee80211_ptr->wiphy->wext->get_wireless_stats) | 617 | dev->ieee80211_ptr->wiphy->wext->get_wireless_stats) |
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 9818198add8a..6fffe62d7c25 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -197,6 +197,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
197 | wdev->wext.connect.ssid_len = len; | 197 | wdev->wext.connect.ssid_len = len; |
198 | 198 | ||
199 | wdev->wext.connect.crypto.control_port = false; | 199 | wdev->wext.connect.crypto.control_port = false; |
200 | wdev->wext.connect.crypto.control_port_ethertype = | ||
201 | cpu_to_be16(ETH_P_PAE); | ||
200 | 202 | ||
201 | err = cfg80211_mgd_wext_connect(rdev, wdev); | 203 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
202 | out: | 204 | out: |