diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 259 |
1 files changed, 180 insertions, 79 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 841b8450b3de..7ecda9d59d8a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 30 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
31 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 31 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
32 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 32 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) |
33 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) | 33 | #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) |
34 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | 34 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) |
35 | 35 | ||
36 | /* utils */ | 36 | /* utils */ |
@@ -82,38 +82,23 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | |||
82 | 82 | ||
83 | /* frame sending functions */ | 83 | /* frame sending functions */ |
84 | 84 | ||
85 | static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len) | ||
86 | { | ||
87 | if (ies) | ||
88 | memcpy(skb_put(skb, ies_len), ies, ies_len); | ||
89 | } | ||
90 | |||
91 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | 85 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) |
92 | { | 86 | { |
93 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 87 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
94 | struct ieee80211_local *local = sdata->local; | 88 | struct ieee80211_local *local = sdata->local; |
95 | struct sk_buff *skb; | 89 | struct sk_buff *skb; |
96 | struct ieee80211_mgmt *mgmt; | 90 | struct ieee80211_mgmt *mgmt; |
97 | u8 *pos, *ies, *ht_ie, *e_ies; | 91 | u8 *pos, *ies, *ht_ie; |
98 | int i, len, count, rates_len, supp_rates_len; | 92 | int i, len, count, rates_len, supp_rates_len; |
99 | u16 capab; | 93 | u16 capab; |
100 | struct ieee80211_bss *bss; | 94 | struct ieee80211_bss *bss; |
101 | int wmm = 0; | 95 | int wmm = 0; |
102 | struct ieee80211_supported_band *sband; | 96 | struct ieee80211_supported_band *sband; |
103 | u32 rates = 0; | 97 | u32 rates = 0; |
104 | size_t e_ies_len; | ||
105 | |||
106 | if (ifmgd->flags & IEEE80211_IBSS_PREV_BSSID_SET) { | ||
107 | e_ies = sdata->u.mgd.ie_reassocreq; | ||
108 | e_ies_len = sdata->u.mgd.ie_reassocreq_len; | ||
109 | } else { | ||
110 | e_ies = sdata->u.mgd.ie_assocreq; | ||
111 | e_ies_len = sdata->u.mgd.ie_assocreq_len; | ||
112 | } | ||
113 | 98 | ||
114 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 99 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
115 | sizeof(*mgmt) + 200 + ifmgd->extra_ie_len + | 100 | sizeof(*mgmt) + 200 + ifmgd->extra_ie_len + |
116 | ifmgd->ssid_len + e_ies_len); | 101 | ifmgd->ssid_len); |
117 | if (!skb) { | 102 | if (!skb) { |
118 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | 103 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " |
119 | "frame\n", sdata->dev->name); | 104 | "frame\n", sdata->dev->name); |
@@ -304,8 +289,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
304 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 289 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); |
305 | } | 290 | } |
306 | 291 | ||
307 | add_extra_ies(skb, e_ies, e_ies_len); | ||
308 | |||
309 | kfree(ifmgd->assocreq_ies); | 292 | kfree(ifmgd->assocreq_ies); |
310 | ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies; | 293 | ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies; |
311 | ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL); | 294 | ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL); |
@@ -323,19 +306,8 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
323 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 306 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
324 | struct sk_buff *skb; | 307 | struct sk_buff *skb; |
325 | struct ieee80211_mgmt *mgmt; | 308 | struct ieee80211_mgmt *mgmt; |
326 | u8 *ies; | ||
327 | size_t ies_len; | ||
328 | |||
329 | if (stype == IEEE80211_STYPE_DEAUTH) { | ||
330 | ies = sdata->u.mgd.ie_deauth; | ||
331 | ies_len = sdata->u.mgd.ie_deauth_len; | ||
332 | } else { | ||
333 | ies = sdata->u.mgd.ie_disassoc; | ||
334 | ies_len = sdata->u.mgd.ie_disassoc_len; | ||
335 | } | ||
336 | 309 | ||
337 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + | 310 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); |
338 | ies_len); | ||
339 | if (!skb) { | 311 | if (!skb) { |
340 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | 312 | printk(KERN_DEBUG "%s: failed to allocate buffer for " |
341 | "deauth/disassoc frame\n", sdata->dev->name); | 313 | "deauth/disassoc frame\n", sdata->dev->name); |
@@ -353,8 +325,6 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
353 | /* u.deauth.reason_code == u.disassoc.reason_code */ | 325 | /* u.deauth.reason_code == u.disassoc.reason_code */ |
354 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | 326 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); |
355 | 327 | ||
356 | add_extra_ies(skb, ies, ies_len); | ||
357 | |||
358 | ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); | 328 | ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); |
359 | } | 329 | } |
360 | 330 | ||
@@ -640,6 +610,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
640 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 610 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
641 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); | 611 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); |
642 | 612 | ||
613 | cfg80211_hold_bss(&bss->cbss); | ||
614 | |||
643 | ieee80211_rx_bss_put(local, bss); | 615 | ieee80211_rx_bss_put(local, bss); |
644 | } | 616 | } |
645 | 617 | ||
@@ -682,6 +654,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
682 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) | 654 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) |
683 | { | 655 | { |
684 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 656 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
657 | struct ieee80211_local *local = sdata->local; | ||
685 | 658 | ||
686 | ifmgd->direct_probe_tries++; | 659 | ifmgd->direct_probe_tries++; |
687 | if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { | 660 | if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { |
@@ -697,6 +670,13 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) | |||
697 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | 670 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
698 | sdata->local->hw.conf.channel->center_freq, | 671 | sdata->local->hw.conf.channel->center_freq, |
699 | ifmgd->ssid, ifmgd->ssid_len); | 672 | ifmgd->ssid, ifmgd->ssid_len); |
673 | |||
674 | /* | ||
675 | * We might have a pending scan which had no chance to run yet | ||
676 | * due to state == IEEE80211_STA_MLME_DIRECT_PROBE. | ||
677 | * Hence, queue the STAs work again | ||
678 | */ | ||
679 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
700 | return; | 680 | return; |
701 | } | 681 | } |
702 | 682 | ||
@@ -721,6 +701,9 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) | |||
721 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) | 701 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) |
722 | { | 702 | { |
723 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 703 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
704 | struct ieee80211_local *local = sdata->local; | ||
705 | u8 *ies; | ||
706 | size_t ies_len; | ||
724 | 707 | ||
725 | ifmgd->auth_tries++; | 708 | ifmgd->auth_tries++; |
726 | if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { | 709 | if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { |
@@ -732,6 +715,13 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) | |||
732 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | 715 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
733 | sdata->local->hw.conf.channel->center_freq, | 716 | sdata->local->hw.conf.channel->center_freq, |
734 | ifmgd->ssid, ifmgd->ssid_len); | 717 | ifmgd->ssid, ifmgd->ssid_len); |
718 | |||
719 | /* | ||
720 | * We might have a pending scan which had no chance to run yet | ||
721 | * due to state == IEEE80211_STA_MLME_AUTHENTICATE. | ||
722 | * Hence, queue the STAs work again | ||
723 | */ | ||
724 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
735 | return; | 725 | return; |
736 | } | 726 | } |
737 | 727 | ||
@@ -739,7 +729,14 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) | |||
739 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", | 729 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", |
740 | sdata->dev->name, ifmgd->bssid); | 730 | sdata->dev->name, ifmgd->bssid); |
741 | 731 | ||
742 | ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, NULL, 0, | 732 | if (ifmgd->flags & IEEE80211_STA_EXT_SME) { |
733 | ies = ifmgd->sme_auth_ie; | ||
734 | ies_len = ifmgd->sme_auth_ie_len; | ||
735 | } else { | ||
736 | ies = NULL; | ||
737 | ies_len = 0; | ||
738 | } | ||
739 | ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ies, ies_len, | ||
743 | ifmgd->bssid, 0); | 740 | ifmgd->bssid, 0); |
744 | ifmgd->auth_transaction = 2; | 741 | ifmgd->auth_transaction = 2; |
745 | 742 | ||
@@ -756,6 +753,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
756 | { | 753 | { |
757 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 754 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
758 | struct ieee80211_local *local = sdata->local; | 755 | struct ieee80211_local *local = sdata->local; |
756 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; | ||
757 | struct ieee80211_bss *bss; | ||
759 | struct sta_info *sta; | 758 | struct sta_info *sta; |
760 | u32 changed = 0, config_changed = 0; | 759 | u32 changed = 0, config_changed = 0; |
761 | 760 | ||
@@ -779,6 +778,15 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
779 | 778 | ||
780 | ieee80211_sta_tear_down_BA_sessions(sta); | 779 | ieee80211_sta_tear_down_BA_sessions(sta); |
781 | 780 | ||
781 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, | ||
782 | conf->channel->center_freq, | ||
783 | ifmgd->ssid, ifmgd->ssid_len); | ||
784 | |||
785 | if (bss) { | ||
786 | cfg80211_unhold_bss(&bss->cbss); | ||
787 | ieee80211_rx_bss_put(local, bss); | ||
788 | } | ||
789 | |||
782 | if (self_disconnected) { | 790 | if (self_disconnected) { |
783 | if (deauth) | 791 | if (deauth) |
784 | ieee80211_send_deauth_disassoc(sdata, | 792 | ieee80211_send_deauth_disassoc(sdata, |
@@ -854,7 +862,7 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata) | |||
854 | int wep_privacy; | 862 | int wep_privacy; |
855 | int privacy_invoked; | 863 | int privacy_invoked; |
856 | 864 | ||
857 | if (!ifmgd || (ifmgd->flags & IEEE80211_STA_MIXED_CELL)) | 865 | if (!ifmgd || (ifmgd->flags & IEEE80211_STA_EXT_SME)) |
858 | return 0; | 866 | return 0; |
859 | 867 | ||
860 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, | 868 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, |
@@ -878,6 +886,7 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata) | |||
878 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) | 886 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) |
879 | { | 887 | { |
880 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 888 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
889 | struct ieee80211_local *local = sdata->local; | ||
881 | 890 | ||
882 | ifmgd->assoc_tries++; | 891 | ifmgd->assoc_tries++; |
883 | if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { | 892 | if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { |
@@ -889,6 +898,12 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) | |||
889 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | 898 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
890 | sdata->local->hw.conf.channel->center_freq, | 899 | sdata->local->hw.conf.channel->center_freq, |
891 | ifmgd->ssid, ifmgd->ssid_len); | 900 | ifmgd->ssid, ifmgd->ssid_len); |
901 | /* | ||
902 | * We might have a pending scan which had no chance to run yet | ||
903 | * due to state == IEEE80211_STA_MLME_ASSOCIATE. | ||
904 | * Hence, queue the STAs work again | ||
905 | */ | ||
906 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
892 | return; | 907 | return; |
893 | } | 908 | } |
894 | 909 | ||
@@ -907,13 +922,55 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) | |||
907 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); | 922 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); |
908 | } | 923 | } |
909 | 924 | ||
925 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | ||
926 | struct ieee80211_hdr *hdr) | ||
927 | { | ||
928 | /* | ||
929 | * We can postpone the mgd.timer whenever receiving unicast frames | ||
930 | * from AP because we know that the connection is working both ways | ||
931 | * at that time. But multicast frames (and hence also beacons) must | ||
932 | * be ignored here, because we need to trigger the timer during | ||
933 | * data idle periods for sending the periodical probe request to | ||
934 | * the AP. | ||
935 | */ | ||
936 | if (!is_multicast_ether_addr(hdr->addr1)) | ||
937 | mod_timer(&sdata->u.mgd.timer, | ||
938 | jiffies + IEEE80211_MONITORING_INTERVAL); | ||
939 | } | ||
940 | |||
941 | void ieee80211_beacon_loss_work(struct work_struct *work) | ||
942 | { | ||
943 | struct ieee80211_sub_if_data *sdata = | ||
944 | container_of(work, struct ieee80211_sub_if_data, | ||
945 | u.mgd.beacon_loss_work); | ||
946 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
947 | |||
948 | printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM " | ||
949 | "- sending probe request\n", sdata->dev->name, | ||
950 | sdata->u.mgd.bssid); | ||
951 | |||
952 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | ||
953 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | ||
954 | ifmgd->ssid_len, NULL, 0); | ||
955 | |||
956 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL); | ||
957 | } | ||
958 | |||
959 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | ||
960 | { | ||
961 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
962 | |||
963 | queue_work(sdata->local->hw.workqueue, | ||
964 | &sdata->u.mgd.beacon_loss_work); | ||
965 | } | ||
966 | EXPORT_SYMBOL(ieee80211_beacon_loss); | ||
910 | 967 | ||
911 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | 968 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) |
912 | { | 969 | { |
913 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 970 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
914 | struct ieee80211_local *local = sdata->local; | 971 | struct ieee80211_local *local = sdata->local; |
915 | struct sta_info *sta; | 972 | struct sta_info *sta; |
916 | int disassoc; | 973 | bool disassoc = false; |
917 | 974 | ||
918 | /* TODO: start monitoring current AP signal quality and number of | 975 | /* TODO: start monitoring current AP signal quality and number of |
919 | * missed beacons. Scan other channels every now and then and search | 976 | * missed beacons. Scan other channels every now and then and search |
@@ -928,36 +985,45 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | |||
928 | if (!sta) { | 985 | if (!sta) { |
929 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", | 986 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", |
930 | sdata->dev->name, ifmgd->bssid); | 987 | sdata->dev->name, ifmgd->bssid); |
931 | disassoc = 1; | 988 | disassoc = true; |
932 | } else { | 989 | goto unlock; |
933 | disassoc = 0; | ||
934 | if (time_after(jiffies, | ||
935 | sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { | ||
936 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { | ||
937 | printk(KERN_DEBUG "%s: No ProbeResp from " | ||
938 | "current AP %pM - assume out of " | ||
939 | "range\n", | ||
940 | sdata->dev->name, ifmgd->bssid); | ||
941 | disassoc = 1; | ||
942 | } else | ||
943 | ieee80211_send_probe_req(sdata, ifmgd->bssid, | ||
944 | ifmgd->ssid, | ||
945 | ifmgd->ssid_len, | ||
946 | NULL, 0); | ||
947 | ifmgd->flags ^= IEEE80211_STA_PROBEREQ_POLL; | ||
948 | } else { | ||
949 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
950 | if (time_after(jiffies, ifmgd->last_probe + | ||
951 | IEEE80211_PROBE_INTERVAL)) { | ||
952 | ifmgd->last_probe = jiffies; | ||
953 | ieee80211_send_probe_req(sdata, ifmgd->bssid, | ||
954 | ifmgd->ssid, | ||
955 | ifmgd->ssid_len, | ||
956 | NULL, 0); | ||
957 | } | ||
958 | } | ||
959 | } | 990 | } |
960 | 991 | ||
992 | if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && | ||
993 | time_after(jiffies, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { | ||
994 | printk(KERN_DEBUG "%s: no probe response from AP %pM " | ||
995 | "- disassociating\n", | ||
996 | sdata->dev->name, ifmgd->bssid); | ||
997 | disassoc = true; | ||
998 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
999 | goto unlock; | ||
1000 | } | ||
1001 | |||
1002 | /* | ||
1003 | * Beacon filtering is only enabled with power save and then the | ||
1004 | * stack should not check for beacon loss. | ||
1005 | */ | ||
1006 | if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) && | ||
1007 | (local->hw.conf.flags & IEEE80211_CONF_PS)) && | ||
1008 | time_after(jiffies, | ||
1009 | ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) { | ||
1010 | printk(KERN_DEBUG "%s: beacon loss from AP %pM " | ||
1011 | "- sending probe request\n", | ||
1012 | sdata->dev->name, ifmgd->bssid); | ||
1013 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | ||
1014 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | ||
1015 | ifmgd->ssid_len, NULL, 0); | ||
1016 | goto unlock; | ||
1017 | |||
1018 | } | ||
1019 | |||
1020 | if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) { | ||
1021 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | ||
1022 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | ||
1023 | ifmgd->ssid_len, NULL, 0); | ||
1024 | } | ||
1025 | |||
1026 | unlock: | ||
961 | rcu_read_unlock(); | 1027 | rcu_read_unlock(); |
962 | 1028 | ||
963 | if (disassoc) | 1029 | if (disassoc) |
@@ -975,7 +1041,11 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) | |||
975 | 1041 | ||
976 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); | 1042 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); |
977 | ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; | 1043 | ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; |
978 | ieee80211_associate(sdata); | 1044 | if (ifmgd->flags & IEEE80211_STA_EXT_SME) { |
1045 | /* Wait for SME to request association */ | ||
1046 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | ||
1047 | } else | ||
1048 | ieee80211_associate(sdata); | ||
979 | } | 1049 | } |
980 | 1050 | ||
981 | 1051 | ||
@@ -1061,12 +1131,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
1061 | switch (ifmgd->auth_alg) { | 1131 | switch (ifmgd->auth_alg) { |
1062 | case WLAN_AUTH_OPEN: | 1132 | case WLAN_AUTH_OPEN: |
1063 | case WLAN_AUTH_LEAP: | 1133 | case WLAN_AUTH_LEAP: |
1134 | case WLAN_AUTH_FT: | ||
1064 | ieee80211_auth_completed(sdata); | 1135 | ieee80211_auth_completed(sdata); |
1136 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); | ||
1065 | break; | 1137 | break; |
1066 | case WLAN_AUTH_SHARED_KEY: | 1138 | case WLAN_AUTH_SHARED_KEY: |
1067 | if (ifmgd->auth_transaction == 4) | 1139 | if (ifmgd->auth_transaction == 4) { |
1068 | ieee80211_auth_completed(sdata); | 1140 | ieee80211_auth_completed(sdata); |
1069 | else | 1141 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); |
1142 | } else | ||
1070 | ieee80211_auth_challenge(sdata, mgmt, len); | 1143 | ieee80211_auth_challenge(sdata, mgmt, len); |
1071 | break; | 1144 | break; |
1072 | } | 1145 | } |
@@ -1092,9 +1165,10 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1092 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", | 1165 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", |
1093 | sdata->dev->name, reason_code); | 1166 | sdata->dev->name, reason_code); |
1094 | 1167 | ||
1095 | if (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || | 1168 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && |
1096 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE || | 1169 | (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || |
1097 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1170 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE || |
1171 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) { | ||
1098 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 1172 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
1099 | mod_timer(&ifmgd->timer, jiffies + | 1173 | mod_timer(&ifmgd->timer, jiffies + |
1100 | IEEE80211_RETRY_AUTH_INTERVAL); | 1174 | IEEE80211_RETRY_AUTH_INTERVAL); |
@@ -1102,6 +1176,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1102 | 1176 | ||
1103 | ieee80211_set_disassoc(sdata, true, false, 0); | 1177 | ieee80211_set_disassoc(sdata, true, false, 0); |
1104 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; | 1178 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; |
1179 | cfg80211_send_rx_deauth(sdata->dev, (u8 *) mgmt, len); | ||
1105 | } | 1180 | } |
1106 | 1181 | ||
1107 | 1182 | ||
@@ -1124,13 +1199,15 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1124 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", | 1199 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", |
1125 | sdata->dev->name, reason_code); | 1200 | sdata->dev->name, reason_code); |
1126 | 1201 | ||
1127 | if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1202 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && |
1203 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { | ||
1128 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; | 1204 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; |
1129 | mod_timer(&ifmgd->timer, jiffies + | 1205 | mod_timer(&ifmgd->timer, jiffies + |
1130 | IEEE80211_RETRY_AUTH_INTERVAL); | 1206 | IEEE80211_RETRY_AUTH_INTERVAL); |
1131 | } | 1207 | } |
1132 | 1208 | ||
1133 | ieee80211_set_disassoc(sdata, false, false, reason_code); | 1209 | ieee80211_set_disassoc(sdata, false, false, reason_code); |
1210 | cfg80211_send_rx_disassoc(sdata->dev, (u8 *) mgmt, len); | ||
1134 | } | 1211 | } |
1135 | 1212 | ||
1136 | 1213 | ||
@@ -1346,7 +1423,14 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1346 | bss_conf->assoc_capability = capab_info; | 1423 | bss_conf->assoc_capability = capab_info; |
1347 | ieee80211_set_associated(sdata, changed); | 1424 | ieee80211_set_associated(sdata, changed); |
1348 | 1425 | ||
1426 | /* | ||
1427 | * initialise the time of last beacon to be the association time, | ||
1428 | * otherwise beacon loss check will trigger immediately | ||
1429 | */ | ||
1430 | ifmgd->last_beacon = jiffies; | ||
1431 | |||
1349 | ieee80211_associated(sdata); | 1432 | ieee80211_associated(sdata); |
1433 | cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len); | ||
1350 | } | 1434 | } |
1351 | 1435 | ||
1352 | 1436 | ||
@@ -1393,9 +1477,12 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1393 | size_t len, | 1477 | size_t len, |
1394 | struct ieee80211_rx_status *rx_status) | 1478 | struct ieee80211_rx_status *rx_status) |
1395 | { | 1479 | { |
1480 | struct ieee80211_if_managed *ifmgd; | ||
1396 | size_t baselen; | 1481 | size_t baselen; |
1397 | struct ieee802_11_elems elems; | 1482 | struct ieee802_11_elems elems; |
1398 | 1483 | ||
1484 | ifmgd = &sdata->u.mgd; | ||
1485 | |||
1399 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | 1486 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) |
1400 | return; /* ignore ProbeResp to foreign address */ | 1487 | return; /* ignore ProbeResp to foreign address */ |
1401 | 1488 | ||
@@ -1410,11 +1497,14 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1410 | 1497 | ||
1411 | /* direct probe may be part of the association flow */ | 1498 | /* direct probe may be part of the association flow */ |
1412 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, | 1499 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, |
1413 | &sdata->u.mgd.request)) { | 1500 | &ifmgd->request)) { |
1414 | printk(KERN_DEBUG "%s direct probe responded\n", | 1501 | printk(KERN_DEBUG "%s direct probe responded\n", |
1415 | sdata->dev->name); | 1502 | sdata->dev->name); |
1416 | ieee80211_authenticate(sdata); | 1503 | ieee80211_authenticate(sdata); |
1417 | } | 1504 | } |
1505 | |||
1506 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) | ||
1507 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
1418 | } | 1508 | } |
1419 | 1509 | ||
1420 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 1510 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
@@ -1636,6 +1726,8 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) | |||
1636 | ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY; | 1726 | ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY; |
1637 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) | 1727 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) |
1638 | ifmgd->auth_alg = WLAN_AUTH_LEAP; | 1728 | ifmgd->auth_alg = WLAN_AUTH_LEAP; |
1729 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_FT) | ||
1730 | ifmgd->auth_alg = WLAN_AUTH_FT; | ||
1639 | else | 1731 | else |
1640 | ifmgd->auth_alg = WLAN_AUTH_OPEN; | 1732 | ifmgd->auth_alg = WLAN_AUTH_OPEN; |
1641 | ifmgd->auth_transaction = -1; | 1733 | ifmgd->auth_transaction = -1; |
@@ -1659,7 +1751,8 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) | |||
1659 | u16 capa_val = WLAN_CAPABILITY_ESS; | 1751 | u16 capa_val = WLAN_CAPABILITY_ESS; |
1660 | struct ieee80211_channel *chan = local->oper_channel; | 1752 | struct ieee80211_channel *chan = local->oper_channel; |
1661 | 1753 | ||
1662 | if (ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL | | 1754 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && |
1755 | ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL | | ||
1663 | IEEE80211_STA_AUTO_BSSID_SEL | | 1756 | IEEE80211_STA_AUTO_BSSID_SEL | |
1664 | IEEE80211_STA_AUTO_CHANNEL_SEL)) { | 1757 | IEEE80211_STA_AUTO_CHANNEL_SEL)) { |
1665 | capa_mask |= WLAN_CAPABILITY_PRIVACY; | 1758 | capa_mask |= WLAN_CAPABILITY_PRIVACY; |
@@ -1822,6 +1915,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1822 | ifmgd = &sdata->u.mgd; | 1915 | ifmgd = &sdata->u.mgd; |
1823 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); | 1916 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
1824 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 1917 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
1918 | INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); | ||
1825 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 1919 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
1826 | (unsigned long) sdata); | 1920 | (unsigned long) sdata); |
1827 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, | 1921 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |
@@ -1834,7 +1928,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1834 | ifmgd->flags |= IEEE80211_STA_CREATE_IBSS | | 1928 | ifmgd->flags |= IEEE80211_STA_CREATE_IBSS | |
1835 | IEEE80211_STA_AUTO_BSSID_SEL | | 1929 | IEEE80211_STA_AUTO_BSSID_SEL | |
1836 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 1930 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
1837 | if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) | 1931 | if (sdata->local->hw.queues >= 4) |
1838 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; | 1932 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; |
1839 | } | 1933 | } |
1840 | 1934 | ||
@@ -1856,7 +1950,11 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata) | |||
1856 | ieee80211_set_disassoc(sdata, true, true, | 1950 | ieee80211_set_disassoc(sdata, true, true, |
1857 | WLAN_REASON_DEAUTH_LEAVING); | 1951 | WLAN_REASON_DEAUTH_LEAVING); |
1858 | 1952 | ||
1859 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); | 1953 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) || |
1954 | ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) | ||
1955 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); | ||
1956 | else if (ifmgd->flags & IEEE80211_STA_EXT_SME) | ||
1957 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); | ||
1860 | queue_work(local->hw.workqueue, &ifmgd->work); | 1958 | queue_work(local->hw.workqueue, &ifmgd->work); |
1861 | } | 1959 | } |
1862 | } | 1960 | } |
@@ -1865,8 +1963,6 @@ int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata) | |||
1865 | { | 1963 | { |
1866 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1964 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1867 | 1965 | ||
1868 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
1869 | |||
1870 | if (ifmgd->ssid_len) | 1966 | if (ifmgd->ssid_len) |
1871 | ifmgd->flags |= IEEE80211_STA_SSID_SET; | 1967 | ifmgd->flags |= IEEE80211_STA_SSID_SET; |
1872 | else | 1968 | else |
@@ -1885,6 +1981,10 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size | |||
1885 | ifmgd = &sdata->u.mgd; | 1981 | ifmgd = &sdata->u.mgd; |
1886 | 1982 | ||
1887 | if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) { | 1983 | if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) { |
1984 | /* | ||
1985 | * Do not use reassociation if SSID is changed (different ESS). | ||
1986 | */ | ||
1987 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
1888 | memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid)); | 1988 | memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid)); |
1889 | memcpy(ifmgd->ssid, ssid, len); | 1989 | memcpy(ifmgd->ssid, ssid, len); |
1890 | ifmgd->ssid_len = len; | 1990 | ifmgd->ssid_len = len; |
@@ -1923,7 +2023,8 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | |||
1923 | return ieee80211_sta_commit(sdata); | 2023 | return ieee80211_sta_commit(sdata); |
1924 | } | 2024 | } |
1925 | 2025 | ||
1926 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) | 2026 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, |
2027 | const char *ie, size_t len) | ||
1927 | { | 2028 | { |
1928 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2029 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1929 | 2030 | ||