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.c283
1 files changed, 266 insertions, 17 deletions
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 82e6002c8d67..d1a3fb99fdf2 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>
@@ -43,10 +44,10 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
43 } 44 }
44 } 45 }
45 46
46 WARN_ON(!done); 47 if (done) {
47 48 nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
48 nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); 49 cfg80211_sme_rx_auth(dev, buf, len);
49 cfg80211_sme_rx_auth(dev, buf, len); 50 }
50 51
51 wdev_unlock(wdev); 52 wdev_unlock(wdev);
52} 53}
@@ -148,22 +149,23 @@ void __cfg80211_send_deauth(struct net_device *dev,
148 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 149 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
149 const u8 *bssid = mgmt->bssid; 150 const u8 *bssid = mgmt->bssid;
150 int i; 151 int i;
152 bool found = false;
151 153
152 ASSERT_WDEV_LOCK(wdev); 154 ASSERT_WDEV_LOCK(wdev);
153 155
154 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
155
156 if (wdev->current_bss && 156 if (wdev->current_bss &&
157 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { 157 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
158 cfg80211_unhold_bss(wdev->current_bss); 158 cfg80211_unhold_bss(wdev->current_bss);
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 } else for (i = 0; i < MAX_AUTH_BSSES; i++) { 162 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
162 if (wdev->auth_bsses[i] && 163 if (wdev->auth_bsses[i] &&
163 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { 164 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
164 cfg80211_unhold_bss(wdev->auth_bsses[i]); 165 cfg80211_unhold_bss(wdev->auth_bsses[i]);
165 cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 166 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
166 wdev->auth_bsses[i] = NULL; 167 wdev->auth_bsses[i] = NULL;
168 found = true;
167 break; 169 break;
168 } 170 }
169 if (wdev->authtry_bsses[i] && 171 if (wdev->authtry_bsses[i] &&
@@ -171,10 +173,16 @@ void __cfg80211_send_deauth(struct net_device *dev,
171 cfg80211_unhold_bss(wdev->authtry_bsses[i]); 173 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
172 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 174 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
173 wdev->authtry_bsses[i] = NULL; 175 wdev->authtry_bsses[i] = NULL;
176 found = true;
174 break; 177 break;
175 } 178 }
176 } 179 }
177 180
181 if (!found)
182 return;
183
184 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
185
178 if (wdev->sme_state == CFG80211_SME_CONNECTED) { 186 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
179 u16 reason_code; 187 u16 reason_code;
180 bool from_ap; 188 bool from_ap;
@@ -370,7 +378,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
370 const u8 *bssid, 378 const u8 *bssid,
371 const u8 *ssid, int ssid_len, 379 const u8 *ssid, int ssid_len,
372 const u8 *ie, int ie_len, 380 const u8 *ie, int ie_len,
373 const u8 *key, int key_len, int key_idx) 381 const u8 *key, int key_len, int key_idx,
382 bool local_state_change)
374{ 383{
375 struct wireless_dev *wdev = dev->ieee80211_ptr; 384 struct wireless_dev *wdev = dev->ieee80211_ptr;
376 struct cfg80211_auth_request req; 385 struct cfg80211_auth_request req;
@@ -400,6 +409,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
400 409
401 memset(&req, 0, sizeof(req)); 410 memset(&req, 0, sizeof(req));
402 411
412 req.local_state_change = local_state_change;
403 req.ie = ie; 413 req.ie = ie;
404 req.ie_len = ie_len; 414 req.ie_len = ie_len;
405 req.auth_type = auth_type; 415 req.auth_type = auth_type;
@@ -426,12 +436,18 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
426 goto out; 436 goto out;
427 } 437 }
428 438
429 wdev->authtry_bsses[slot] = bss; 439 if (local_state_change)
440 wdev->auth_bsses[slot] = bss;
441 else
442 wdev->authtry_bsses[slot] = bss;
430 cfg80211_hold_bss(bss); 443 cfg80211_hold_bss(bss);
431 444
432 err = rdev->ops->auth(&rdev->wiphy, dev, &req); 445 err = rdev->ops->auth(&rdev->wiphy, dev, &req);
433 if (err) { 446 if (err) {
434 wdev->authtry_bsses[slot] = NULL; 447 if (local_state_change)
448 wdev->auth_bsses[slot] = NULL;
449 else
450 wdev->authtry_bsses[slot] = NULL;
435 cfg80211_unhold_bss(bss); 451 cfg80211_unhold_bss(bss);
436 } 452 }
437 453
@@ -446,14 +462,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
446 enum nl80211_auth_type auth_type, const u8 *bssid, 462 enum nl80211_auth_type auth_type, const u8 *bssid,
447 const u8 *ssid, int ssid_len, 463 const u8 *ssid, int ssid_len,
448 const u8 *ie, int ie_len, 464 const u8 *ie, int ie_len,
449 const u8 *key, int key_len, int key_idx) 465 const u8 *key, int key_len, int key_idx,
466 bool local_state_change)
450{ 467{
451 int err; 468 int err;
452 469
453 wdev_lock(dev->ieee80211_ptr); 470 wdev_lock(dev->ieee80211_ptr);
454 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, 471 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
455 ssid, ssid_len, ie, ie_len, 472 ssid, ssid_len, ie, ie_len,
456 key, key_len, key_idx); 473 key, key_len, key_idx, local_state_change);
457 wdev_unlock(dev->ieee80211_ptr); 474 wdev_unlock(dev->ieee80211_ptr);
458 475
459 return err; 476 return err;
@@ -547,7 +564,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
547 564
548int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 565int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
549 struct net_device *dev, const u8 *bssid, 566 struct net_device *dev, const u8 *bssid,
550 const u8 *ie, int ie_len, u16 reason) 567 const u8 *ie, int ie_len, u16 reason,
568 bool local_state_change)
551{ 569{
552 struct wireless_dev *wdev = dev->ieee80211_ptr; 570 struct wireless_dev *wdev = dev->ieee80211_ptr;
553 struct cfg80211_deauth_request req; 571 struct cfg80211_deauth_request req;
@@ -557,6 +575,7 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
557 575
558 memset(&req, 0, sizeof(req)); 576 memset(&req, 0, sizeof(req));
559 req.reason_code = reason; 577 req.reason_code = reason;
578 req.local_state_change = local_state_change;
560 req.ie = ie; 579 req.ie = ie;
561 req.ie_len = ie_len; 580 req.ie_len = ie_len;
562 if (wdev->current_bss && 581 if (wdev->current_bss &&
@@ -583,13 +602,15 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
583 602
584int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 603int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
585 struct net_device *dev, const u8 *bssid, 604 struct net_device *dev, const u8 *bssid,
586 const u8 *ie, int ie_len, u16 reason) 605 const u8 *ie, int ie_len, u16 reason,
606 bool local_state_change)
587{ 607{
588 struct wireless_dev *wdev = dev->ieee80211_ptr; 608 struct wireless_dev *wdev = dev->ieee80211_ptr;
589 int err; 609 int err;
590 610
591 wdev_lock(wdev); 611 wdev_lock(wdev);
592 err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason); 612 err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason,
613 local_state_change);
593 wdev_unlock(wdev); 614 wdev_unlock(wdev);
594 615
595 return err; 616 return err;
@@ -597,7 +618,8 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
597 618
598static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, 619static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
599 struct net_device *dev, const u8 *bssid, 620 struct net_device *dev, const u8 *bssid,
600 const u8 *ie, int ie_len, u16 reason) 621 const u8 *ie, int ie_len, u16 reason,
622 bool local_state_change)
601{ 623{
602 struct wireless_dev *wdev = dev->ieee80211_ptr; 624 struct wireless_dev *wdev = dev->ieee80211_ptr;
603 struct cfg80211_disassoc_request req; 625 struct cfg80211_disassoc_request req;
@@ -612,6 +634,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
612 634
613 memset(&req, 0, sizeof(req)); 635 memset(&req, 0, sizeof(req));
614 req.reason_code = reason; 636 req.reason_code = reason;
637 req.local_state_change = local_state_change;
615 req.ie = ie; 638 req.ie = ie;
616 req.ie_len = ie_len; 639 req.ie_len = ie_len;
617 if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) 640 if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
@@ -624,13 +647,15 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
624 647
625int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, 648int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
626 struct net_device *dev, const u8 *bssid, 649 struct net_device *dev, const u8 *bssid,
627 const u8 *ie, int ie_len, u16 reason) 650 const u8 *ie, int ie_len, u16 reason,
651 bool local_state_change)
628{ 652{
629 struct wireless_dev *wdev = dev->ieee80211_ptr; 653 struct wireless_dev *wdev = dev->ieee80211_ptr;
630 int err; 654 int err;
631 655
632 wdev_lock(wdev); 656 wdev_lock(wdev);
633 err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason); 657 err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason,
658 local_state_change);
634 wdev_unlock(wdev); 659 wdev_unlock(wdev);
635 660
636 return err; 661 return err;
@@ -684,3 +709,227 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
684 } 709 }
685 } 710 }
686} 711}
712
713void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
714 struct ieee80211_channel *chan,
715 enum nl80211_channel_type channel_type,
716 unsigned int duration, gfp_t gfp)
717{
718 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
719 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
720
721 nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type,
722 duration, gfp);
723}
724EXPORT_SYMBOL(cfg80211_ready_on_channel);
725
726void cfg80211_remain_on_channel_expired(struct net_device *dev,
727 u64 cookie,
728 struct ieee80211_channel *chan,
729 enum nl80211_channel_type channel_type,
730 gfp_t gfp)
731{
732 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
733 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
734
735 nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan,
736 channel_type, gfp);
737}
738EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
739
740void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
741 struct station_info *sinfo, gfp_t gfp)
742{
743 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
744 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
745
746 nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
747}
748EXPORT_SYMBOL(cfg80211_new_sta);
749
750struct cfg80211_action_registration {
751 struct list_head list;
752
753 u32 nlpid;
754
755 int match_len;
756
757 u8 match[];
758};
759
760int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
761 const u8 *match_data, int match_len)
762{
763 struct cfg80211_action_registration *reg, *nreg;
764 int err = 0;
765
766 nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
767 if (!nreg)
768 return -ENOMEM;
769
770 spin_lock_bh(&wdev->action_registrations_lock);
771
772 list_for_each_entry(reg, &wdev->action_registrations, list) {
773 int mlen = min(match_len, reg->match_len);
774
775 if (memcmp(reg->match, match_data, mlen) == 0) {
776 err = -EALREADY;
777 break;
778 }
779 }
780
781 if (err) {
782 kfree(nreg);
783 goto out;
784 }
785
786 memcpy(nreg->match, match_data, match_len);
787 nreg->match_len = match_len;
788 nreg->nlpid = snd_pid;
789 list_add(&nreg->list, &wdev->action_registrations);
790
791 out:
792 spin_unlock_bh(&wdev->action_registrations_lock);
793 return err;
794}
795
796void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid)
797{
798 struct cfg80211_action_registration *reg, *tmp;
799
800 spin_lock_bh(&wdev->action_registrations_lock);
801
802 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
803 if (reg->nlpid == nlpid) {
804 list_del(&reg->list);
805 kfree(reg);
806 }
807 }
808
809 spin_unlock_bh(&wdev->action_registrations_lock);
810}
811
812void cfg80211_mlme_purge_actions(struct wireless_dev *wdev)
813{
814 struct cfg80211_action_registration *reg, *tmp;
815
816 spin_lock_bh(&wdev->action_registrations_lock);
817
818 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
819 list_del(&reg->list);
820 kfree(reg);
821 }
822
823 spin_unlock_bh(&wdev->action_registrations_lock);
824}
825
826int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
827 struct net_device *dev,
828 struct ieee80211_channel *chan,
829 enum nl80211_channel_type channel_type,
830 bool channel_type_valid,
831 const u8 *buf, size_t len, u64 *cookie)
832{
833 struct wireless_dev *wdev = dev->ieee80211_ptr;
834 const struct ieee80211_mgmt *mgmt;
835
836 if (rdev->ops->action == NULL)
837 return -EOPNOTSUPP;
838 if (len < 24 + 1)
839 return -EINVAL;
840
841 mgmt = (const struct ieee80211_mgmt *) buf;
842 if (!ieee80211_is_action(mgmt->frame_control))
843 return -EINVAL;
844 if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
845 /* Verify that we are associated with the destination AP */
846 wdev_lock(wdev);
847
848 if (!wdev->current_bss ||
849 memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
850 ETH_ALEN) != 0 ||
851 (wdev->iftype == NL80211_IFTYPE_STATION &&
852 memcmp(wdev->current_bss->pub.bssid, mgmt->da,
853 ETH_ALEN) != 0)) {
854 wdev_unlock(wdev);
855 return -ENOTCONN;
856 }
857
858 wdev_unlock(wdev);
859 }
860
861 if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
862 return -EINVAL;
863
864 /* Transmit the Action frame as requested by user space */
865 return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
866 channel_type_valid, buf, len, cookie);
867}
868
869bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
870 size_t len, gfp_t gfp)
871{
872 struct wireless_dev *wdev = dev->ieee80211_ptr;
873 struct wiphy *wiphy = wdev->wiphy;
874 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
875 struct cfg80211_action_registration *reg;
876 const u8 *action_data;
877 int action_data_len;
878 bool result = false;
879
880 /* frame length - min size excluding category */
881 action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1);
882
883 /* action data starts with category */
884 action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1;
885
886 spin_lock_bh(&wdev->action_registrations_lock);
887
888 list_for_each_entry(reg, &wdev->action_registrations, list) {
889 if (reg->match_len > action_data_len)
890 continue;
891
892 if (memcmp(reg->match, action_data, reg->match_len))
893 continue;
894
895 /* found match! */
896
897 /* Indicate the received Action frame to user space */
898 if (nl80211_send_action(rdev, dev, reg->nlpid, freq,
899 buf, len, gfp))
900 continue;
901
902 result = true;
903 break;
904 }
905
906 spin_unlock_bh(&wdev->action_registrations_lock);
907
908 return result;
909}
910EXPORT_SYMBOL(cfg80211_rx_action);
911
912void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
913 const u8 *buf, size_t len, bool ack, gfp_t gfp)
914{
915 struct wireless_dev *wdev = dev->ieee80211_ptr;
916 struct wiphy *wiphy = wdev->wiphy;
917 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
918
919 /* Indicate TX status of the Action frame to user space */
920 nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
921}
922EXPORT_SYMBOL(cfg80211_action_tx_status);
923
924void cfg80211_cqm_rssi_notify(struct net_device *dev,
925 enum nl80211_cqm_rssi_threshold_event rssi_event,
926 gfp_t gfp)
927{
928 struct wireless_dev *wdev = dev->ieee80211_ptr;
929 struct wiphy *wiphy = wdev->wiphy;
930 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
931
932 /* Indicate roaming trigger event to user space */
933 nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp);
934}
935EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);