diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 790 |
1 files changed, 601 insertions, 189 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 132938b073dc..d779c57a8220 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -17,10 +17,13 @@ | |||
17 | #include <linux/if_arp.h> | 17 | #include <linux/if_arp.h> |
18 | #include <linux/etherdevice.h> | 18 | #include <linux/etherdevice.h> |
19 | #include <linux/rtnetlink.h> | 19 | #include <linux/rtnetlink.h> |
20 | #include <linux/pm_qos_params.h> | ||
21 | #include <linux/crc32.h> | ||
20 | #include <net/mac80211.h> | 22 | #include <net/mac80211.h> |
21 | #include <asm/unaligned.h> | 23 | #include <asm/unaligned.h> |
22 | 24 | ||
23 | #include "ieee80211_i.h" | 25 | #include "ieee80211_i.h" |
26 | #include "driver-ops.h" | ||
24 | #include "rate.h" | 27 | #include "rate.h" |
25 | #include "led.h" | 28 | #include "led.h" |
26 | 29 | ||
@@ -30,9 +33,13 @@ | |||
30 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 33 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
31 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 34 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
32 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 35 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) |
36 | #define IEEE80211_PROBE_WAIT (HZ / 5) | ||
33 | #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) | 37 | #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) |
34 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | 38 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) |
35 | 39 | ||
40 | #define TMR_RUNNING_TIMER 0 | ||
41 | #define TMR_RUNNING_CHANSW 1 | ||
42 | |||
36 | /* utils */ | 43 | /* utils */ |
37 | static int ecw2cw(int ecw) | 44 | static int ecw2cw(int ecw) |
38 | { | 45 | { |
@@ -80,6 +87,92 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | |||
80 | return count; | 87 | return count; |
81 | } | 88 | } |
82 | 89 | ||
90 | /* | ||
91 | * ieee80211_enable_ht should be called only after the operating band | ||
92 | * has been determined as ht configuration depends on the hw's | ||
93 | * HT abilities for a specific band. | ||
94 | */ | ||
95 | static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | ||
96 | struct ieee80211_ht_info *hti, | ||
97 | u16 ap_ht_cap_flags) | ||
98 | { | ||
99 | struct ieee80211_local *local = sdata->local; | ||
100 | struct ieee80211_supported_band *sband; | ||
101 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
102 | struct sta_info *sta; | ||
103 | u32 changed = 0; | ||
104 | u16 ht_opmode; | ||
105 | bool enable_ht = true, ht_changed; | ||
106 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
107 | |||
108 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
109 | |||
110 | /* HT is not supported */ | ||
111 | if (!sband->ht_cap.ht_supported) | ||
112 | enable_ht = false; | ||
113 | |||
114 | /* check that channel matches the right operating channel */ | ||
115 | if (local->hw.conf.channel->center_freq != | ||
116 | ieee80211_channel_to_frequency(hti->control_chan)) | ||
117 | enable_ht = false; | ||
118 | |||
119 | if (enable_ht) { | ||
120 | channel_type = NL80211_CHAN_HT20; | ||
121 | |||
122 | if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && | ||
123 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && | ||
124 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { | ||
125 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
126 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
127 | if (!(local->hw.conf.channel->flags & | ||
128 | IEEE80211_CHAN_NO_HT40PLUS)) | ||
129 | channel_type = NL80211_CHAN_HT40PLUS; | ||
130 | break; | ||
131 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
132 | if (!(local->hw.conf.channel->flags & | ||
133 | IEEE80211_CHAN_NO_HT40MINUS)) | ||
134 | channel_type = NL80211_CHAN_HT40MINUS; | ||
135 | break; | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | |||
140 | ht_changed = conf_is_ht(&local->hw.conf) != enable_ht || | ||
141 | channel_type != local->hw.conf.channel_type; | ||
142 | |||
143 | local->oper_channel_type = channel_type; | ||
144 | |||
145 | if (ht_changed) { | ||
146 | /* channel_type change automatically detected */ | ||
147 | ieee80211_hw_config(local, 0); | ||
148 | |||
149 | rcu_read_lock(); | ||
150 | |||
151 | sta = sta_info_get(local, ifmgd->bssid); | ||
152 | if (sta) | ||
153 | rate_control_rate_update(local, sband, sta, | ||
154 | IEEE80211_RC_HT_CHANGED); | ||
155 | |||
156 | rcu_read_unlock(); | ||
157 | } | ||
158 | |||
159 | /* disable HT */ | ||
160 | if (!enable_ht) | ||
161 | return 0; | ||
162 | |||
163 | ht_opmode = le16_to_cpu(hti->operation_mode); | ||
164 | |||
165 | /* if bss configuration changed store the new one */ | ||
166 | if (!sdata->ht_opmode_valid || | ||
167 | sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { | ||
168 | changed |= BSS_CHANGED_HT; | ||
169 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; | ||
170 | sdata->ht_opmode_valid = true; | ||
171 | } | ||
172 | |||
173 | return changed; | ||
174 | } | ||
175 | |||
83 | /* frame sending functions */ | 176 | /* frame sending functions */ |
84 | 177 | ||
85 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | 178 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) |
@@ -263,13 +356,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
263 | 356 | ||
264 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 357 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
265 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 358 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
266 | if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { | 359 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { |
267 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 360 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
268 | cap &= ~IEEE80211_HT_CAP_SGI_40; | 361 | cap &= ~IEEE80211_HT_CAP_SGI_40; |
269 | } | 362 | } |
270 | break; | 363 | break; |
271 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | 364 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: |
272 | if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { | 365 | if (flags & IEEE80211_CHAN_NO_HT40MINUS) { |
273 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 366 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
274 | cap &= ~IEEE80211_HT_CAP_SGI_40; | 367 | cap &= ~IEEE80211_HT_CAP_SGI_40; |
275 | } | 368 | } |
@@ -325,6 +418,10 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
325 | /* u.deauth.reason_code == u.disassoc.reason_code */ | 418 | /* u.deauth.reason_code == u.disassoc.reason_code */ |
326 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | 419 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); |
327 | 420 | ||
421 | if (stype == IEEE80211_STYPE_DEAUTH) | ||
422 | cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len); | ||
423 | else | ||
424 | cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len); | ||
328 | ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); | 425 | ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); |
329 | } | 426 | } |
330 | 427 | ||
@@ -359,6 +456,277 @@ void ieee80211_send_pspoll(struct ieee80211_local *local, | |||
359 | ieee80211_tx_skb(sdata, skb, 0); | 456 | ieee80211_tx_skb(sdata, skb, 0); |
360 | } | 457 | } |
361 | 458 | ||
459 | void ieee80211_send_nullfunc(struct ieee80211_local *local, | ||
460 | struct ieee80211_sub_if_data *sdata, | ||
461 | int powersave) | ||
462 | { | ||
463 | struct sk_buff *skb; | ||
464 | struct ieee80211_hdr *nullfunc; | ||
465 | __le16 fc; | ||
466 | |||
467 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | ||
468 | return; | ||
469 | |||
470 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | ||
471 | if (!skb) { | ||
472 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
473 | "frame\n", sdata->dev->name); | ||
474 | return; | ||
475 | } | ||
476 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
477 | |||
478 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | ||
479 | memset(nullfunc, 0, 24); | ||
480 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | ||
481 | IEEE80211_FCTL_TODS); | ||
482 | if (powersave) | ||
483 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
484 | nullfunc->frame_control = fc; | ||
485 | memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); | ||
486 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); | ||
487 | memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); | ||
488 | |||
489 | ieee80211_tx_skb(sdata, skb, 0); | ||
490 | } | ||
491 | |||
492 | /* spectrum management related things */ | ||
493 | static void ieee80211_chswitch_work(struct work_struct *work) | ||
494 | { | ||
495 | struct ieee80211_sub_if_data *sdata = | ||
496 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | ||
497 | struct ieee80211_bss *bss; | ||
498 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
499 | |||
500 | if (!netif_running(sdata->dev)) | ||
501 | return; | ||
502 | |||
503 | bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, | ||
504 | sdata->local->hw.conf.channel->center_freq, | ||
505 | ifmgd->ssid, ifmgd->ssid_len); | ||
506 | if (!bss) | ||
507 | goto exit; | ||
508 | |||
509 | sdata->local->oper_channel = sdata->local->csa_channel; | ||
510 | /* XXX: shouldn't really modify cfg80211-owned data! */ | ||
511 | if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) | ||
512 | bss->cbss.channel = sdata->local->oper_channel; | ||
513 | |||
514 | ieee80211_rx_bss_put(sdata->local, bss); | ||
515 | exit: | ||
516 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
517 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
518 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
519 | } | ||
520 | |||
521 | static void ieee80211_chswitch_timer(unsigned long data) | ||
522 | { | ||
523 | struct ieee80211_sub_if_data *sdata = | ||
524 | (struct ieee80211_sub_if_data *) data; | ||
525 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
526 | |||
527 | if (sdata->local->quiescing) { | ||
528 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | ||
529 | return; | ||
530 | } | ||
531 | |||
532 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); | ||
533 | } | ||
534 | |||
535 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
536 | struct ieee80211_channel_sw_ie *sw_elem, | ||
537 | struct ieee80211_bss *bss) | ||
538 | { | ||
539 | struct ieee80211_channel *new_ch; | ||
540 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
541 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); | ||
542 | |||
543 | if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) | ||
544 | return; | ||
545 | |||
546 | if (sdata->local->sw_scanning || sdata->local->hw_scanning) | ||
547 | return; | ||
548 | |||
549 | /* Disregard subsequent beacons if we are already running a timer | ||
550 | processing a CSA */ | ||
551 | |||
552 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | ||
553 | return; | ||
554 | |||
555 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | ||
556 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) | ||
557 | return; | ||
558 | |||
559 | sdata->local->csa_channel = new_ch; | ||
560 | |||
561 | if (sw_elem->count <= 1) { | ||
562 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); | ||
563 | } else { | ||
564 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
565 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
566 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||
567 | mod_timer(&ifmgd->chswitch_timer, | ||
568 | jiffies + | ||
569 | msecs_to_jiffies(sw_elem->count * | ||
570 | bss->cbss.beacon_interval)); | ||
571 | } | ||
572 | } | ||
573 | |||
574 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | ||
575 | u16 capab_info, u8 *pwr_constr_elem, | ||
576 | u8 pwr_constr_elem_len) | ||
577 | { | ||
578 | struct ieee80211_conf *conf = &sdata->local->hw.conf; | ||
579 | |||
580 | if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) | ||
581 | return; | ||
582 | |||
583 | /* Power constraint IE length should be 1 octet */ | ||
584 | if (pwr_constr_elem_len != 1) | ||
585 | return; | ||
586 | |||
587 | if ((*pwr_constr_elem <= conf->channel->max_power) && | ||
588 | (*pwr_constr_elem != sdata->local->power_constr_level)) { | ||
589 | sdata->local->power_constr_level = *pwr_constr_elem; | ||
590 | ieee80211_hw_config(sdata->local, 0); | ||
591 | } | ||
592 | } | ||
593 | |||
594 | /* powersave */ | ||
595 | static void ieee80211_enable_ps(struct ieee80211_local *local, | ||
596 | struct ieee80211_sub_if_data *sdata) | ||
597 | { | ||
598 | struct ieee80211_conf *conf = &local->hw.conf; | ||
599 | |||
600 | /* | ||
601 | * If we are scanning right now then the parameters will | ||
602 | * take effect when scan finishes. | ||
603 | */ | ||
604 | if (local->hw_scanning || local->sw_scanning) | ||
605 | return; | ||
606 | |||
607 | if (conf->dynamic_ps_timeout > 0 && | ||
608 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) { | ||
609 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
610 | msecs_to_jiffies(conf->dynamic_ps_timeout)); | ||
611 | } else { | ||
612 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
613 | ieee80211_send_nullfunc(local, sdata, 1); | ||
614 | conf->flags |= IEEE80211_CONF_PS; | ||
615 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
616 | } | ||
617 | } | ||
618 | |||
619 | static void ieee80211_change_ps(struct ieee80211_local *local) | ||
620 | { | ||
621 | struct ieee80211_conf *conf = &local->hw.conf; | ||
622 | |||
623 | if (local->ps_sdata) { | ||
624 | ieee80211_enable_ps(local, local->ps_sdata); | ||
625 | } else if (conf->flags & IEEE80211_CONF_PS) { | ||
626 | conf->flags &= ~IEEE80211_CONF_PS; | ||
627 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
628 | del_timer_sync(&local->dynamic_ps_timer); | ||
629 | cancel_work_sync(&local->dynamic_ps_enable_work); | ||
630 | } | ||
631 | } | ||
632 | |||
633 | /* need to hold RTNL or interface lock */ | ||
634 | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | ||
635 | { | ||
636 | struct ieee80211_sub_if_data *sdata, *found = NULL; | ||
637 | int count = 0; | ||
638 | |||
639 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) { | ||
640 | local->ps_sdata = NULL; | ||
641 | return; | ||
642 | } | ||
643 | |||
644 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
645 | if (!netif_running(sdata->dev)) | ||
646 | continue; | ||
647 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
648 | continue; | ||
649 | found = sdata; | ||
650 | count++; | ||
651 | } | ||
652 | |||
653 | if (count == 1 && found->u.mgd.powersave && | ||
654 | (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) && | ||
655 | !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { | ||
656 | s32 beaconint_us; | ||
657 | |||
658 | if (latency < 0) | ||
659 | latency = pm_qos_requirement(PM_QOS_NETWORK_LATENCY); | ||
660 | |||
661 | beaconint_us = ieee80211_tu_to_usec( | ||
662 | found->vif.bss_conf.beacon_int); | ||
663 | |||
664 | if (beaconint_us > latency) { | ||
665 | local->ps_sdata = NULL; | ||
666 | } else { | ||
667 | u8 dtimper = found->vif.bss_conf.dtim_period; | ||
668 | int maxslp = 1; | ||
669 | |||
670 | if (dtimper > 1) | ||
671 | maxslp = min_t(int, dtimper, | ||
672 | latency / beaconint_us); | ||
673 | |||
674 | local->hw.conf.max_sleep_period = maxslp; | ||
675 | local->ps_sdata = found; | ||
676 | } | ||
677 | } else { | ||
678 | local->ps_sdata = NULL; | ||
679 | } | ||
680 | |||
681 | ieee80211_change_ps(local); | ||
682 | } | ||
683 | |||
684 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work) | ||
685 | { | ||
686 | struct ieee80211_local *local = | ||
687 | container_of(work, struct ieee80211_local, | ||
688 | dynamic_ps_disable_work); | ||
689 | |||
690 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
691 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||
692 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
693 | } | ||
694 | |||
695 | ieee80211_wake_queues_by_reason(&local->hw, | ||
696 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
697 | } | ||
698 | |||
699 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | ||
700 | { | ||
701 | struct ieee80211_local *local = | ||
702 | container_of(work, struct ieee80211_local, | ||
703 | dynamic_ps_enable_work); | ||
704 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; | ||
705 | |||
706 | /* can only happen when PS was just disabled anyway */ | ||
707 | if (!sdata) | ||
708 | return; | ||
709 | |||
710 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | ||
711 | return; | ||
712 | |||
713 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
714 | ieee80211_send_nullfunc(local, sdata, 1); | ||
715 | |||
716 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
717 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
718 | } | ||
719 | |||
720 | void ieee80211_dynamic_ps_timer(unsigned long data) | ||
721 | { | ||
722 | struct ieee80211_local *local = (void *) data; | ||
723 | |||
724 | if (local->quiescing) | ||
725 | return; | ||
726 | |||
727 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); | ||
728 | } | ||
729 | |||
362 | /* MLME */ | 730 | /* MLME */ |
363 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | 731 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, |
364 | struct ieee80211_if_managed *ifmgd, | 732 | struct ieee80211_if_managed *ifmgd, |
@@ -424,41 +792,16 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
424 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 792 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
425 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " | 793 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " |
426 | "cWmin=%d cWmax=%d txop=%d\n", | 794 | "cWmin=%d cWmax=%d txop=%d\n", |
427 | local->mdev->name, queue, aci, acm, params.aifs, params.cw_min, | 795 | wiphy_name(local->hw.wiphy), queue, aci, acm, |
428 | params.cw_max, params.txop); | 796 | params.aifs, params.cw_min, params.cw_max, params.txop); |
429 | #endif | 797 | #endif |
430 | if (local->ops->conf_tx && | 798 | if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) |
431 | local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) { | ||
432 | printk(KERN_DEBUG "%s: failed to set TX queue " | 799 | printk(KERN_DEBUG "%s: failed to set TX queue " |
433 | "parameters for queue %d\n", local->mdev->name, queue); | 800 | "parameters for queue %d\n", |
434 | } | 801 | wiphy_name(local->hw.wiphy), queue); |
435 | } | 802 | } |
436 | } | 803 | } |
437 | 804 | ||
438 | static bool ieee80211_check_tim(struct ieee802_11_elems *elems, u16 aid) | ||
439 | { | ||
440 | u8 mask; | ||
441 | u8 index, indexn1, indexn2; | ||
442 | struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) elems->tim; | ||
443 | |||
444 | if (unlikely(!tim || elems->tim_len < 4)) | ||
445 | return false; | ||
446 | |||
447 | aid &= 0x3fff; | ||
448 | index = aid / 8; | ||
449 | mask = 1 << (aid & 7); | ||
450 | |||
451 | indexn1 = tim->bitmap_ctrl & 0xfe; | ||
452 | indexn2 = elems->tim_len + indexn1 - 4; | ||
453 | |||
454 | if (index < indexn1 || index > indexn2) | ||
455 | return false; | ||
456 | |||
457 | index -= indexn1; | ||
458 | |||
459 | return !!(tim->virtual_map[index] & mask); | ||
460 | } | ||
461 | |||
462 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | 805 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, |
463 | u16 capab, bool erp_valid, u8 erp) | 806 | u16 capab, bool erp_valid, u8 erp) |
464 | { | 807 | { |
@@ -610,6 +953,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
610 | sdata->vif.bss_conf.timestamp = bss->cbss.tsf; | 953 | sdata->vif.bss_conf.timestamp = bss->cbss.tsf; |
611 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; | 954 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; |
612 | 955 | ||
956 | bss_info_changed |= BSS_CHANGED_BEACON_INT; | ||
613 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 957 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
614 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); | 958 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); |
615 | 959 | ||
@@ -632,20 +976,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
632 | * changed or not. | 976 | * changed or not. |
633 | */ | 977 | */ |
634 | bss_info_changed |= BSS_CHANGED_BASIC_RATES; | 978 | bss_info_changed |= BSS_CHANGED_BASIC_RATES; |
979 | |||
980 | /* And the BSSID changed - we're associated now */ | ||
981 | bss_info_changed |= BSS_CHANGED_BSSID; | ||
982 | |||
635 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); | 983 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); |
636 | 984 | ||
637 | if (local->powersave) { | 985 | /* will be same as sdata */ |
638 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) && | 986 | if (local->ps_sdata) { |
639 | local->hw.conf.dynamic_ps_timeout > 0) { | 987 | mutex_lock(&local->iflist_mtx); |
640 | mod_timer(&local->dynamic_ps_timer, jiffies + | 988 | ieee80211_recalc_ps(local, -1); |
641 | msecs_to_jiffies( | 989 | mutex_unlock(&local->iflist_mtx); |
642 | local->hw.conf.dynamic_ps_timeout)); | ||
643 | } else { | ||
644 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
645 | ieee80211_send_nullfunc(local, sdata, 1); | ||
646 | conf->flags |= IEEE80211_CONF_PS; | ||
647 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
648 | } | ||
649 | } | 990 | } |
650 | 991 | ||
651 | netif_tx_start_all_queues(sdata->dev); | 992 | netif_tx_start_all_queues(sdata->dev); |
@@ -664,7 +1005,8 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) | |||
664 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", | 1005 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", |
665 | sdata->dev->name, ifmgd->bssid); | 1006 | sdata->dev->name, ifmgd->bssid); |
666 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | 1007 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
667 | ieee80211_sta_send_apinfo(sdata); | 1008 | ieee80211_recalc_idle(local); |
1009 | cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); | ||
668 | 1010 | ||
669 | /* | 1011 | /* |
670 | * Most likely AP is not in the range so remove the | 1012 | * Most likely AP is not in the range so remove the |
@@ -689,8 +1031,6 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) | |||
689 | 1031 | ||
690 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 1032 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
691 | 1033 | ||
692 | set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifmgd->request); | ||
693 | |||
694 | /* Direct probe is sent to broadcast address as some APs | 1034 | /* Direct probe is sent to broadcast address as some APs |
695 | * will not answer to direct packet in unassociated state. | 1035 | * will not answer to direct packet in unassociated state. |
696 | */ | 1036 | */ |
@@ -714,7 +1054,8 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) | |||
714 | " timed out\n", | 1054 | " timed out\n", |
715 | sdata->dev->name, ifmgd->bssid); | 1055 | sdata->dev->name, ifmgd->bssid); |
716 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | 1056 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
717 | ieee80211_sta_send_apinfo(sdata); | 1057 | ieee80211_recalc_idle(local); |
1058 | cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); | ||
718 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | 1059 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
719 | sdata->local->hw.conf.channel->center_freq, | 1060 | sdata->local->hw.conf.channel->center_freq, |
720 | ifmgd->ssid, ifmgd->ssid_len); | 1061 | ifmgd->ssid, ifmgd->ssid_len); |
@@ -817,9 +1158,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
817 | 1158 | ||
818 | rcu_read_unlock(); | 1159 | rcu_read_unlock(); |
819 | 1160 | ||
1161 | ieee80211_set_wmm_default(sdata); | ||
1162 | |||
1163 | ieee80211_recalc_idle(local); | ||
1164 | |||
820 | /* channel(_type) changes are handled by ieee80211_hw_config */ | 1165 | /* channel(_type) changes are handled by ieee80211_hw_config */ |
821 | local->oper_channel_type = NL80211_CHAN_NO_HT; | 1166 | local->oper_channel_type = NL80211_CHAN_NO_HT; |
822 | 1167 | ||
1168 | /* on the next assoc, re-program HT parameters */ | ||
1169 | sdata->ht_opmode_valid = false; | ||
1170 | |||
823 | local->power_constr_level = 0; | 1171 | local->power_constr_level = 0; |
824 | 1172 | ||
825 | del_timer_sync(&local->dynamic_ps_timer); | 1173 | del_timer_sync(&local->dynamic_ps_timer); |
@@ -831,6 +1179,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
831 | } | 1179 | } |
832 | 1180 | ||
833 | ieee80211_hw_config(local, config_changed); | 1181 | ieee80211_hw_config(local, config_changed); |
1182 | |||
1183 | /* And the BSSID changed -- not very interesting here */ | ||
1184 | changed |= BSS_CHANGED_BSSID; | ||
834 | ieee80211_bss_info_change_notify(sdata, changed); | 1185 | ieee80211_bss_info_change_notify(sdata, changed); |
835 | 1186 | ||
836 | rcu_read_lock(); | 1187 | rcu_read_lock(); |
@@ -897,7 +1248,8 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) | |||
897 | " timed out\n", | 1248 | " timed out\n", |
898 | sdata->dev->name, ifmgd->bssid); | 1249 | sdata->dev->name, ifmgd->bssid); |
899 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | 1250 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
900 | ieee80211_sta_send_apinfo(sdata); | 1251 | ieee80211_recalc_idle(local); |
1252 | cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid); | ||
901 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | 1253 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
902 | sdata->local->hw.conf.channel->center_freq, | 1254 | sdata->local->hw.conf.channel->center_freq, |
903 | ifmgd->ssid, ifmgd->ssid_len); | 1255 | ifmgd->ssid, ifmgd->ssid_len); |
@@ -917,6 +1269,7 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) | |||
917 | printk(KERN_DEBUG "%s: mismatch in privacy configuration and " | 1269 | printk(KERN_DEBUG "%s: mismatch in privacy configuration and " |
918 | "mixed-cell disabled - abort association\n", sdata->dev->name); | 1270 | "mixed-cell disabled - abort association\n", sdata->dev->name); |
919 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | 1271 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
1272 | ieee80211_recalc_idle(local); | ||
920 | return; | 1273 | return; |
921 | } | 1274 | } |
922 | 1275 | ||
@@ -948,6 +1301,17 @@ void ieee80211_beacon_loss_work(struct work_struct *work) | |||
948 | u.mgd.beacon_loss_work); | 1301 | u.mgd.beacon_loss_work); |
949 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1302 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
950 | 1303 | ||
1304 | /* | ||
1305 | * The driver has already reported this event and we have | ||
1306 | * already sent a probe request. Maybe the AP died and the | ||
1307 | * driver keeps reporting until we disassociate... We have | ||
1308 | * to ignore that because otherwise we would continually | ||
1309 | * reset the timer and never check whether we received a | ||
1310 | * probe response! | ||
1311 | */ | ||
1312 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) | ||
1313 | return; | ||
1314 | |||
951 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1315 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
952 | if (net_ratelimit()) { | 1316 | if (net_ratelimit()) { |
953 | printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM " | 1317 | printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM " |
@@ -957,10 +1321,15 @@ void ieee80211_beacon_loss_work(struct work_struct *work) | |||
957 | #endif | 1321 | #endif |
958 | 1322 | ||
959 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | 1323 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; |
1324 | |||
1325 | mutex_lock(&sdata->local->iflist_mtx); | ||
1326 | ieee80211_recalc_ps(sdata->local, -1); | ||
1327 | mutex_unlock(&sdata->local->iflist_mtx); | ||
1328 | |||
960 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | 1329 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, |
961 | ifmgd->ssid_len, NULL, 0); | 1330 | ifmgd->ssid_len, NULL, 0); |
962 | 1331 | ||
963 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL); | 1332 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); |
964 | } | 1333 | } |
965 | 1334 | ||
966 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | 1335 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) |
@@ -977,6 +1346,7 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | |||
977 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1346 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
978 | struct ieee80211_local *local = sdata->local; | 1347 | struct ieee80211_local *local = sdata->local; |
979 | struct sta_info *sta; | 1348 | struct sta_info *sta; |
1349 | unsigned long last_rx; | ||
980 | bool disassoc = false; | 1350 | bool disassoc = false; |
981 | 1351 | ||
982 | /* TODO: start monitoring current AP signal quality and number of | 1352 | /* TODO: start monitoring current AP signal quality and number of |
@@ -993,17 +1363,21 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | |||
993 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", | 1363 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", |
994 | sdata->dev->name, ifmgd->bssid); | 1364 | sdata->dev->name, ifmgd->bssid); |
995 | disassoc = true; | 1365 | disassoc = true; |
996 | goto unlock; | 1366 | rcu_read_unlock(); |
1367 | goto out; | ||
997 | } | 1368 | } |
998 | 1369 | ||
1370 | last_rx = sta->last_rx; | ||
1371 | rcu_read_unlock(); | ||
1372 | |||
999 | if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && | 1373 | if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && |
1000 | time_after(jiffies, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { | 1374 | time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) { |
1001 | printk(KERN_DEBUG "%s: no probe response from AP %pM " | 1375 | printk(KERN_DEBUG "%s: no probe response from AP %pM " |
1002 | "- disassociating\n", | 1376 | "- disassociating\n", |
1003 | sdata->dev->name, ifmgd->bssid); | 1377 | sdata->dev->name, ifmgd->bssid); |
1004 | disassoc = true; | 1378 | disassoc = true; |
1005 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | 1379 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; |
1006 | goto unlock; | 1380 | goto out; |
1007 | } | 1381 | } |
1008 | 1382 | ||
1009 | /* | 1383 | /* |
@@ -1022,27 +1396,31 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | |||
1022 | } | 1396 | } |
1023 | #endif | 1397 | #endif |
1024 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | 1398 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; |
1399 | mutex_lock(&local->iflist_mtx); | ||
1400 | ieee80211_recalc_ps(local, -1); | ||
1401 | mutex_unlock(&local->iflist_mtx); | ||
1025 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | 1402 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, |
1026 | ifmgd->ssid_len, NULL, 0); | 1403 | ifmgd->ssid_len, NULL, 0); |
1027 | goto unlock; | 1404 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); |
1028 | 1405 | goto out; | |
1029 | } | 1406 | } |
1030 | 1407 | ||
1031 | if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) { | 1408 | if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) { |
1032 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | 1409 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; |
1410 | mutex_lock(&local->iflist_mtx); | ||
1411 | ieee80211_recalc_ps(local, -1); | ||
1412 | mutex_unlock(&local->iflist_mtx); | ||
1033 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | 1413 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, |
1034 | ifmgd->ssid_len, NULL, 0); | 1414 | ifmgd->ssid_len, NULL, 0); |
1035 | } | 1415 | } |
1036 | 1416 | ||
1037 | unlock: | 1417 | out: |
1038 | rcu_read_unlock(); | 1418 | if (!disassoc) |
1039 | 1419 | mod_timer(&ifmgd->timer, | |
1040 | if (disassoc) | 1420 | jiffies + IEEE80211_MONITORING_INTERVAL); |
1421 | else | ||
1041 | ieee80211_set_disassoc(sdata, true, true, | 1422 | ieee80211_set_disassoc(sdata, true, true, |
1042 | WLAN_REASON_PREV_AUTH_NOT_VALID); | 1423 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
1043 | else | ||
1044 | mod_timer(&ifmgd->timer, jiffies + | ||
1045 | IEEE80211_MONITORING_INTERVAL); | ||
1046 | } | 1424 | } |
1047 | 1425 | ||
1048 | 1426 | ||
@@ -1055,6 +1433,7 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) | |||
1055 | if (ifmgd->flags & IEEE80211_STA_EXT_SME) { | 1433 | if (ifmgd->flags & IEEE80211_STA_EXT_SME) { |
1056 | /* Wait for SME to request association */ | 1434 | /* Wait for SME to request association */ |
1057 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | 1435 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
1436 | ieee80211_recalc_idle(sdata->local); | ||
1058 | } else | 1437 | } else |
1059 | ieee80211_associate(sdata); | 1438 | ieee80211_associate(sdata); |
1060 | } | 1439 | } |
@@ -1187,7 +1566,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1187 | 1566 | ||
1188 | ieee80211_set_disassoc(sdata, true, false, 0); | 1567 | ieee80211_set_disassoc(sdata, true, false, 0); |
1189 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; | 1568 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; |
1190 | cfg80211_send_rx_deauth(sdata->dev, (u8 *) mgmt, len); | 1569 | cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len); |
1191 | } | 1570 | } |
1192 | 1571 | ||
1193 | 1572 | ||
@@ -1218,7 +1597,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1218 | } | 1597 | } |
1219 | 1598 | ||
1220 | ieee80211_set_disassoc(sdata, false, false, reason_code); | 1599 | ieee80211_set_disassoc(sdata, false, false, reason_code); |
1221 | cfg80211_send_rx_disassoc(sdata->dev, (u8 *) mgmt, len); | 1600 | cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len); |
1222 | } | 1601 | } |
1223 | 1602 | ||
1224 | 1603 | ||
@@ -1287,6 +1666,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1287 | * association next time. This works around some broken APs | 1666 | * association next time. This works around some broken APs |
1288 | * which do not correctly reject reassociation requests. */ | 1667 | * which do not correctly reject reassociation requests. */ |
1289 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 1668 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; |
1669 | cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len); | ||
1670 | if (ifmgd->flags & IEEE80211_STA_EXT_SME) { | ||
1671 | /* Wait for SME to decide what to do next */ | ||
1672 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | ||
1673 | ieee80211_recalc_idle(local); | ||
1674 | } | ||
1290 | return; | 1675 | return; |
1291 | } | 1676 | } |
1292 | 1677 | ||
@@ -1340,8 +1725,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1340 | * to between the sta_info_alloc() and sta_info_insert() above. | 1725 | * to between the sta_info_alloc() and sta_info_insert() above. |
1341 | */ | 1726 | */ |
1342 | 1727 | ||
1343 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | | 1728 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP); |
1344 | WLAN_STA_AUTHORIZED); | 1729 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) |
1730 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | ||
1345 | 1731 | ||
1346 | rates = 0; | 1732 | rates = 0; |
1347 | basic_rates = 0; | 1733 | basic_rates = 0; |
@@ -1421,6 +1807,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1421 | if (elems.wmm_param) | 1807 | if (elems.wmm_param) |
1422 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, | 1808 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, |
1423 | elems.wmm_param_len); | 1809 | elems.wmm_param_len); |
1810 | else | ||
1811 | ieee80211_set_wmm_default(sdata); | ||
1424 | 1812 | ||
1425 | if (elems.ht_info_elem && elems.wmm_param && | 1813 | if (elems.ht_info_elem && elems.wmm_param && |
1426 | (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && | 1814 | (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && |
@@ -1476,7 +1864,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1476 | (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { | 1864 | (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { |
1477 | struct ieee80211_channel_sw_ie *sw_elem = | 1865 | struct ieee80211_channel_sw_ie *sw_elem = |
1478 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; | 1866 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; |
1479 | ieee80211_process_chanswitch(sdata, sw_elem, bss); | 1867 | ieee80211_sta_process_chanswitch(sdata, sw_elem, bss); |
1480 | } | 1868 | } |
1481 | 1869 | ||
1482 | ieee80211_rx_bss_put(local, bss); | 1870 | ieee80211_rx_bss_put(local, bss); |
@@ -1507,57 +1895,98 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1507 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); | 1895 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
1508 | 1896 | ||
1509 | /* direct probe may be part of the association flow */ | 1897 | /* direct probe may be part of the association flow */ |
1510 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, | 1898 | if (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE) { |
1511 | &ifmgd->request)) { | ||
1512 | printk(KERN_DEBUG "%s direct probe responded\n", | 1899 | printk(KERN_DEBUG "%s direct probe responded\n", |
1513 | sdata->dev->name); | 1900 | sdata->dev->name); |
1514 | ieee80211_authenticate(sdata); | 1901 | ieee80211_authenticate(sdata); |
1515 | } | 1902 | } |
1516 | 1903 | ||
1517 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) | 1904 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { |
1518 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | 1905 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; |
1906 | mutex_lock(&sdata->local->iflist_mtx); | ||
1907 | ieee80211_recalc_ps(sdata->local, -1); | ||
1908 | mutex_unlock(&sdata->local->iflist_mtx); | ||
1909 | } | ||
1519 | } | 1910 | } |
1520 | 1911 | ||
1912 | /* | ||
1913 | * This is the canonical list of information elements we care about, | ||
1914 | * the filter code also gives us all changes to the Microsoft OUI | ||
1915 | * (00:50:F2) vendor IE which is used for WMM which we need to track. | ||
1916 | * | ||
1917 | * We implement beacon filtering in software since that means we can | ||
1918 | * avoid processing the frame here and in cfg80211, and userspace | ||
1919 | * will not be able to tell whether the hardware supports it or not. | ||
1920 | * | ||
1921 | * XXX: This list needs to be dynamic -- userspace needs to be able to | ||
1922 | * add items it requires. It also needs to be able to tell us to | ||
1923 | * look out for other vendor IEs. | ||
1924 | */ | ||
1925 | static const u64 care_about_ies = | ||
1926 | (1ULL << WLAN_EID_COUNTRY) | | ||
1927 | (1ULL << WLAN_EID_ERP_INFO) | | ||
1928 | (1ULL << WLAN_EID_CHANNEL_SWITCH) | | ||
1929 | (1ULL << WLAN_EID_PWR_CONSTRAINT) | | ||
1930 | (1ULL << WLAN_EID_HT_CAPABILITY) | | ||
1931 | (1ULL << WLAN_EID_HT_INFORMATION); | ||
1932 | |||
1521 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 1933 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
1522 | struct ieee80211_mgmt *mgmt, | 1934 | struct ieee80211_mgmt *mgmt, |
1523 | size_t len, | 1935 | size_t len, |
1524 | struct ieee80211_rx_status *rx_status) | 1936 | struct ieee80211_rx_status *rx_status) |
1525 | { | 1937 | { |
1526 | struct ieee80211_if_managed *ifmgd; | 1938 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1527 | size_t baselen; | 1939 | size_t baselen; |
1528 | struct ieee802_11_elems elems; | 1940 | struct ieee802_11_elems elems; |
1529 | struct ieee80211_local *local = sdata->local; | 1941 | struct ieee80211_local *local = sdata->local; |
1530 | u32 changed = 0; | 1942 | u32 changed = 0; |
1531 | bool erp_valid, directed_tim; | 1943 | bool erp_valid, directed_tim = false; |
1532 | u8 erp_value = 0; | 1944 | u8 erp_value = 0; |
1945 | u32 ncrc; | ||
1533 | 1946 | ||
1534 | /* Process beacon from the current BSS */ | 1947 | /* Process beacon from the current BSS */ |
1535 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; | 1948 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; |
1536 | if (baselen > len) | 1949 | if (baselen > len) |
1537 | return; | 1950 | return; |
1538 | 1951 | ||
1539 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); | 1952 | if (rx_status->freq != local->hw.conf.channel->center_freq) |
1540 | |||
1541 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); | ||
1542 | |||
1543 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
1544 | return; | 1953 | return; |
1545 | 1954 | ||
1546 | ifmgd = &sdata->u.mgd; | ||
1547 | |||
1548 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) || | 1955 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) || |
1549 | memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1956 | memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) |
1550 | return; | 1957 | return; |
1551 | 1958 | ||
1552 | if (rx_status->freq != local->hw.conf.channel->center_freq) | 1959 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { |
1553 | return; | 1960 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1961 | if (net_ratelimit()) { | ||
1962 | printk(KERN_DEBUG "%s: cancelling probereq poll due " | ||
1963 | "to a received beacon\n", sdata->dev->name); | ||
1964 | } | ||
1965 | #endif | ||
1966 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
1967 | mutex_lock(&local->iflist_mtx); | ||
1968 | ieee80211_recalc_ps(local, -1); | ||
1969 | mutex_unlock(&local->iflist_mtx); | ||
1970 | } | ||
1554 | 1971 | ||
1555 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, | 1972 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); |
1556 | elems.wmm_param_len); | 1973 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, |
1974 | len - baselen, &elems, | ||
1975 | care_about_ies, ncrc); | ||
1557 | 1976 | ||
1558 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { | 1977 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
1559 | directed_tim = ieee80211_check_tim(&elems, ifmgd->aid); | 1978 | directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, |
1979 | ifmgd->aid); | ||
1560 | 1980 | ||
1981 | if (ncrc != ifmgd->beacon_crc) { | ||
1982 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, | ||
1983 | true); | ||
1984 | |||
1985 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, | ||
1986 | elems.wmm_param_len); | ||
1987 | } | ||
1988 | |||
1989 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { | ||
1561 | if (directed_tim) { | 1990 | if (directed_tim) { |
1562 | if (local->hw.conf.dynamic_ps_timeout > 0) { | 1991 | if (local->hw.conf.dynamic_ps_timeout > 0) { |
1563 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | 1992 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; |
@@ -1580,6 +2009,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1580 | } | 2009 | } |
1581 | } | 2010 | } |
1582 | 2011 | ||
2012 | if (ncrc == ifmgd->beacon_crc) | ||
2013 | return; | ||
2014 | ifmgd->beacon_crc = ncrc; | ||
2015 | |||
1583 | if (elems.erp_info && elems.erp_info_len >= 1) { | 2016 | if (elems.erp_info && elems.erp_info_len >= 1) { |
1584 | erp_valid = true; | 2017 | erp_valid = true; |
1585 | erp_value = elems.erp_info[0]; | 2018 | erp_value = elems.erp_info[0]; |
@@ -1714,6 +2147,11 @@ static void ieee80211_sta_timer(unsigned long data) | |||
1714 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2147 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1715 | struct ieee80211_local *local = sdata->local; | 2148 | struct ieee80211_local *local = sdata->local; |
1716 | 2149 | ||
2150 | if (local->quiescing) { | ||
2151 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | ||
2152 | return; | ||
2153 | } | ||
2154 | |||
1717 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); | 2155 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); |
1718 | queue_work(local->hw.workqueue, &ifmgd->work); | 2156 | queue_work(local->hw.workqueue, &ifmgd->work); |
1719 | } | 2157 | } |
@@ -1723,10 +2161,8 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) | |||
1723 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2161 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1724 | struct ieee80211_local *local = sdata->local; | 2162 | struct ieee80211_local *local = sdata->local; |
1725 | 2163 | ||
1726 | if (local->ops->reset_tsf) { | 2164 | /* Reset own TSF to allow time synchronization work. */ |
1727 | /* Reset own TSF to allow time synchronization work. */ | 2165 | drv_reset_tsf(local); |
1728 | local->ops->reset_tsf(local_to_hw(local)); | ||
1729 | } | ||
1730 | 2166 | ||
1731 | ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ | 2167 | ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ |
1732 | 2168 | ||
@@ -1814,25 +2250,18 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) | |||
1814 | return 0; | 2250 | return 0; |
1815 | } else { | 2251 | } else { |
1816 | if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | 2252 | if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { |
2253 | |||
1817 | ifmgd->assoc_scan_tries++; | 2254 | ifmgd->assoc_scan_tries++; |
1818 | /* XXX maybe racy? */ | ||
1819 | if (local->scan_req) | ||
1820 | return -1; | ||
1821 | memcpy(local->int_scan_req.ssids[0].ssid, | ||
1822 | ifmgd->ssid, IEEE80211_MAX_SSID_LEN); | ||
1823 | if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) | ||
1824 | local->int_scan_req.ssids[0].ssid_len = 0; | ||
1825 | else | ||
1826 | local->int_scan_req.ssids[0].ssid_len = ifmgd->ssid_len; | ||
1827 | 2255 | ||
1828 | if (ieee80211_start_scan(sdata, &local->int_scan_req)) | 2256 | ieee80211_request_internal_scan(sdata, ifmgd->ssid, |
1829 | ieee80211_scan_failed(local); | 2257 | ssid_len); |
1830 | 2258 | ||
1831 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; | 2259 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; |
1832 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); | 2260 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); |
1833 | } else { | 2261 | } else { |
1834 | ifmgd->assoc_scan_tries = 0; | 2262 | ifmgd->assoc_scan_tries = 0; |
1835 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | 2263 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
2264 | ieee80211_recalc_idle(local); | ||
1836 | } | 2265 | } |
1837 | } | 2266 | } |
1838 | return -1; | 2267 | return -1; |
@@ -1855,6 +2284,17 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
1855 | 2284 | ||
1856 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | 2285 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
1857 | return; | 2286 | return; |
2287 | |||
2288 | /* | ||
2289 | * Nothing should have been stuffed into the workqueue during | ||
2290 | * the suspend->resume cycle. If this WARN is seen then there | ||
2291 | * is a bug with either the driver suspend or something in | ||
2292 | * mac80211 stuffing into the workqueue which we haven't yet | ||
2293 | * cleared during mac80211's suspend cycle. | ||
2294 | */ | ||
2295 | if (WARN_ON(local->suspended)) | ||
2296 | return; | ||
2297 | |||
1858 | ifmgd = &sdata->u.mgd; | 2298 | ifmgd = &sdata->u.mgd; |
1859 | 2299 | ||
1860 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) | 2300 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) |
@@ -1864,14 +2304,8 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
1864 | ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && | 2304 | ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && |
1865 | ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && | 2305 | ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && |
1866 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { | 2306 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { |
1867 | /* | 2307 | queue_delayed_work(local->hw.workqueue, &local->scan_work, |
1868 | * The call to ieee80211_start_scan can fail but ieee80211_request_scan | 2308 | round_jiffies_relative(0)); |
1869 | * (which queued ieee80211_sta_work) did not return an error. Thus, call | ||
1870 | * ieee80211_scan_failed here if ieee80211_start_scan fails in order to | ||
1871 | * notify the scan requester. | ||
1872 | */ | ||
1873 | if (ieee80211_start_scan(sdata, local->scan_req)) | ||
1874 | ieee80211_scan_failed(local); | ||
1875 | return; | 2309 | return; |
1876 | } | 2310 | } |
1877 | 2311 | ||
@@ -1882,6 +2316,8 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
1882 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request)) | 2316 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request)) |
1883 | return; | 2317 | return; |
1884 | 2318 | ||
2319 | ieee80211_recalc_idle(local); | ||
2320 | |||
1885 | switch (ifmgd->state) { | 2321 | switch (ifmgd->state) { |
1886 | case IEEE80211_STA_MLME_DISABLED: | 2322 | case IEEE80211_STA_MLME_DISABLED: |
1887 | break; | 2323 | break; |
@@ -1926,10 +2362,43 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
1926 | } | 2362 | } |
1927 | } | 2363 | } |
1928 | 2364 | ||
2365 | #ifdef CONFIG_PM | ||
2366 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | ||
2367 | { | ||
2368 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2369 | |||
2370 | /* | ||
2371 | * we need to use atomic bitops for the running bits | ||
2372 | * only because both timers might fire at the same | ||
2373 | * time -- the code here is properly synchronised. | ||
2374 | */ | ||
2375 | |||
2376 | cancel_work_sync(&ifmgd->work); | ||
2377 | cancel_work_sync(&ifmgd->beacon_loss_work); | ||
2378 | if (del_timer_sync(&ifmgd->timer)) | ||
2379 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | ||
2380 | |||
2381 | cancel_work_sync(&ifmgd->chswitch_work); | ||
2382 | if (del_timer_sync(&ifmgd->chswitch_timer)) | ||
2383 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | ||
2384 | } | ||
2385 | |||
2386 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | ||
2387 | { | ||
2388 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2389 | |||
2390 | if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) | ||
2391 | add_timer(&ifmgd->timer); | ||
2392 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) | ||
2393 | add_timer(&ifmgd->chswitch_timer); | ||
2394 | } | ||
2395 | #endif | ||
2396 | |||
1929 | /* interface setup */ | 2397 | /* interface setup */ |
1930 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | 2398 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
1931 | { | 2399 | { |
1932 | struct ieee80211_if_managed *ifmgd; | 2400 | struct ieee80211_if_managed *ifmgd; |
2401 | u32 hw_flags; | ||
1933 | 2402 | ||
1934 | ifmgd = &sdata->u.mgd; | 2403 | ifmgd = &sdata->u.mgd; |
1935 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); | 2404 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
@@ -1949,6 +2418,13 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1949 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 2418 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
1950 | if (sdata->local->hw.queues >= 4) | 2419 | if (sdata->local->hw.queues >= 4) |
1951 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; | 2420 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; |
2421 | |||
2422 | hw_flags = sdata->local->hw.flags; | ||
2423 | |||
2424 | if (hw_flags & IEEE80211_HW_SUPPORTS_PS) { | ||
2425 | ifmgd->powersave = CONFIG_MAC80211_DEFAULT_PS_VALUE; | ||
2426 | sdata->local->hw.conf.dynamic_ps_timeout = 500; | ||
2427 | } | ||
1952 | } | 2428 | } |
1953 | 2429 | ||
1954 | /* configuration hooks */ | 2430 | /* configuration hooks */ |
@@ -2032,13 +2508,6 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | |||
2032 | ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; | 2508 | ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; |
2033 | } | 2509 | } |
2034 | 2510 | ||
2035 | if (netif_running(sdata->dev)) { | ||
2036 | if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) { | ||
2037 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " | ||
2038 | "the low-level driver\n", sdata->dev->name); | ||
2039 | } | ||
2040 | } | ||
2041 | |||
2042 | return ieee80211_sta_commit(sdata); | 2511 | return ieee80211_sta_commit(sdata); |
2043 | } | 2512 | } |
2044 | 2513 | ||
@@ -2047,6 +2516,13 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, | |||
2047 | { | 2516 | { |
2048 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2517 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2049 | 2518 | ||
2519 | if (len == 0 && ifmgd->extra_ie_len == 0) | ||
2520 | return -EALREADY; | ||
2521 | |||
2522 | if (len == ifmgd->extra_ie_len && ifmgd->extra_ie && | ||
2523 | memcmp(ifmgd->extra_ie, ie, len) == 0) | ||
2524 | return -EALREADY; | ||
2525 | |||
2050 | kfree(ifmgd->extra_ie); | 2526 | kfree(ifmgd->extra_ie); |
2051 | if (len == 0) { | 2527 | if (len == 0) { |
2052 | ifmgd->extra_ie = NULL; | 2528 | ifmgd->extra_ie = NULL; |
@@ -2068,9 +2544,6 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason | |||
2068 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", | 2544 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", |
2069 | sdata->dev->name, reason); | 2545 | sdata->dev->name, reason); |
2070 | 2546 | ||
2071 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
2072 | return -EINVAL; | ||
2073 | |||
2074 | ieee80211_set_disassoc(sdata, true, true, reason); | 2547 | ieee80211_set_disassoc(sdata, true, true, reason); |
2075 | return 0; | 2548 | return 0; |
2076 | } | 2549 | } |
@@ -2082,9 +2555,6 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | |||
2082 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", | 2555 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", |
2083 | sdata->dev->name, reason); | 2556 | sdata->dev->name, reason); |
2084 | 2557 | ||
2085 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
2086 | return -EINVAL; | ||
2087 | |||
2088 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED)) | 2558 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED)) |
2089 | return -ENOLINK; | 2559 | return -ENOLINK; |
2090 | 2560 | ||
@@ -2104,75 +2574,17 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) | |||
2104 | rcu_read_unlock(); | 2574 | rcu_read_unlock(); |
2105 | } | 2575 | } |
2106 | 2576 | ||
2107 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work) | 2577 | int ieee80211_max_network_latency(struct notifier_block *nb, |
2578 | unsigned long data, void *dummy) | ||
2108 | { | 2579 | { |
2580 | s32 latency_usec = (s32) data; | ||
2109 | struct ieee80211_local *local = | 2581 | struct ieee80211_local *local = |
2110 | container_of(work, struct ieee80211_local, | 2582 | container_of(nb, struct ieee80211_local, |
2111 | dynamic_ps_disable_work); | 2583 | network_latency_notifier); |
2112 | |||
2113 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
2114 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||
2115 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
2116 | } | ||
2117 | |||
2118 | ieee80211_wake_queues_by_reason(&local->hw, | ||
2119 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
2120 | } | ||
2121 | |||
2122 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | ||
2123 | { | ||
2124 | struct ieee80211_local *local = | ||
2125 | container_of(work, struct ieee80211_local, | ||
2126 | dynamic_ps_enable_work); | ||
2127 | /* XXX: using scan_sdata is completely broken! */ | ||
2128 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
2129 | |||
2130 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | ||
2131 | return; | ||
2132 | |||
2133 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && sdata) | ||
2134 | ieee80211_send_nullfunc(local, sdata, 1); | ||
2135 | |||
2136 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
2137 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
2138 | } | ||
2139 | |||
2140 | void ieee80211_dynamic_ps_timer(unsigned long data) | ||
2141 | { | ||
2142 | struct ieee80211_local *local = (void *) data; | ||
2143 | |||
2144 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); | ||
2145 | } | ||
2146 | |||
2147 | void ieee80211_send_nullfunc(struct ieee80211_local *local, | ||
2148 | struct ieee80211_sub_if_data *sdata, | ||
2149 | int powersave) | ||
2150 | { | ||
2151 | struct sk_buff *skb; | ||
2152 | struct ieee80211_hdr *nullfunc; | ||
2153 | __le16 fc; | ||
2154 | 2584 | ||
2155 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | 2585 | mutex_lock(&local->iflist_mtx); |
2156 | return; | 2586 | ieee80211_recalc_ps(local, latency_usec); |
2157 | 2587 | mutex_unlock(&local->iflist_mtx); | |
2158 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | ||
2159 | if (!skb) { | ||
2160 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
2161 | "frame\n", sdata->dev->name); | ||
2162 | return; | ||
2163 | } | ||
2164 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2165 | 2588 | ||
2166 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | 2589 | return 0; |
2167 | memset(nullfunc, 0, 24); | ||
2168 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | ||
2169 | IEEE80211_FCTL_TODS); | ||
2170 | if (powersave) | ||
2171 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
2172 | nullfunc->frame_control = fc; | ||
2173 | memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); | ||
2174 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); | ||
2175 | memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); | ||
2176 | |||
2177 | ieee80211_tx_skb(sdata, skb, 0); | ||
2178 | } | 2590 | } |