diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 476 |
1 files changed, 333 insertions, 143 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index fdf432f14554..915e77769312 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -20,27 +20,21 @@ | |||
20 | #include <linux/if_arp.h> | 20 | #include <linux/if_arp.h> |
21 | #include <linux/wireless.h> | 21 | #include <linux/wireless.h> |
22 | #include <linux/bitmap.h> | 22 | #include <linux/bitmap.h> |
23 | #include <linux/crc32.h> | ||
23 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
24 | #include <net/cfg80211.h> | 25 | #include <net/cfg80211.h> |
25 | #include <net/rtnetlink.h> | 26 | #include <net/rtnetlink.h> |
26 | 27 | ||
27 | #include "ieee80211_i.h" | 28 | #include "ieee80211_i.h" |
29 | #include "driver-ops.h" | ||
28 | #include "rate.h" | 30 | #include "rate.h" |
29 | #include "mesh.h" | 31 | #include "mesh.h" |
30 | #include "wme.h" | 32 | #include "wme.h" |
33 | #include "led.h" | ||
31 | 34 | ||
32 | /* privid for wiphys to determine whether they belong to us or not */ | 35 | /* privid for wiphys to determine whether they belong to us or not */ |
33 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; | 36 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; |
34 | 37 | ||
35 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | ||
36 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | ||
37 | const unsigned char rfc1042_header[] __aligned(2) = | ||
38 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | ||
39 | |||
40 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | ||
41 | const unsigned char bridge_tunnel_header[] __aligned(2) = | ||
42 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | ||
43 | |||
44 | struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) | 38 | struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) |
45 | { | 39 | { |
46 | struct ieee80211_local *local; | 40 | struct ieee80211_local *local; |
@@ -100,70 +94,6 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | |||
100 | return NULL; | 94 | return NULL; |
101 | } | 95 | } |
102 | 96 | ||
103 | unsigned int ieee80211_hdrlen(__le16 fc) | ||
104 | { | ||
105 | unsigned int hdrlen = 24; | ||
106 | |||
107 | if (ieee80211_is_data(fc)) { | ||
108 | if (ieee80211_has_a4(fc)) | ||
109 | hdrlen = 30; | ||
110 | if (ieee80211_is_data_qos(fc)) | ||
111 | hdrlen += IEEE80211_QOS_CTL_LEN; | ||
112 | goto out; | ||
113 | } | ||
114 | |||
115 | if (ieee80211_is_ctl(fc)) { | ||
116 | /* | ||
117 | * ACK and CTS are 10 bytes, all others 16. To see how | ||
118 | * to get this condition consider | ||
119 | * subtype mask: 0b0000000011110000 (0x00F0) | ||
120 | * ACK subtype: 0b0000000011010000 (0x00D0) | ||
121 | * CTS subtype: 0b0000000011000000 (0x00C0) | ||
122 | * bits that matter: ^^^ (0x00E0) | ||
123 | * value of those: 0b0000000011000000 (0x00C0) | ||
124 | */ | ||
125 | if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) | ||
126 | hdrlen = 10; | ||
127 | else | ||
128 | hdrlen = 16; | ||
129 | } | ||
130 | out: | ||
131 | return hdrlen; | ||
132 | } | ||
133 | EXPORT_SYMBOL(ieee80211_hdrlen); | ||
134 | |||
135 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) | ||
136 | { | ||
137 | const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)skb->data; | ||
138 | unsigned int hdrlen; | ||
139 | |||
140 | if (unlikely(skb->len < 10)) | ||
141 | return 0; | ||
142 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
143 | if (unlikely(hdrlen > skb->len)) | ||
144 | return 0; | ||
145 | return hdrlen; | ||
146 | } | ||
147 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | ||
148 | |||
149 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | ||
150 | { | ||
151 | int ae = meshhdr->flags & IEEE80211S_FLAGS_AE; | ||
152 | /* 7.1.3.5a.2 */ | ||
153 | switch (ae) { | ||
154 | case 0: | ||
155 | return 6; | ||
156 | case 1: | ||
157 | return 12; | ||
158 | case 2: | ||
159 | return 18; | ||
160 | case 3: | ||
161 | return 24; | ||
162 | default: | ||
163 | return 6; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) | 97 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) |
168 | { | 98 | { |
169 | struct sk_buff *skb = tx->skb; | 99 | struct sk_buff *skb = tx->skb; |
@@ -411,6 +341,52 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) | |||
411 | } | 341 | } |
412 | EXPORT_SYMBOL(ieee80211_stop_queue); | 342 | EXPORT_SYMBOL(ieee80211_stop_queue); |
413 | 343 | ||
344 | void ieee80211_add_pending_skb(struct ieee80211_local *local, | ||
345 | struct sk_buff *skb) | ||
346 | { | ||
347 | struct ieee80211_hw *hw = &local->hw; | ||
348 | unsigned long flags; | ||
349 | int queue = skb_get_queue_mapping(skb); | ||
350 | |||
351 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
352 | __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | ||
353 | __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING); | ||
354 | skb_queue_tail(&local->pending[queue], skb); | ||
355 | __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | ||
356 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
357 | } | ||
358 | |||
359 | int ieee80211_add_pending_skbs(struct ieee80211_local *local, | ||
360 | struct sk_buff_head *skbs) | ||
361 | { | ||
362 | struct ieee80211_hw *hw = &local->hw; | ||
363 | struct sk_buff *skb; | ||
364 | unsigned long flags; | ||
365 | int queue, ret = 0, i; | ||
366 | |||
367 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
368 | for (i = 0; i < hw->queues; i++) | ||
369 | __ieee80211_stop_queue(hw, i, | ||
370 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | ||
371 | |||
372 | while ((skb = skb_dequeue(skbs))) { | ||
373 | ret++; | ||
374 | queue = skb_get_queue_mapping(skb); | ||
375 | skb_queue_tail(&local->pending[queue], skb); | ||
376 | } | ||
377 | |||
378 | for (i = 0; i < hw->queues; i++) { | ||
379 | if (ret) | ||
380 | __ieee80211_stop_queue(hw, i, | ||
381 | IEEE80211_QUEUE_STOP_REASON_PENDING); | ||
382 | __ieee80211_wake_queue(hw, i, | ||
383 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | ||
384 | } | ||
385 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
386 | |||
387 | return ret; | ||
388 | } | ||
389 | |||
414 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 390 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
415 | enum queue_stop_reason reason) | 391 | enum queue_stop_reason reason) |
416 | { | 392 | { |
@@ -536,8 +512,16 @@ EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); | |||
536 | void ieee802_11_parse_elems(u8 *start, size_t len, | 512 | void ieee802_11_parse_elems(u8 *start, size_t len, |
537 | struct ieee802_11_elems *elems) | 513 | struct ieee802_11_elems *elems) |
538 | { | 514 | { |
515 | ieee802_11_parse_elems_crc(start, len, elems, 0, 0); | ||
516 | } | ||
517 | |||
518 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | ||
519 | struct ieee802_11_elems *elems, | ||
520 | u64 filter, u32 crc) | ||
521 | { | ||
539 | size_t left = len; | 522 | size_t left = len; |
540 | u8 *pos = start; | 523 | u8 *pos = start; |
524 | bool calc_crc = filter != 0; | ||
541 | 525 | ||
542 | memset(elems, 0, sizeof(*elems)); | 526 | memset(elems, 0, sizeof(*elems)); |
543 | elems->ie_start = start; | 527 | elems->ie_start = start; |
@@ -551,7 +535,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | |||
551 | left -= 2; | 535 | left -= 2; |
552 | 536 | ||
553 | if (elen > left) | 537 | if (elen > left) |
554 | return; | 538 | break; |
539 | |||
540 | if (calc_crc && id < 64 && (filter & BIT(id))) | ||
541 | crc = crc32_be(crc, pos - 2, elen + 2); | ||
555 | 542 | ||
556 | switch (id) { | 543 | switch (id) { |
557 | case WLAN_EID_SSID: | 544 | case WLAN_EID_SSID: |
@@ -575,8 +562,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | |||
575 | elems->cf_params_len = elen; | 562 | elems->cf_params_len = elen; |
576 | break; | 563 | break; |
577 | case WLAN_EID_TIM: | 564 | case WLAN_EID_TIM: |
578 | elems->tim = pos; | 565 | if (elen >= sizeof(struct ieee80211_tim_ie)) { |
579 | elems->tim_len = elen; | 566 | elems->tim = (void *)pos; |
567 | elems->tim_len = elen; | ||
568 | } | ||
580 | break; | 569 | break; |
581 | case WLAN_EID_IBSS_PARAMS: | 570 | case WLAN_EID_IBSS_PARAMS: |
582 | elems->ibss_params = pos; | 571 | elems->ibss_params = pos; |
@@ -586,15 +575,20 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | |||
586 | elems->challenge = pos; | 575 | elems->challenge = pos; |
587 | elems->challenge_len = elen; | 576 | elems->challenge_len = elen; |
588 | break; | 577 | break; |
589 | case WLAN_EID_WPA: | 578 | case WLAN_EID_VENDOR_SPECIFIC: |
590 | if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && | 579 | if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && |
591 | pos[2] == 0xf2) { | 580 | pos[2] == 0xf2) { |
592 | /* Microsoft OUI (00:50:F2) */ | 581 | /* Microsoft OUI (00:50:F2) */ |
582 | |||
583 | if (calc_crc) | ||
584 | crc = crc32_be(crc, pos - 2, elen + 2); | ||
585 | |||
593 | if (pos[3] == 1) { | 586 | if (pos[3] == 1) { |
594 | /* OUI Type 1 - WPA IE */ | 587 | /* OUI Type 1 - WPA IE */ |
595 | elems->wpa = pos; | 588 | elems->wpa = pos; |
596 | elems->wpa_len = elen; | 589 | elems->wpa_len = elen; |
597 | } else if (elen >= 5 && pos[3] == 2) { | 590 | } else if (elen >= 5 && pos[3] == 2) { |
591 | /* OUI Type 2 - WMM IE */ | ||
598 | if (pos[4] == 0) { | 592 | if (pos[4] == 0) { |
599 | elems->wmm_info = pos; | 593 | elems->wmm_info = pos; |
600 | elems->wmm_info_len = elen; | 594 | elems->wmm_info_len = elen; |
@@ -679,32 +673,70 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | |||
679 | left -= elen; | 673 | left -= elen; |
680 | pos += elen; | 674 | pos += elen; |
681 | } | 675 | } |
676 | |||
677 | return crc; | ||
682 | } | 678 | } |
683 | 679 | ||
684 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | 680 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) |
685 | { | 681 | { |
686 | struct ieee80211_local *local = sdata->local; | 682 | struct ieee80211_local *local = sdata->local; |
687 | struct ieee80211_tx_queue_params qparam; | 683 | struct ieee80211_tx_queue_params qparam; |
688 | int i; | 684 | int queue; |
685 | bool use_11b; | ||
686 | int aCWmin, aCWmax; | ||
689 | 687 | ||
690 | if (!local->ops->conf_tx) | 688 | if (!local->ops->conf_tx) |
691 | return; | 689 | return; |
692 | 690 | ||
693 | memset(&qparam, 0, sizeof(qparam)); | 691 | memset(&qparam, 0, sizeof(qparam)); |
694 | 692 | ||
695 | qparam.aifs = 2; | 693 | use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && |
696 | 694 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); | |
697 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | ||
698 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) | ||
699 | qparam.cw_min = 31; | ||
700 | else | ||
701 | qparam.cw_min = 15; | ||
702 | 695 | ||
703 | qparam.cw_max = 1023; | 696 | for (queue = 0; queue < local_to_hw(local)->queues; queue++) { |
704 | qparam.txop = 0; | 697 | /* Set defaults according to 802.11-2007 Table 7-37 */ |
698 | aCWmax = 1023; | ||
699 | if (use_11b) | ||
700 | aCWmin = 31; | ||
701 | else | ||
702 | aCWmin = 15; | ||
703 | |||
704 | switch (queue) { | ||
705 | case 3: /* AC_BK */ | ||
706 | qparam.cw_max = aCWmax; | ||
707 | qparam.cw_min = aCWmin; | ||
708 | qparam.txop = 0; | ||
709 | qparam.aifs = 7; | ||
710 | break; | ||
711 | default: /* never happens but let's not leave undefined */ | ||
712 | case 2: /* AC_BE */ | ||
713 | qparam.cw_max = aCWmax; | ||
714 | qparam.cw_min = aCWmin; | ||
715 | qparam.txop = 0; | ||
716 | qparam.aifs = 3; | ||
717 | break; | ||
718 | case 1: /* AC_VI */ | ||
719 | qparam.cw_max = aCWmin; | ||
720 | qparam.cw_min = (aCWmin + 1) / 2 - 1; | ||
721 | if (use_11b) | ||
722 | qparam.txop = 6016/32; | ||
723 | else | ||
724 | qparam.txop = 3008/32; | ||
725 | qparam.aifs = 2; | ||
726 | break; | ||
727 | case 0: /* AC_VO */ | ||
728 | qparam.cw_max = (aCWmin + 1) / 2 - 1; | ||
729 | qparam.cw_min = (aCWmin + 1) / 4 - 1; | ||
730 | if (use_11b) | ||
731 | qparam.txop = 3264/32; | ||
732 | else | ||
733 | qparam.txop = 1504/32; | ||
734 | qparam.aifs = 2; | ||
735 | break; | ||
736 | } | ||
705 | 737 | ||
706 | for (i = 0; i < local_to_hw(local)->queues; i++) | 738 | drv_conf_tx(local, queue, &qparam); |
707 | local->ops->conf_tx(local_to_hw(local), i, &qparam); | 739 | } |
708 | } | 740 | } |
709 | 741 | ||
710 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 742 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, |
@@ -742,31 +774,6 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
742 | dev_queue_xmit(skb); | 774 | dev_queue_xmit(skb); |
743 | } | 775 | } |
744 | 776 | ||
745 | int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) | ||
746 | { | ||
747 | int ret = -EINVAL; | ||
748 | struct ieee80211_channel *chan; | ||
749 | struct ieee80211_local *local = sdata->local; | ||
750 | |||
751 | chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); | ||
752 | |||
753 | if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { | ||
754 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | ||
755 | chan->flags & IEEE80211_CHAN_NO_IBSS) | ||
756 | return ret; | ||
757 | local->oper_channel = chan; | ||
758 | local->oper_channel_type = NL80211_CHAN_NO_HT; | ||
759 | |||
760 | if (local->sw_scanning || local->hw_scanning) | ||
761 | ret = 0; | ||
762 | else | ||
763 | ret = ieee80211_hw_config( | ||
764 | local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
765 | } | ||
766 | |||
767 | return ret; | ||
768 | } | ||
769 | |||
770 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | 777 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, |
771 | enum ieee80211_band band) | 778 | enum ieee80211_band band) |
772 | { | 779 | { |
@@ -831,16 +838,73 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
831 | ieee80211_tx_skb(sdata, skb, encrypt); | 838 | ieee80211_tx_skb(sdata, skb, encrypt); |
832 | } | 839 | } |
833 | 840 | ||
841 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | ||
842 | const u8 *ie, size_t ie_len) | ||
843 | { | ||
844 | struct ieee80211_supported_band *sband; | ||
845 | u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; | ||
846 | int i; | ||
847 | |||
848 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
849 | |||
850 | pos = buffer; | ||
851 | |||
852 | *pos++ = WLAN_EID_SUPP_RATES; | ||
853 | supp_rates_len = pos; | ||
854 | *pos++ = 0; | ||
855 | |||
856 | for (i = 0; i < sband->n_bitrates; i++) { | ||
857 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
858 | |||
859 | if (esupp_rates_len) { | ||
860 | *esupp_rates_len += 1; | ||
861 | } else if (*supp_rates_len == 8) { | ||
862 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
863 | esupp_rates_len = pos; | ||
864 | *pos++ = 1; | ||
865 | } else | ||
866 | *supp_rates_len += 1; | ||
867 | |||
868 | *pos++ = rate->bitrate / 5; | ||
869 | } | ||
870 | |||
871 | if (sband->ht_cap.ht_supported) { | ||
872 | __le16 tmp = cpu_to_le16(sband->ht_cap.cap); | ||
873 | |||
874 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
875 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
876 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | ||
877 | memcpy(pos, &tmp, sizeof(u16)); | ||
878 | pos += sizeof(u16); | ||
879 | /* TODO: needs a define here for << 2 */ | ||
880 | *pos++ = sband->ht_cap.ampdu_factor | | ||
881 | (sband->ht_cap.ampdu_density << 2); | ||
882 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | ||
883 | pos += sizeof(sband->ht_cap.mcs); | ||
884 | pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ | ||
885 | } | ||
886 | |||
887 | /* | ||
888 | * If adding more here, adjust code in main.c | ||
889 | * that calculates local->scan_ies_len. | ||
890 | */ | ||
891 | |||
892 | if (ie) { | ||
893 | memcpy(pos, ie, ie_len); | ||
894 | pos += ie_len; | ||
895 | } | ||
896 | |||
897 | return pos - buffer; | ||
898 | } | ||
899 | |||
834 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 900 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
835 | u8 *ssid, size_t ssid_len, | 901 | const u8 *ssid, size_t ssid_len, |
836 | u8 *ie, size_t ie_len) | 902 | const u8 *ie, size_t ie_len) |
837 | { | 903 | { |
838 | struct ieee80211_local *local = sdata->local; | 904 | struct ieee80211_local *local = sdata->local; |
839 | struct ieee80211_supported_band *sband; | ||
840 | struct sk_buff *skb; | 905 | struct sk_buff *skb; |
841 | struct ieee80211_mgmt *mgmt; | 906 | struct ieee80211_mgmt *mgmt; |
842 | u8 *pos, *supp_rates, *esupp_rates = NULL; | 907 | u8 *pos; |
843 | int i; | ||
844 | 908 | ||
845 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | 909 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + |
846 | ie_len); | 910 | ie_len); |
@@ -867,31 +931,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
867 | *pos++ = WLAN_EID_SSID; | 931 | *pos++ = WLAN_EID_SSID; |
868 | *pos++ = ssid_len; | 932 | *pos++ = ssid_len; |
869 | memcpy(pos, ssid, ssid_len); | 933 | memcpy(pos, ssid, ssid_len); |
934 | pos += ssid_len; | ||
870 | 935 | ||
871 | supp_rates = skb_put(skb, 2); | 936 | skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len)); |
872 | supp_rates[0] = WLAN_EID_SUPP_RATES; | ||
873 | supp_rates[1] = 0; | ||
874 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
875 | |||
876 | for (i = 0; i < sband->n_bitrates; i++) { | ||
877 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
878 | if (esupp_rates) { | ||
879 | pos = skb_put(skb, 1); | ||
880 | esupp_rates[1]++; | ||
881 | } else if (supp_rates[1] == 8) { | ||
882 | esupp_rates = skb_put(skb, 3); | ||
883 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | ||
884 | esupp_rates[1] = 1; | ||
885 | pos = &esupp_rates[2]; | ||
886 | } else { | ||
887 | pos = skb_put(skb, 1); | ||
888 | supp_rates[1]++; | ||
889 | } | ||
890 | *pos = rate->bitrate / 5; | ||
891 | } | ||
892 | |||
893 | if (ie) | ||
894 | memcpy(skb_put(skb, ie_len), ie, ie_len); | ||
895 | 937 | ||
896 | ieee80211_tx_skb(sdata, skb, 0); | 938 | ieee80211_tx_skb(sdata, skb, 0); |
897 | } | 939 | } |
@@ -931,3 +973,151 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
931 | } | 973 | } |
932 | return supp_rates; | 974 | return supp_rates; |
933 | } | 975 | } |
976 | |||
977 | int ieee80211_reconfig(struct ieee80211_local *local) | ||
978 | { | ||
979 | struct ieee80211_hw *hw = &local->hw; | ||
980 | struct ieee80211_sub_if_data *sdata; | ||
981 | struct ieee80211_if_init_conf conf; | ||
982 | struct sta_info *sta; | ||
983 | unsigned long flags; | ||
984 | int res; | ||
985 | bool from_suspend = local->suspended; | ||
986 | |||
987 | /* | ||
988 | * We're going to start the hardware, at that point | ||
989 | * we are no longer suspended and can RX frames. | ||
990 | */ | ||
991 | local->suspended = false; | ||
992 | |||
993 | /* restart hardware */ | ||
994 | if (local->open_count) { | ||
995 | res = drv_start(local); | ||
996 | |||
997 | ieee80211_led_radio(local, true); | ||
998 | } | ||
999 | |||
1000 | /* add interfaces */ | ||
1001 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1002 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
1003 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||
1004 | netif_running(sdata->dev)) { | ||
1005 | conf.vif = &sdata->vif; | ||
1006 | conf.type = sdata->vif.type; | ||
1007 | conf.mac_addr = sdata->dev->dev_addr; | ||
1008 | res = drv_add_interface(local, &conf); | ||
1009 | } | ||
1010 | } | ||
1011 | |||
1012 | /* add STAs back */ | ||
1013 | if (local->ops->sta_notify) { | ||
1014 | spin_lock_irqsave(&local->sta_lock, flags); | ||
1015 | list_for_each_entry(sta, &local->sta_list, list) { | ||
1016 | sdata = sta->sdata; | ||
1017 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
1018 | sdata = container_of(sdata->bss, | ||
1019 | struct ieee80211_sub_if_data, | ||
1020 | u.ap); | ||
1021 | |||
1022 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, | ||
1023 | &sta->sta); | ||
1024 | } | ||
1025 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
1026 | } | ||
1027 | |||
1028 | /* Clear Suspend state so that ADDBA requests can be processed */ | ||
1029 | |||
1030 | rcu_read_lock(); | ||
1031 | |||
1032 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
1033 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
1034 | clear_sta_flags(sta, WLAN_STA_SUSPEND); | ||
1035 | } | ||
1036 | } | ||
1037 | |||
1038 | rcu_read_unlock(); | ||
1039 | |||
1040 | /* setup RTS threshold */ | ||
1041 | drv_set_rts_threshold(local, hw->wiphy->rts_threshold); | ||
1042 | |||
1043 | /* reconfigure hardware */ | ||
1044 | ieee80211_hw_config(local, ~0); | ||
1045 | |||
1046 | netif_addr_lock_bh(local->mdev); | ||
1047 | ieee80211_configure_filter(local); | ||
1048 | netif_addr_unlock_bh(local->mdev); | ||
1049 | |||
1050 | /* Finally also reconfigure all the BSS information */ | ||
1051 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1052 | u32 changed = ~0; | ||
1053 | if (!netif_running(sdata->dev)) | ||
1054 | continue; | ||
1055 | switch (sdata->vif.type) { | ||
1056 | case NL80211_IFTYPE_STATION: | ||
1057 | /* disable beacon change bits */ | ||
1058 | changed &= ~(BSS_CHANGED_BEACON | | ||
1059 | BSS_CHANGED_BEACON_ENABLED); | ||
1060 | /* fall through */ | ||
1061 | case NL80211_IFTYPE_ADHOC: | ||
1062 | case NL80211_IFTYPE_AP: | ||
1063 | case NL80211_IFTYPE_MESH_POINT: | ||
1064 | ieee80211_bss_info_change_notify(sdata, changed); | ||
1065 | break; | ||
1066 | case NL80211_IFTYPE_WDS: | ||
1067 | break; | ||
1068 | case NL80211_IFTYPE_AP_VLAN: | ||
1069 | case NL80211_IFTYPE_MONITOR: | ||
1070 | /* ignore virtual */ | ||
1071 | break; | ||
1072 | case NL80211_IFTYPE_UNSPECIFIED: | ||
1073 | case __NL80211_IFTYPE_AFTER_LAST: | ||
1074 | WARN_ON(1); | ||
1075 | break; | ||
1076 | } | ||
1077 | } | ||
1078 | |||
1079 | /* add back keys */ | ||
1080 | list_for_each_entry(sdata, &local->interfaces, list) | ||
1081 | if (netif_running(sdata->dev)) | ||
1082 | ieee80211_enable_keys(sdata); | ||
1083 | |||
1084 | ieee80211_wake_queues_by_reason(hw, | ||
1085 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | ||
1086 | |||
1087 | /* | ||
1088 | * If this is for hw restart things are still running. | ||
1089 | * We may want to change that later, however. | ||
1090 | */ | ||
1091 | if (!from_suspend) | ||
1092 | return 0; | ||
1093 | |||
1094 | #ifdef CONFIG_PM | ||
1095 | local->suspended = false; | ||
1096 | |||
1097 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1098 | switch(sdata->vif.type) { | ||
1099 | case NL80211_IFTYPE_STATION: | ||
1100 | ieee80211_sta_restart(sdata); | ||
1101 | break; | ||
1102 | case NL80211_IFTYPE_ADHOC: | ||
1103 | ieee80211_ibss_restart(sdata); | ||
1104 | break; | ||
1105 | case NL80211_IFTYPE_MESH_POINT: | ||
1106 | ieee80211_mesh_restart(sdata); | ||
1107 | break; | ||
1108 | default: | ||
1109 | break; | ||
1110 | } | ||
1111 | } | ||
1112 | |||
1113 | add_timer(&local->sta_cleanup); | ||
1114 | |||
1115 | spin_lock_irqsave(&local->sta_lock, flags); | ||
1116 | list_for_each_entry(sta, &local->sta_list, list) | ||
1117 | mesh_plink_restart(sta); | ||
1118 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
1119 | #else | ||
1120 | WARN_ON(1); | ||
1121 | #endif | ||
1122 | return 0; | ||
1123 | } | ||