aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/mlme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/mlme.c')
-rw-r--r--net/wireless/mlme.c331
1 files changed, 280 insertions, 51 deletions
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 0a6b7a0eca6b..22139fa46115 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -8,6 +8,7 @@
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/netdevice.h> 9#include <linux/netdevice.h>
10#include <linux/nl80211.h> 10#include <linux/nl80211.h>
11#include <linux/slab.h>
11#include <linux/wireless.h> 12#include <linux/wireless.h>
12#include <net/cfg80211.h> 13#include <net/cfg80211.h>
13#include <net/iw_handler.h> 14#include <net/iw_handler.h>
@@ -62,7 +63,6 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
62 u8 *ie = mgmt->u.assoc_resp.variable; 63 u8 *ie = mgmt->u.assoc_resp.variable;
63 int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); 64 int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
64 struct cfg80211_internal_bss *bss = NULL; 65 struct cfg80211_internal_bss *bss = NULL;
65 bool need_connect_result = true;
66 66
67 wdev_lock(wdev); 67 wdev_lock(wdev);
68 68
@@ -94,10 +94,20 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
94 } 94 }
95 } 95 }
96 96
97 WARN_ON(!bss); 97 /*
98 * We might be coming here because the driver reported
99 * a successful association at the same time as the
100 * user requested a deauth. In that case, we will have
101 * removed the BSS from the auth_bsses list due to the
102 * deauth request when the assoc response makes it. If
103 * the two code paths acquire the lock the other way
104 * around, that's just the standard situation of a
105 * deauth being requested while connected.
106 */
107 if (!bss)
108 goto out;
98 } else if (wdev->conn) { 109 } else if (wdev->conn) {
99 cfg80211_sme_failed_assoc(wdev); 110 cfg80211_sme_failed_assoc(wdev);
100 need_connect_result = false;
101 /* 111 /*
102 * do not call connect_result() now because the 112 * do not call connect_result() now because the
103 * sme will schedule work that does it later. 113 * sme will schedule work that does it later.
@@ -130,7 +140,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
130} 140}
131EXPORT_SYMBOL(cfg80211_send_rx_assoc); 141EXPORT_SYMBOL(cfg80211_send_rx_assoc);
132 142
133static void __cfg80211_send_deauth(struct net_device *dev, 143void __cfg80211_send_deauth(struct net_device *dev,
134 const u8 *buf, size_t len) 144 const u8 *buf, size_t len)
135{ 145{
136 struct wireless_dev *wdev = dev->ieee80211_ptr; 146 struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -139,25 +149,23 @@ static void __cfg80211_send_deauth(struct net_device *dev,
139 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 149 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
140 const u8 *bssid = mgmt->bssid; 150 const u8 *bssid = mgmt->bssid;
141 int i; 151 int i;
142 bool done = false; 152 bool found = false;
143 153
144 ASSERT_WDEV_LOCK(wdev); 154 ASSERT_WDEV_LOCK(wdev);
145 155
146 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
147
148 if (wdev->current_bss && 156 if (wdev->current_bss &&
149 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { 157 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
150 done = true;
151 cfg80211_unhold_bss(wdev->current_bss); 158 cfg80211_unhold_bss(wdev->current_bss);
152 cfg80211_put_bss(&wdev->current_bss->pub); 159 cfg80211_put_bss(&wdev->current_bss->pub);
153 wdev->current_bss = NULL; 160 wdev->current_bss = NULL;
161 found = true;
154 } else for (i = 0; i < MAX_AUTH_BSSES; i++) { 162 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
155 if (wdev->auth_bsses[i] && 163 if (wdev->auth_bsses[i] &&
156 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { 164 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
157 cfg80211_unhold_bss(wdev->auth_bsses[i]); 165 cfg80211_unhold_bss(wdev->auth_bsses[i]);
158 cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 166 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
159 wdev->auth_bsses[i] = NULL; 167 wdev->auth_bsses[i] = NULL;
160 done = true; 168 found = true;
161 break; 169 break;
162 } 170 }
163 if (wdev->authtry_bsses[i] && 171 if (wdev->authtry_bsses[i] &&
@@ -165,12 +173,15 @@ static void __cfg80211_send_deauth(struct net_device *dev,
165 cfg80211_unhold_bss(wdev->authtry_bsses[i]); 173 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
166 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 174 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
167 wdev->authtry_bsses[i] = NULL; 175 wdev->authtry_bsses[i] = NULL;
168 done = true; 176 found = true;
169 break; 177 break;
170 } 178 }
171 } 179 }
172 180
173 WARN_ON(!done); 181 if (!found)
182 return;
183
184 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
174 185
175 if (wdev->sme_state == CFG80211_SME_CONNECTED) { 186 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
176 u16 reason_code; 187 u16 reason_code;
@@ -186,27 +197,19 @@ static void __cfg80211_send_deauth(struct net_device *dev,
186 false, NULL); 197 false, NULL);
187 } 198 }
188} 199}
200EXPORT_SYMBOL(__cfg80211_send_deauth);
189 201
190 202void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
191void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
192 void *cookie)
193{ 203{
194 struct wireless_dev *wdev = dev->ieee80211_ptr; 204 struct wireless_dev *wdev = dev->ieee80211_ptr;
195 205
196 BUG_ON(cookie && wdev != cookie); 206 wdev_lock(wdev);
197 207 __cfg80211_send_deauth(dev, buf, len);
198 if (cookie) { 208 wdev_unlock(wdev);
199 /* called within callback */
200 __cfg80211_send_deauth(dev, buf, len);
201 } else {
202 wdev_lock(wdev);
203 __cfg80211_send_deauth(dev, buf, len);
204 wdev_unlock(wdev);
205 }
206} 209}
207EXPORT_SYMBOL(cfg80211_send_deauth); 210EXPORT_SYMBOL(cfg80211_send_deauth);
208 211
209static void __cfg80211_send_disassoc(struct net_device *dev, 212void __cfg80211_send_disassoc(struct net_device *dev,
210 const u8 *buf, size_t len) 213 const u8 *buf, size_t len)
211{ 214{
212 struct wireless_dev *wdev = dev->ieee80211_ptr; 215 struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -247,40 +250,24 @@ static void __cfg80211_send_disassoc(struct net_device *dev,
247 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; 250 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
248 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); 251 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
249} 252}
253EXPORT_SYMBOL(__cfg80211_send_disassoc);
250 254
251void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, 255void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
252 void *cookie)
253{ 256{
254 struct wireless_dev *wdev = dev->ieee80211_ptr; 257 struct wireless_dev *wdev = dev->ieee80211_ptr;
255 258
256 BUG_ON(cookie && wdev != cookie); 259 wdev_lock(wdev);
257 260 __cfg80211_send_disassoc(dev, buf, len);
258 if (cookie) { 261 wdev_unlock(wdev);
259 /* called within callback */
260 __cfg80211_send_disassoc(dev, buf, len);
261 } else {
262 wdev_lock(wdev);
263 __cfg80211_send_disassoc(dev, buf, len);
264 wdev_unlock(wdev);
265 }
266} 262}
267EXPORT_SYMBOL(cfg80211_send_disassoc); 263EXPORT_SYMBOL(cfg80211_send_disassoc);
268 264
269void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) 265static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr)
270{ 266{
271 struct wireless_dev *wdev = dev->ieee80211_ptr;
272 struct wiphy *wiphy = wdev->wiphy;
273 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
274 int i; 267 int i;
275 bool done = false; 268 bool done = false;
276 269
277 wdev_lock(wdev); 270 ASSERT_WDEV_LOCK(wdev);
278
279 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
280 if (wdev->sme_state == CFG80211_SME_CONNECTING)
281 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
282 WLAN_STATUS_UNSPECIFIED_FAILURE,
283 false, NULL);
284 271
285 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { 272 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
286 if (wdev->authtry_bsses[i] && 273 if (wdev->authtry_bsses[i] &&
@@ -295,6 +282,29 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
295 } 282 }
296 283
297 WARN_ON(!done); 284 WARN_ON(!done);
285}
286
287void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr)
288{
289 __cfg80211_auth_remove(dev->ieee80211_ptr, addr);
290}
291EXPORT_SYMBOL(__cfg80211_auth_canceled);
292
293void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
294{
295 struct wireless_dev *wdev = dev->ieee80211_ptr;
296 struct wiphy *wiphy = wdev->wiphy;
297 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
298
299 wdev_lock(wdev);
300
301 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
302 if (wdev->sme_state == CFG80211_SME_CONNECTING)
303 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
304 WLAN_STATUS_UNSPECIFIED_FAILURE,
305 false, NULL);
306
307 __cfg80211_auth_remove(wdev, addr);
298 308
299 wdev_unlock(wdev); 309 wdev_unlock(wdev);
300} 310}
@@ -340,7 +350,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
340{ 350{
341 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 351 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
342 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 352 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
343#ifdef CONFIG_WIRELESS_EXT 353#ifdef CONFIG_CFG80211_WEXT
344 union iwreq_data wrqu; 354 union iwreq_data wrqu;
345 char *buf = kmalloc(128, gfp); 355 char *buf = kmalloc(128, gfp);
346 356
@@ -469,12 +479,23 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
469 struct cfg80211_assoc_request req; 479 struct cfg80211_assoc_request req;
470 struct cfg80211_internal_bss *bss; 480 struct cfg80211_internal_bss *bss;
471 int i, err, slot = -1; 481 int i, err, slot = -1;
482 bool was_connected = false;
472 483
473 ASSERT_WDEV_LOCK(wdev); 484 ASSERT_WDEV_LOCK(wdev);
474 485
475 memset(&req, 0, sizeof(req)); 486 memset(&req, 0, sizeof(req));
476 487
477 if (wdev->current_bss) 488 if (wdev->current_bss && prev_bssid &&
489 memcmp(wdev->current_bss->pub.bssid, prev_bssid, ETH_ALEN) == 0) {
490 /*
491 * Trying to reassociate: Allow this to proceed and let the old
492 * association to be dropped when the new one is completed.
493 */
494 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
495 was_connected = true;
496 wdev->sme_state = CFG80211_SME_CONNECTING;
497 }
498 } else if (wdev->current_bss)
478 return -EALREADY; 499 return -EALREADY;
479 500
480 req.ie = ie; 501 req.ie = ie;
@@ -484,8 +505,11 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
484 req.prev_bssid = prev_bssid; 505 req.prev_bssid = prev_bssid;
485 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, 506 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
486 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); 507 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
487 if (!req.bss) 508 if (!req.bss) {
509 if (was_connected)
510 wdev->sme_state = CFG80211_SME_CONNECTED;
488 return -ENOENT; 511 return -ENOENT;
512 }
489 513
490 bss = bss_from_pub(req.bss); 514 bss = bss_from_pub(req.bss);
491 515
@@ -503,6 +527,8 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
503 527
504 err = rdev->ops->assoc(&rdev->wiphy, dev, &req); 528 err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
505 out: 529 out:
530 if (err && was_connected)
531 wdev->sme_state = CFG80211_SME_CONNECTED;
506 /* still a reference in wdev->auth_bsses[slot] */ 532 /* still a reference in wdev->auth_bsses[slot] */
507 cfg80211_put_bss(req.bss); 533 cfg80211_put_bss(req.bss);
508 return err; 534 return err;
@@ -666,3 +692,206 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
666 } 692 }
667 } 693 }
668} 694}
695
696void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
697 struct ieee80211_channel *chan,
698 enum nl80211_channel_type channel_type,
699 unsigned int duration, gfp_t gfp)
700{
701 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
702 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
703
704 nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type,
705 duration, gfp);
706}
707EXPORT_SYMBOL(cfg80211_ready_on_channel);
708
709void cfg80211_remain_on_channel_expired(struct net_device *dev,
710 u64 cookie,
711 struct ieee80211_channel *chan,
712 enum nl80211_channel_type channel_type,
713 gfp_t gfp)
714{
715 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
716 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
717
718 nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan,
719 channel_type, gfp);
720}
721EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
722
723void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
724 struct station_info *sinfo, gfp_t gfp)
725{
726 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
727 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
728
729 nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
730}
731EXPORT_SYMBOL(cfg80211_new_sta);
732
733struct cfg80211_action_registration {
734 struct list_head list;
735
736 u32 nlpid;
737
738 int match_len;
739
740 u8 match[];
741};
742
743int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
744 const u8 *match_data, int match_len)
745{
746 struct cfg80211_action_registration *reg, *nreg;
747 int err = 0;
748
749 nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
750 if (!nreg)
751 return -ENOMEM;
752
753 spin_lock_bh(&wdev->action_registrations_lock);
754
755 list_for_each_entry(reg, &wdev->action_registrations, list) {
756 int mlen = min(match_len, reg->match_len);
757
758 if (memcmp(reg->match, match_data, mlen) == 0) {
759 err = -EALREADY;
760 break;
761 }
762 }
763
764 if (err) {
765 kfree(nreg);
766 goto out;
767 }
768
769 memcpy(nreg->match, match_data, match_len);
770 nreg->match_len = match_len;
771 nreg->nlpid = snd_pid;
772 list_add(&nreg->list, &wdev->action_registrations);
773
774 out:
775 spin_unlock_bh(&wdev->action_registrations_lock);
776 return err;
777}
778
779void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid)
780{
781 struct cfg80211_action_registration *reg, *tmp;
782
783 spin_lock_bh(&wdev->action_registrations_lock);
784
785 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
786 if (reg->nlpid == nlpid) {
787 list_del(&reg->list);
788 kfree(reg);
789 }
790 }
791
792 spin_unlock_bh(&wdev->action_registrations_lock);
793}
794
795void cfg80211_mlme_purge_actions(struct wireless_dev *wdev)
796{
797 struct cfg80211_action_registration *reg, *tmp;
798
799 spin_lock_bh(&wdev->action_registrations_lock);
800
801 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
802 list_del(&reg->list);
803 kfree(reg);
804 }
805
806 spin_unlock_bh(&wdev->action_registrations_lock);
807}
808
809int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
810 struct net_device *dev,
811 struct ieee80211_channel *chan,
812 enum nl80211_channel_type channel_type,
813 const u8 *buf, size_t len, u64 *cookie)
814{
815 struct wireless_dev *wdev = dev->ieee80211_ptr;
816 const struct ieee80211_mgmt *mgmt;
817
818 if (rdev->ops->action == NULL)
819 return -EOPNOTSUPP;
820 if (len < 24 + 1)
821 return -EINVAL;
822
823 mgmt = (const struct ieee80211_mgmt *) buf;
824 if (!ieee80211_is_action(mgmt->frame_control))
825 return -EINVAL;
826 if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
827 /* Verify that we are associated with the destination AP */
828 if (!wdev->current_bss ||
829 memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
830 ETH_ALEN) != 0 ||
831 memcmp(wdev->current_bss->pub.bssid, mgmt->da,
832 ETH_ALEN) != 0)
833 return -ENOTCONN;
834 }
835
836 if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
837 return -EINVAL;
838
839 /* Transmit the Action frame as requested by user space */
840 return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
841 buf, len, cookie);
842}
843
844bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
845 size_t len, gfp_t gfp)
846{
847 struct wireless_dev *wdev = dev->ieee80211_ptr;
848 struct wiphy *wiphy = wdev->wiphy;
849 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
850 struct cfg80211_action_registration *reg;
851 const u8 *action_data;
852 int action_data_len;
853 bool result = false;
854
855 /* frame length - min size excluding category */
856 action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1);
857
858 /* action data starts with category */
859 action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1;
860
861 spin_lock_bh(&wdev->action_registrations_lock);
862
863 list_for_each_entry(reg, &wdev->action_registrations, list) {
864 if (reg->match_len > action_data_len)
865 continue;
866
867 if (memcmp(reg->match, action_data, reg->match_len))
868 continue;
869
870 /* found match! */
871
872 /* Indicate the received Action frame to user space */
873 if (nl80211_send_action(rdev, dev, reg->nlpid, freq,
874 buf, len, gfp))
875 continue;
876
877 result = true;
878 break;
879 }
880
881 spin_unlock_bh(&wdev->action_registrations_lock);
882
883 return result;
884}
885EXPORT_SYMBOL(cfg80211_rx_action);
886
887void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
888 const u8 *buf, size_t len, bool ack, gfp_t gfp)
889{
890 struct wireless_dev *wdev = dev->ieee80211_ptr;
891 struct wiphy *wiphy = wdev->wiphy;
892 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
893
894 /* Indicate TX status of the Action frame to user space */
895 nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
896}
897EXPORT_SYMBOL(cfg80211_action_tx_status);