aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 00:04:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 00:04:44 -0400
commitf8965467f366fd18f01feafb5db10512d7b4422c (patch)
tree3706a9cd779859271ca61b85c63a1bc3f82d626e /net/mac80211/mlme.c
parenta26272e5200765691e67d6780e52b32498fdb659 (diff)
parent2ec8c6bb5d8f3a62a79f463525054bae1e3d4487 (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: (1674 commits) qlcnic: adding co maintainer ixgbe: add support for active DA cables ixgbe: dcb, do not tag tc_prio_control frames ixgbe: fix ixgbe_tx_is_paused logic ixgbe: always enable vlan strip/insert when DCB is enabled ixgbe: remove some redundant code in setting FCoE FIP filter ixgbe: fix wrong offset to fc_frame_header in ixgbe_fcoe_ddp ixgbe: fix header len when unsplit packet overflows to data buffer ipv6: Never schedule DAD timer on dead address ipv6: Use POSTDAD state ipv6: Use state_lock to protect ifa state ipv6: Replace inet6_ifaddr->dead with state cxgb4: notify upper drivers if the device is already up when they load cxgb4: keep interrupts available when the ports are brought down cxgb4: fix initial addition of MAC address cnic: Return SPQ credit to bnx2x after ring setup and shutdown. cnic: Convert cnic_local_flags to atomic ops. can: Fix SJA1000 command register writes on SMP systems bridge: fix build for CONFIG_SYSFS disabled ARCNET: Limit com20020 PCI ID matches for SOHARD cards ... Fix up various conflicts with pcmcia tree drivers/net/ {pcmcia/3c589_cs.c, wireless/orinoco/orinoco_cs.c and wireless/orinoco/spectrum_cs.c} and feature removal (Documentation/feature-removal-schedule.txt). Also fix a non-content conflict due to pm_qos_requirement getting renamed in the PM tree (now pm_qos_request) in net/mac80211/scan.c
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c310
1 files changed, 261 insertions, 49 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 88f95e7bab49..0839c4e8fd2e 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -47,6 +47,13 @@
47 */ 47 */
48#define IEEE80211_PROBE_WAIT (HZ / 2) 48#define IEEE80211_PROBE_WAIT (HZ / 2)
49 49
50/*
51 * Weight given to the latest Beacon frame when calculating average signal
52 * strength for Beacon frames received in the current BSS. This must be
53 * between 1 and 15.
54 */
55#define IEEE80211_SIGNAL_AVE_WEIGHT 3
56
50#define TMR_RUNNING_TIMER 0 57#define TMR_RUNNING_TIMER 0
51#define TMR_RUNNING_CHANSW 1 58#define TMR_RUNNING_CHANSW 1
52 59
@@ -130,11 +137,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
130 struct sta_info *sta; 137 struct sta_info *sta;
131 u32 changed = 0; 138 u32 changed = 0;
132 u16 ht_opmode; 139 u16 ht_opmode;
133 bool enable_ht = true, ht_changed; 140 bool enable_ht = true;
141 enum nl80211_channel_type prev_chantype;
134 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; 142 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
135 143
136 sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 144 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
137 145
146 prev_chantype = sdata->vif.bss_conf.channel_type;
147
138 /* HT is not supported */ 148 /* HT is not supported */
139 if (!sband->ht_cap.ht_supported) 149 if (!sband->ht_cap.ht_supported)
140 enable_ht = false; 150 enable_ht = false;
@@ -165,38 +175,37 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
165 } 175 }
166 } 176 }
167 177
168 ht_changed = conf_is_ht(&local->hw.conf) != enable_ht ||
169 channel_type != local->hw.conf.channel_type;
170
171 if (local->tmp_channel) 178 if (local->tmp_channel)
172 local->tmp_channel_type = channel_type; 179 local->tmp_channel_type = channel_type;
173 local->oper_channel_type = channel_type;
174 180
175 if (ht_changed) { 181 if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
176 /* channel_type change automatically detected */ 182 /* can only fail due to HT40+/- mismatch */
177 ieee80211_hw_config(local, 0); 183 channel_type = NL80211_CHAN_HT20;
184 WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type));
185 }
186
187 /* channel_type change automatically detected */
188 ieee80211_hw_config(local, 0);
178 189
190 if (prev_chantype != channel_type) {
179 rcu_read_lock(); 191 rcu_read_lock();
180 sta = sta_info_get(sdata, bssid); 192 sta = sta_info_get(sdata, bssid);
181 if (sta) 193 if (sta)
182 rate_control_rate_update(local, sband, sta, 194 rate_control_rate_update(local, sband, sta,
183 IEEE80211_RC_HT_CHANGED, 195 IEEE80211_RC_HT_CHANGED,
184 local->oper_channel_type); 196 channel_type);
185 rcu_read_unlock(); 197 rcu_read_unlock();
186 } 198 }
187
188 /* disable HT */
189 if (!enable_ht)
190 return 0;
191 199
192 ht_opmode = le16_to_cpu(hti->operation_mode); 200 ht_opmode = le16_to_cpu(hti->operation_mode);
193 201
194 /* if bss configuration changed store the new one */ 202 /* if bss configuration changed store the new one */
195 if (!sdata->ht_opmode_valid || 203 if (sdata->ht_opmode_valid != enable_ht ||
196 sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { 204 sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
205 prev_chantype != channel_type) {
197 changed |= BSS_CHANGED_HT; 206 changed |= BSS_CHANGED_HT;
198 sdata->vif.bss_conf.ht_operation_mode = ht_opmode; 207 sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
199 sdata->ht_opmode_valid = true; 208 sdata->ht_opmode_valid = enable_ht;
200 } 209 }
201 210
202 return changed; 211 return changed;
@@ -206,7 +215,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
206 215
207static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, 216static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
208 const u8 *bssid, u16 stype, u16 reason, 217 const u8 *bssid, u16 stype, u16 reason,
209 void *cookie) 218 void *cookie, bool send_frame)
210{ 219{
211 struct ieee80211_local *local = sdata->local; 220 struct ieee80211_local *local = sdata->local;
212 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 221 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -243,7 +252,11 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
243 cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); 252 cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
244 if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) 253 if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
245 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 254 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
246 ieee80211_tx_skb(sdata, skb); 255
256 if (send_frame)
257 ieee80211_tx_skb(sdata, skb);
258 else
259 kfree_skb(skb);
247} 260}
248 261
249void ieee80211_send_pspoll(struct ieee80211_local *local, 262void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -329,7 +342,11 @@ static void ieee80211_chswitch_work(struct work_struct *work)
329 goto out; 342 goto out;
330 343
331 sdata->local->oper_channel = sdata->local->csa_channel; 344 sdata->local->oper_channel = sdata->local->csa_channel;
332 ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); 345 if (!sdata->local->ops->channel_switch) {
346 /* call "hw_config" only if doing sw channel switch */
347 ieee80211_hw_config(sdata->local,
348 IEEE80211_CONF_CHANGE_CHANNEL);
349 }
333 350
334 /* XXX: shouldn't really modify cfg80211-owned data! */ 351 /* XXX: shouldn't really modify cfg80211-owned data! */
335 ifmgd->associated->channel = sdata->local->oper_channel; 352 ifmgd->associated->channel = sdata->local->oper_channel;
@@ -341,6 +358,29 @@ static void ieee80211_chswitch_work(struct work_struct *work)
341 mutex_unlock(&ifmgd->mtx); 358 mutex_unlock(&ifmgd->mtx);
342} 359}
343 360
361void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
362{
363 struct ieee80211_sub_if_data *sdata;
364 struct ieee80211_if_managed *ifmgd;
365
366 sdata = vif_to_sdata(vif);
367 ifmgd = &sdata->u.mgd;
368
369 trace_api_chswitch_done(sdata, success);
370 if (!success) {
371 /*
372 * If the channel switch was not successful, stay
373 * around on the old channel. We currently lack
374 * good handling of this situation, possibly we
375 * should just drop the association.
376 */
377 sdata->local->csa_channel = sdata->local->oper_channel;
378 }
379
380 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
381}
382EXPORT_SYMBOL(ieee80211_chswitch_done);
383
344static void ieee80211_chswitch_timer(unsigned long data) 384static void ieee80211_chswitch_timer(unsigned long data)
345{ 385{
346 struct ieee80211_sub_if_data *sdata = 386 struct ieee80211_sub_if_data *sdata =
@@ -357,7 +397,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
357 397
358void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, 398void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
359 struct ieee80211_channel_sw_ie *sw_elem, 399 struct ieee80211_channel_sw_ie *sw_elem,
360 struct ieee80211_bss *bss) 400 struct ieee80211_bss *bss,
401 u64 timestamp)
361{ 402{
362 struct cfg80211_bss *cbss = 403 struct cfg80211_bss *cbss =
363 container_of((void *)bss, struct cfg80211_bss, priv); 404 container_of((void *)bss, struct cfg80211_bss, priv);
@@ -385,10 +426,29 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
385 426
386 sdata->local->csa_channel = new_ch; 427 sdata->local->csa_channel = new_ch;
387 428
429 if (sdata->local->ops->channel_switch) {
430 /* use driver's channel switch callback */
431 struct ieee80211_channel_switch ch_switch;
432 memset(&ch_switch, 0, sizeof(ch_switch));
433 ch_switch.timestamp = timestamp;
434 if (sw_elem->mode) {
435 ch_switch.block_tx = true;
436 ieee80211_stop_queues_by_reason(&sdata->local->hw,
437 IEEE80211_QUEUE_STOP_REASON_CSA);
438 }
439 ch_switch.channel = new_ch;
440 ch_switch.count = sw_elem->count;
441 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
442 drv_channel_switch(sdata->local, &ch_switch);
443 return;
444 }
445
446 /* channel switch handled in software */
388 if (sw_elem->count <= 1) { 447 if (sw_elem->count <= 1) {
389 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); 448 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
390 } else { 449 } else {
391 ieee80211_stop_queues_by_reason(&sdata->local->hw, 450 if (sw_elem->mode)
451 ieee80211_stop_queues_by_reason(&sdata->local->hw,
392 IEEE80211_QUEUE_STOP_REASON_CSA); 452 IEEE80211_QUEUE_STOP_REASON_CSA);
393 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; 453 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
394 mod_timer(&ifmgd->chswitch_timer, 454 mod_timer(&ifmgd->chswitch_timer,
@@ -467,6 +527,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
467{ 527{
468 struct ieee80211_sub_if_data *sdata, *found = NULL; 528 struct ieee80211_sub_if_data *sdata, *found = NULL;
469 int count = 0; 529 int count = 0;
530 int timeout;
470 531
471 if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) { 532 if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) {
472 local->ps_sdata = NULL; 533 local->ps_sdata = NULL;
@@ -500,6 +561,26 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
500 beaconint_us = ieee80211_tu_to_usec( 561 beaconint_us = ieee80211_tu_to_usec(
501 found->vif.bss_conf.beacon_int); 562 found->vif.bss_conf.beacon_int);
502 563
564 timeout = local->hw.conf.dynamic_ps_forced_timeout;
565 if (timeout < 0) {
566 /*
567 * The 2 second value is there for compatibility until
568 * the PM_QOS_NETWORK_LATENCY is configured with real
569 * values.
570 */
571 if (latency == 2000000000)
572 timeout = 100;
573 else if (latency <= 50000)
574 timeout = 300;
575 else if (latency <= 100000)
576 timeout = 100;
577 else if (latency <= 500000)
578 timeout = 50;
579 else
580 timeout = 0;
581 }
582 local->hw.conf.dynamic_ps_timeout = timeout;
583
503 if (beaconint_us > latency) { 584 if (beaconint_us > latency) {
504 local->ps_sdata = NULL; 585 local->ps_sdata = NULL;
505 } else { 586 } else {
@@ -592,6 +673,9 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
592 int count; 673 int count;
593 u8 *pos, uapsd_queues = 0; 674 u8 *pos, uapsd_queues = 0;
594 675
676 if (!local->ops->conf_tx)
677 return;
678
595 if (local->hw.queues < 4) 679 if (local->hw.queues < 4)
596 return; 680 return;
597 681
@@ -666,11 +750,15 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
666 params.aifs, params.cw_min, params.cw_max, params.txop, 750 params.aifs, params.cw_min, params.cw_max, params.txop,
667 params.uapsd); 751 params.uapsd);
668#endif 752#endif
669 if (drv_conf_tx(local, queue, &params) && local->ops->conf_tx) 753 if (drv_conf_tx(local, queue, &params))
670 printk(KERN_DEBUG "%s: failed to set TX queue " 754 printk(KERN_DEBUG "%s: failed to set TX queue "
671 "parameters for queue %d\n", 755 "parameters for queue %d\n",
672 wiphy_name(local->hw.wiphy), queue); 756 wiphy_name(local->hw.wiphy), queue);
673 } 757 }
758
759 /* enable WMM or activate new settings */
760 local->hw.conf.flags |= IEEE80211_CONF_QOS;
761 drv_config(local, IEEE80211_CONF_CHANGE_QOS);
674} 762}
675 763
676static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, 764static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
@@ -731,6 +819,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
731 sdata->u.mgd.associated = cbss; 819 sdata->u.mgd.associated = cbss;
732 memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); 820 memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
733 821
822 sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
823
734 /* just to be sure */ 824 /* just to be sure */
735 sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | 825 sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
736 IEEE80211_STA_BEACON_POLL); 826 IEEE80211_STA_BEACON_POLL);
@@ -756,6 +846,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
756 /* And the BSSID changed - we're associated now */ 846 /* And the BSSID changed - we're associated now */
757 bss_info_changed |= BSS_CHANGED_BSSID; 847 bss_info_changed |= BSS_CHANGED_BSSID;
758 848
849 /* Tell the driver to monitor connection quality (if supported) */
850 if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) &&
851 sdata->vif.bss_conf.cqm_rssi_thold)
852 bss_info_changed |= BSS_CHANGED_CQM;
853
759 ieee80211_bss_info_change_notify(sdata, bss_info_changed); 854 ieee80211_bss_info_change_notify(sdata, bss_info_changed);
760 855
761 mutex_lock(&local->iflist_mtx); 856 mutex_lock(&local->iflist_mtx);
@@ -767,7 +862,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
767 netif_carrier_on(sdata->dev); 862 netif_carrier_on(sdata->dev);
768} 863}
769 864
770static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) 865static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
866 bool remove_sta)
771{ 867{
772 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 868 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
773 struct ieee80211_local *local = sdata->local; 869 struct ieee80211_local *local = sdata->local;
@@ -819,7 +915,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
819 ieee80211_set_wmm_default(sdata); 915 ieee80211_set_wmm_default(sdata);
820 916
821 /* channel(_type) changes are handled by ieee80211_hw_config */ 917 /* channel(_type) changes are handled by ieee80211_hw_config */
822 local->oper_channel_type = NL80211_CHAN_NO_HT; 918 WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
823 919
824 /* on the next assoc, re-program HT parameters */ 920 /* on the next assoc, re-program HT parameters */
825 sdata->ht_opmode_valid = false; 921 sdata->ht_opmode_valid = false;
@@ -836,11 +932,12 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
836 932
837 ieee80211_hw_config(local, config_changed); 933 ieee80211_hw_config(local, config_changed);
838 934
839 /* And the BSSID changed -- not very interesting here */ 935 /* The BSSID (not really interesting) and HT changed */
840 changed |= BSS_CHANGED_BSSID; 936 changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
841 ieee80211_bss_info_change_notify(sdata, changed); 937 ieee80211_bss_info_change_notify(sdata, changed);
842 938
843 sta_info_destroy_addr(sdata, bssid); 939 if (remove_sta)
940 sta_info_destroy_addr(sdata, bssid);
844} 941}
845 942
846void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, 943void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -857,6 +954,9 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
857 if (is_multicast_ether_addr(hdr->addr1)) 954 if (is_multicast_ether_addr(hdr->addr1))
858 return; 955 return;
859 956
957 if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
958 return;
959
860 mod_timer(&sdata->u.mgd.conn_mon_timer, 960 mod_timer(&sdata->u.mgd.conn_mon_timer,
861 round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); 961 round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
862} 962}
@@ -934,23 +1034,72 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
934 mutex_unlock(&ifmgd->mtx); 1034 mutex_unlock(&ifmgd->mtx);
935} 1035}
936 1036
937void ieee80211_beacon_loss_work(struct work_struct *work) 1037static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
1038{
1039 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1040 struct ieee80211_local *local = sdata->local;
1041 u8 bssid[ETH_ALEN];
1042
1043 mutex_lock(&ifmgd->mtx);
1044 if (!ifmgd->associated) {
1045 mutex_unlock(&ifmgd->mtx);
1046 return;
1047 }
1048
1049 memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
1050
1051 printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid);
1052
1053 ieee80211_set_disassoc(sdata, true);
1054 ieee80211_recalc_idle(local);
1055 mutex_unlock(&ifmgd->mtx);
1056 /*
1057 * must be outside lock due to cfg80211,
1058 * but that's not a problem.
1059 */
1060 ieee80211_send_deauth_disassoc(sdata, bssid,
1061 IEEE80211_STYPE_DEAUTH,
1062 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
1063 NULL, true);
1064}
1065
1066void ieee80211_beacon_connection_loss_work(struct work_struct *work)
938{ 1067{
939 struct ieee80211_sub_if_data *sdata = 1068 struct ieee80211_sub_if_data *sdata =
940 container_of(work, struct ieee80211_sub_if_data, 1069 container_of(work, struct ieee80211_sub_if_data,
941 u.mgd.beacon_loss_work); 1070 u.mgd.beacon_connection_loss_work);
942 1071
943 ieee80211_mgd_probe_ap(sdata, true); 1072 if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
1073 __ieee80211_connection_loss(sdata);
1074 else
1075 ieee80211_mgd_probe_ap(sdata, true);
944} 1076}
945 1077
946void ieee80211_beacon_loss(struct ieee80211_vif *vif) 1078void ieee80211_beacon_loss(struct ieee80211_vif *vif)
947{ 1079{
948 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 1080 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
1081 struct ieee80211_hw *hw = &sdata->local->hw;
949 1082
950 ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); 1083 trace_api_beacon_loss(sdata);
1084
1085 WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR);
1086 ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
951} 1087}
952EXPORT_SYMBOL(ieee80211_beacon_loss); 1088EXPORT_SYMBOL(ieee80211_beacon_loss);
953 1089
1090void ieee80211_connection_loss(struct ieee80211_vif *vif)
1091{
1092 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
1093 struct ieee80211_hw *hw = &sdata->local->hw;
1094
1095 trace_api_connection_loss(sdata);
1096
1097 WARN_ON(!(hw->flags & IEEE80211_HW_CONNECTION_MONITOR));
1098 ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
1099}
1100EXPORT_SYMBOL(ieee80211_connection_loss);
1101
1102
954static enum rx_mgmt_action __must_check 1103static enum rx_mgmt_action __must_check
955ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, 1104ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
956 struct ieee80211_mgmt *mgmt, size_t len) 1105 struct ieee80211_mgmt *mgmt, size_t len)
@@ -971,7 +1120,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
971 printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", 1120 printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
972 sdata->name, bssid, reason_code); 1121 sdata->name, bssid, reason_code);
973 1122
974 ieee80211_set_disassoc(sdata); 1123 ieee80211_set_disassoc(sdata, true);
975 ieee80211_recalc_idle(sdata->local); 1124 ieee80211_recalc_idle(sdata->local);
976 1125
977 return RX_MGMT_CFG80211_DEAUTH; 1126 return RX_MGMT_CFG80211_DEAUTH;
@@ -1001,7 +1150,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
1001 printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", 1150 printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
1002 sdata->name, mgmt->sa, reason_code); 1151 sdata->name, mgmt->sa, reason_code);
1003 1152
1004 ieee80211_set_disassoc(sdata); 1153 ieee80211_set_disassoc(sdata, true);
1005 ieee80211_recalc_idle(sdata->local); 1154 ieee80211_recalc_idle(sdata->local);
1006 return RX_MGMT_CFG80211_DISASSOC; 1155 return RX_MGMT_CFG80211_DISASSOC;
1007} 1156}
@@ -1215,7 +1364,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
1215 ETH_ALEN) == 0)) { 1364 ETH_ALEN) == 0)) {
1216 struct ieee80211_channel_sw_ie *sw_elem = 1365 struct ieee80211_channel_sw_ie *sw_elem =
1217 (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; 1366 (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
1218 ieee80211_sta_process_chanswitch(sdata, sw_elem, bss); 1367 ieee80211_sta_process_chanswitch(sdata, sw_elem,
1368 bss, rx_status->mactime);
1219 } 1369 }
1220} 1370}
1221 1371
@@ -1254,12 +1404,17 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
1254 mutex_lock(&sdata->local->iflist_mtx); 1404 mutex_lock(&sdata->local->iflist_mtx);
1255 ieee80211_recalc_ps(sdata->local, -1); 1405 ieee80211_recalc_ps(sdata->local, -1);
1256 mutex_unlock(&sdata->local->iflist_mtx); 1406 mutex_unlock(&sdata->local->iflist_mtx);
1407
1408 if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
1409 return;
1410
1257 /* 1411 /*
1258 * We've received a probe response, but are not sure whether 1412 * We've received a probe response, but are not sure whether
1259 * we have or will be receiving any beacons or data, so let's 1413 * we have or will be receiving any beacons or data, so let's
1260 * schedule the timers again, just in case. 1414 * schedule the timers again, just in case.
1261 */ 1415 */
1262 mod_beacon_timer(sdata); 1416 mod_beacon_timer(sdata);
1417
1263 mod_timer(&ifmgd->conn_mon_timer, 1418 mod_timer(&ifmgd->conn_mon_timer,
1264 round_jiffies_up(jiffies + 1419 round_jiffies_up(jiffies +
1265 IEEE80211_CONNECTION_IDLE_TIME)); 1420 IEEE80211_CONNECTION_IDLE_TIME));
@@ -1293,6 +1448,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
1293 struct ieee80211_rx_status *rx_status) 1448 struct ieee80211_rx_status *rx_status)
1294{ 1449{
1295 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1450 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1451 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
1296 size_t baselen; 1452 size_t baselen;
1297 struct ieee802_11_elems elems; 1453 struct ieee802_11_elems elems;
1298 struct ieee80211_local *local = sdata->local; 1454 struct ieee80211_local *local = sdata->local;
@@ -1328,6 +1484,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
1328 if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0) 1484 if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)
1329 return; 1485 return;
1330 1486
1487 /* Track average RSSI from the Beacon frames of the current AP */
1488 ifmgd->last_beacon_signal = rx_status->signal;
1489 if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
1490 ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
1491 ifmgd->ave_beacon_signal = rx_status->signal;
1492 ifmgd->last_cqm_event_signal = 0;
1493 } else {
1494 ifmgd->ave_beacon_signal =
1495 (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
1496 (16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
1497 ifmgd->ave_beacon_signal) / 16;
1498 }
1499 if (bss_conf->cqm_rssi_thold &&
1500 !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
1501 int sig = ifmgd->ave_beacon_signal / 16;
1502 int last_event = ifmgd->last_cqm_event_signal;
1503 int thold = bss_conf->cqm_rssi_thold;
1504 int hyst = bss_conf->cqm_rssi_hyst;
1505 if (sig < thold &&
1506 (last_event == 0 || sig < last_event - hyst)) {
1507 ifmgd->last_cqm_event_signal = sig;
1508 ieee80211_cqm_rssi_notify(
1509 &sdata->vif,
1510 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
1511 GFP_KERNEL);
1512 } else if (sig > thold &&
1513 (last_event == 0 || sig > last_event + hyst)) {
1514 ifmgd->last_cqm_event_signal = sig;
1515 ieee80211_cqm_rssi_notify(
1516 &sdata->vif,
1517 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
1518 GFP_KERNEL);
1519 }
1520 }
1521
1331 if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { 1522 if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
1332#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 1523#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
1333 if (net_ratelimit()) { 1524 if (net_ratelimit()) {
@@ -1506,7 +1697,8 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
1506 1697
1507 ieee80211_sta_process_chanswitch(sdata, 1698 ieee80211_sta_process_chanswitch(sdata,
1508 &mgmt->u.action.u.chan_switch.sw_elem, 1699 &mgmt->u.action.u.chan_switch.sw_elem,
1509 (void *)ifmgd->associated->priv); 1700 (void *)ifmgd->associated->priv,
1701 rx_status->mactime);
1510 break; 1702 break;
1511 } 1703 }
1512 mutex_unlock(&ifmgd->mtx); 1704 mutex_unlock(&ifmgd->mtx);
@@ -1613,7 +1805,7 @@ static void ieee80211_sta_work(struct work_struct *work)
1613 printk(KERN_DEBUG "No probe response from AP %pM" 1805 printk(KERN_DEBUG "No probe response from AP %pM"
1614 " after %dms, disconnecting.\n", 1806 " after %dms, disconnecting.\n",
1615 bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); 1807 bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
1616 ieee80211_set_disassoc(sdata); 1808 ieee80211_set_disassoc(sdata, true);
1617 ieee80211_recalc_idle(local); 1809 ieee80211_recalc_idle(local);
1618 mutex_unlock(&ifmgd->mtx); 1810 mutex_unlock(&ifmgd->mtx);
1619 /* 1811 /*
@@ -1623,7 +1815,7 @@ static void ieee80211_sta_work(struct work_struct *work)
1623 ieee80211_send_deauth_disassoc(sdata, bssid, 1815 ieee80211_send_deauth_disassoc(sdata, bssid,
1624 IEEE80211_STYPE_DEAUTH, 1816 IEEE80211_STYPE_DEAUTH,
1625 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, 1817 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
1626 NULL); 1818 NULL, true);
1627 mutex_lock(&ifmgd->mtx); 1819 mutex_lock(&ifmgd->mtx);
1628 } 1820 }
1629 } 1821 }
@@ -1640,7 +1832,8 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
1640 if (local->quiescing) 1832 if (local->quiescing)
1641 return; 1833 return;
1642 1834
1643 ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); 1835 ieee80211_queue_work(&sdata->local->hw,
1836 &sdata->u.mgd.beacon_connection_loss_work);
1644} 1837}
1645 1838
1646static void ieee80211_sta_conn_mon_timer(unsigned long data) 1839static void ieee80211_sta_conn_mon_timer(unsigned long data)
@@ -1692,7 +1885,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
1692 */ 1885 */
1693 1886
1694 cancel_work_sync(&ifmgd->work); 1887 cancel_work_sync(&ifmgd->work);
1695 cancel_work_sync(&ifmgd->beacon_loss_work); 1888 cancel_work_sync(&ifmgd->beacon_connection_loss_work);
1696 if (del_timer_sync(&ifmgd->timer)) 1889 if (del_timer_sync(&ifmgd->timer))
1697 set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); 1890 set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
1698 1891
@@ -1726,7 +1919,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
1726 INIT_WORK(&ifmgd->work, ieee80211_sta_work); 1919 INIT_WORK(&ifmgd->work, ieee80211_sta_work);
1727 INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work); 1920 INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
1728 INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); 1921 INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
1729 INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); 1922 INIT_WORK(&ifmgd->beacon_connection_loss_work,
1923 ieee80211_beacon_connection_loss_work);
1730 setup_timer(&ifmgd->timer, ieee80211_sta_timer, 1924 setup_timer(&ifmgd->timer, ieee80211_sta_timer,
1731 (unsigned long) sdata); 1925 (unsigned long) sdata);
1732 setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, 1926 setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
@@ -1805,6 +1999,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
1805 struct ieee80211_work *wk; 1999 struct ieee80211_work *wk;
1806 u16 auth_alg; 2000 u16 auth_alg;
1807 2001
2002 if (req->local_state_change)
2003 return 0; /* no need to update mac80211 state */
2004
1808 switch (req->auth_type) { 2005 switch (req->auth_type) {
1809 case NL80211_AUTHTYPE_OPEN_SYSTEM: 2006 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1810 auth_alg = WLAN_AUTH_OPEN; 2007 auth_alg = WLAN_AUTH_OPEN;
@@ -1913,7 +2110,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
1913 } 2110 }
1914 2111
1915 /* Trying to reassociate - clear previous association state */ 2112 /* Trying to reassociate - clear previous association state */
1916 ieee80211_set_disassoc(sdata); 2113 ieee80211_set_disassoc(sdata, true);
1917 } 2114 }
1918 mutex_unlock(&ifmgd->mtx); 2115 mutex_unlock(&ifmgd->mtx);
1919 2116
@@ -2017,7 +2214,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
2017 2214
2018 if (ifmgd->associated == req->bss) { 2215 if (ifmgd->associated == req->bss) {
2019 bssid = req->bss->bssid; 2216 bssid = req->bss->bssid;
2020 ieee80211_set_disassoc(sdata); 2217 ieee80211_set_disassoc(sdata, true);
2021 mutex_unlock(&ifmgd->mtx); 2218 mutex_unlock(&ifmgd->mtx);
2022 } else { 2219 } else {
2023 bool not_auth_yet = false; 2220 bool not_auth_yet = false;
@@ -2061,9 +2258,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
2061 printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", 2258 printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
2062 sdata->name, bssid, req->reason_code); 2259 sdata->name, bssid, req->reason_code);
2063 2260
2064 ieee80211_send_deauth_disassoc(sdata, bssid, 2261 ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH,
2065 IEEE80211_STYPE_DEAUTH, req->reason_code, 2262 req->reason_code, cookie,
2066 cookie); 2263 !req->local_state_change);
2067 2264
2068 ieee80211_recalc_idle(sdata->local); 2265 ieee80211_recalc_idle(sdata->local);
2069 2266
@@ -2075,6 +2272,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
2075 void *cookie) 2272 void *cookie)
2076{ 2273{
2077 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 2274 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2275 u8 bssid[ETH_ALEN];
2078 2276
2079 mutex_lock(&ifmgd->mtx); 2277 mutex_lock(&ifmgd->mtx);
2080 2278
@@ -2092,13 +2290,15 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
2092 printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", 2290 printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
2093 sdata->name, req->bss->bssid, req->reason_code); 2291 sdata->name, req->bss->bssid, req->reason_code);
2094 2292
2095 ieee80211_set_disassoc(sdata); 2293 memcpy(bssid, req->bss->bssid, ETH_ALEN);
2294 ieee80211_set_disassoc(sdata, false);
2096 2295
2097 mutex_unlock(&ifmgd->mtx); 2296 mutex_unlock(&ifmgd->mtx);
2098 2297
2099 ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, 2298 ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
2100 IEEE80211_STYPE_DISASSOC, req->reason_code, 2299 IEEE80211_STYPE_DISASSOC, req->reason_code,
2101 cookie); 2300 cookie, !req->local_state_change);
2301 sta_info_destroy_addr(sdata, bssid);
2102 2302
2103 ieee80211_recalc_idle(sdata->local); 2303 ieee80211_recalc_idle(sdata->local);
2104 2304
@@ -2118,7 +2318,7 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
2118 if ((chan != local->tmp_channel || 2318 if ((chan != local->tmp_channel ||
2119 channel_type != local->tmp_channel_type) && 2319 channel_type != local->tmp_channel_type) &&
2120 (chan != local->oper_channel || 2320 (chan != local->oper_channel ||
2121 channel_type != local->oper_channel_type)) 2321 channel_type != local->_oper_channel_type))
2122 return -EBUSY; 2322 return -EBUSY;
2123 2323
2124 skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); 2324 skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
@@ -2139,3 +2339,15 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
2139 *cookie = (unsigned long) skb; 2339 *cookie = (unsigned long) skb;
2140 return 0; 2340 return 0;
2141} 2341}
2342
2343void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
2344 enum nl80211_cqm_rssi_threshold_event rssi_event,
2345 gfp_t gfp)
2346{
2347 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
2348
2349 trace_api_cqm_rssi_notify(sdata, rssi_event);
2350
2351 cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
2352}
2353EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);