diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 243 |
1 files changed, 210 insertions, 33 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index fb89e1d0aa03..fdf432f14554 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -41,6 +41,15 @@ const unsigned char rfc1042_header[] __aligned(2) = | |||
41 | const unsigned char bridge_tunnel_header[] __aligned(2) = | 41 | const unsigned char bridge_tunnel_header[] __aligned(2) = |
42 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | 42 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; |
43 | 43 | ||
44 | struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) | ||
45 | { | ||
46 | struct ieee80211_local *local; | ||
47 | BUG_ON(!wiphy); | ||
48 | |||
49 | local = wiphy_priv(wiphy); | ||
50 | return &local->hw; | ||
51 | } | ||
52 | EXPORT_SYMBOL(wiphy_to_ieee80211_hw); | ||
44 | 53 | ||
45 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | 54 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, |
46 | enum nl80211_iftype type) | 55 | enum nl80211_iftype type) |
@@ -157,18 +166,13 @@ int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | |||
157 | 166 | ||
158 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) | 167 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) |
159 | { | 168 | { |
160 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; | 169 | struct sk_buff *skb = tx->skb; |
170 | struct ieee80211_hdr *hdr; | ||
161 | 171 | ||
162 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 172 | do { |
163 | if (tx->extra_frag) { | 173 | hdr = (struct ieee80211_hdr *) skb->data; |
164 | struct ieee80211_hdr *fhdr; | 174 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
165 | int i; | 175 | } while ((skb = skb->next)); |
166 | for (i = 0; i < tx->num_extra_frag; i++) { | ||
167 | fhdr = (struct ieee80211_hdr *) | ||
168 | tx->extra_frag[i]->data; | ||
169 | fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
170 | } | ||
171 | } | ||
172 | } | 176 | } |
173 | 177 | ||
174 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, | 178 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, |
@@ -335,21 +339,21 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
335 | { | 339 | { |
336 | struct ieee80211_local *local = hw_to_local(hw); | 340 | struct ieee80211_local *local = hw_to_local(hw); |
337 | 341 | ||
338 | /* we don't need to track ampdu queues */ | 342 | if (WARN_ON(queue >= hw->queues)) |
339 | if (queue < ieee80211_num_regular_queues(hw)) { | 343 | return; |
340 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | ||
341 | 344 | ||
342 | if (local->queue_stop_reasons[queue] != 0) | 345 | __clear_bit(reason, &local->queue_stop_reasons[queue]); |
343 | /* someone still has this queue stopped */ | ||
344 | return; | ||
345 | } | ||
346 | 346 | ||
347 | if (test_bit(queue, local->queues_pending)) { | 347 | if (!skb_queue_empty(&local->pending[queue]) && |
348 | set_bit(queue, local->queues_pending_run); | 348 | local->queue_stop_reasons[queue] == |
349 | BIT(IEEE80211_QUEUE_STOP_REASON_PENDING)) | ||
349 | tasklet_schedule(&local->tx_pending_tasklet); | 350 | tasklet_schedule(&local->tx_pending_tasklet); |
350 | } else { | 351 | |
351 | netif_wake_subqueue(local->mdev, queue); | 352 | if (local->queue_stop_reasons[queue] != 0) |
352 | } | 353 | /* someone still has this queue stopped */ |
354 | return; | ||
355 | |||
356 | netif_wake_subqueue(local->mdev, queue); | ||
353 | } | 357 | } |
354 | 358 | ||
355 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 359 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
@@ -375,11 +379,18 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
375 | { | 379 | { |
376 | struct ieee80211_local *local = hw_to_local(hw); | 380 | struct ieee80211_local *local = hw_to_local(hw); |
377 | 381 | ||
378 | /* we don't need to track ampdu queues */ | 382 | if (WARN_ON(queue >= hw->queues)) |
379 | if (queue < ieee80211_num_regular_queues(hw)) | 383 | return; |
380 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 384 | |
385 | /* | ||
386 | * Only stop if it was previously running, this is necessary | ||
387 | * for correct pending packets handling because there we may | ||
388 | * start (but not wake) the queue and rely on that. | ||
389 | */ | ||
390 | if (!local->queue_stop_reasons[queue]) | ||
391 | netif_stop_subqueue(local->mdev, queue); | ||
381 | 392 | ||
382 | netif_stop_subqueue(local->mdev, queue); | 393 | __set_bit(reason, &local->queue_stop_reasons[queue]); |
383 | } | 394 | } |
384 | 395 | ||
385 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 396 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
@@ -409,7 +420,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | |||
409 | 420 | ||
410 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 421 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
411 | 422 | ||
412 | for (i = 0; i < ieee80211_num_queues(hw); i++) | 423 | for (i = 0; i < hw->queues; i++) |
413 | __ieee80211_stop_queue(hw, i, reason); | 424 | __ieee80211_stop_queue(hw, i, reason); |
414 | 425 | ||
415 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 426 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
@@ -425,6 +436,10 @@ EXPORT_SYMBOL(ieee80211_stop_queues); | |||
425 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) | 436 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) |
426 | { | 437 | { |
427 | struct ieee80211_local *local = hw_to_local(hw); | 438 | struct ieee80211_local *local = hw_to_local(hw); |
439 | |||
440 | if (WARN_ON(queue >= hw->queues)) | ||
441 | return true; | ||
442 | |||
428 | return __netif_subqueue_stopped(local->mdev, queue); | 443 | return __netif_subqueue_stopped(local->mdev, queue); |
429 | } | 444 | } |
430 | EXPORT_SYMBOL(ieee80211_queue_stopped); | 445 | EXPORT_SYMBOL(ieee80211_queue_stopped); |
@@ -438,7 +453,7 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | |||
438 | 453 | ||
439 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 454 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
440 | 455 | ||
441 | for (i = 0; i < hw->queues + hw->ampdu_queues; i++) | 456 | for (i = 0; i < hw->queues; i++) |
442 | __ieee80211_wake_queue(hw, i, reason); | 457 | __ieee80211_wake_queue(hw, i, reason); |
443 | 458 | ||
444 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 459 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
@@ -459,7 +474,7 @@ void ieee80211_iterate_active_interfaces( | |||
459 | struct ieee80211_local *local = hw_to_local(hw); | 474 | struct ieee80211_local *local = hw_to_local(hw); |
460 | struct ieee80211_sub_if_data *sdata; | 475 | struct ieee80211_sub_if_data *sdata; |
461 | 476 | ||
462 | rtnl_lock(); | 477 | mutex_lock(&local->iflist_mtx); |
463 | 478 | ||
464 | list_for_each_entry(sdata, &local->interfaces, list) { | 479 | list_for_each_entry(sdata, &local->interfaces, list) { |
465 | switch (sdata->vif.type) { | 480 | switch (sdata->vif.type) { |
@@ -480,7 +495,7 @@ void ieee80211_iterate_active_interfaces( | |||
480 | &sdata->vif); | 495 | &sdata->vif); |
481 | } | 496 | } |
482 | 497 | ||
483 | rtnl_unlock(); | 498 | mutex_unlock(&local->iflist_mtx); |
484 | } | 499 | } |
485 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); | 500 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); |
486 | 501 | ||
@@ -653,6 +668,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | |||
653 | elems->pwr_constr_elem = pos; | 668 | elems->pwr_constr_elem = pos; |
654 | elems->pwr_constr_elem_len = elen; | 669 | elems->pwr_constr_elem_len = elen; |
655 | break; | 670 | break; |
671 | case WLAN_EID_TIMEOUT_INTERVAL: | ||
672 | elems->timeout_int = pos; | ||
673 | elems->timeout_int_len = elen; | ||
674 | break; | ||
656 | default: | 675 | default: |
657 | break; | 676 | break; |
658 | } | 677 | } |
@@ -688,6 +707,27 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | |||
688 | local->ops->conf_tx(local_to_hw(local), i, &qparam); | 707 | local->ops->conf_tx(local_to_hw(local), i, &qparam); |
689 | } | 708 | } |
690 | 709 | ||
710 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | ||
711 | const size_t supp_rates_len, | ||
712 | const u8 *supp_rates) | ||
713 | { | ||
714 | struct ieee80211_local *local = sdata->local; | ||
715 | int i, have_higher_than_11mbit = 0; | ||
716 | |||
717 | /* cf. IEEE 802.11 9.2.12 */ | ||
718 | for (i = 0; i < supp_rates_len; i++) | ||
719 | if ((supp_rates[i] & 0x7f) * 5 > 110) | ||
720 | have_higher_than_11mbit = 1; | ||
721 | |||
722 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | ||
723 | have_higher_than_11mbit) | ||
724 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
725 | else | ||
726 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | ||
727 | |||
728 | ieee80211_set_wmm_default(sdata); | ||
729 | } | ||
730 | |||
691 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 731 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
692 | int encrypt) | 732 | int encrypt) |
693 | { | 733 | { |
@@ -727,12 +767,12 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) | |||
727 | return ret; | 767 | return ret; |
728 | } | 768 | } |
729 | 769 | ||
730 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, | 770 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, |
731 | enum ieee80211_band band) | 771 | enum ieee80211_band band) |
732 | { | 772 | { |
733 | struct ieee80211_supported_band *sband; | 773 | struct ieee80211_supported_band *sband; |
734 | struct ieee80211_rate *bitrates; | 774 | struct ieee80211_rate *bitrates; |
735 | u64 mandatory_rates; | 775 | u32 mandatory_rates; |
736 | enum ieee80211_rate_flags mandatory_flag; | 776 | enum ieee80211_rate_flags mandatory_flag; |
737 | int i; | 777 | int i; |
738 | 778 | ||
@@ -754,3 +794,140 @@ u64 ieee80211_mandatory_rates(struct ieee80211_local *local, | |||
754 | mandatory_rates |= BIT(i); | 794 | mandatory_rates |= BIT(i); |
755 | return mandatory_rates; | 795 | return mandatory_rates; |
756 | } | 796 | } |
797 | |||
798 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
799 | u16 transaction, u16 auth_alg, | ||
800 | u8 *extra, size_t extra_len, | ||
801 | const u8 *bssid, int encrypt) | ||
802 | { | ||
803 | struct ieee80211_local *local = sdata->local; | ||
804 | struct sk_buff *skb; | ||
805 | struct ieee80211_mgmt *mgmt; | ||
806 | |||
807 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
808 | sizeof(*mgmt) + 6 + extra_len); | ||
809 | if (!skb) { | ||
810 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
811 | "frame\n", sdata->dev->name); | ||
812 | return; | ||
813 | } | ||
814 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
815 | |||
816 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | ||
817 | memset(mgmt, 0, 24 + 6); | ||
818 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
819 | IEEE80211_STYPE_AUTH); | ||
820 | if (encrypt) | ||
821 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
822 | memcpy(mgmt->da, bssid, ETH_ALEN); | ||
823 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
824 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
825 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); | ||
826 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
827 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
828 | if (extra) | ||
829 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
830 | |||
831 | ieee80211_tx_skb(sdata, skb, encrypt); | ||
832 | } | ||
833 | |||
834 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
835 | u8 *ssid, size_t ssid_len, | ||
836 | u8 *ie, size_t ie_len) | ||
837 | { | ||
838 | struct ieee80211_local *local = sdata->local; | ||
839 | struct ieee80211_supported_band *sband; | ||
840 | struct sk_buff *skb; | ||
841 | struct ieee80211_mgmt *mgmt; | ||
842 | u8 *pos, *supp_rates, *esupp_rates = NULL; | ||
843 | int i; | ||
844 | |||
845 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | ||
846 | ie_len); | ||
847 | if (!skb) { | ||
848 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
849 | "request\n", sdata->dev->name); | ||
850 | return; | ||
851 | } | ||
852 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
853 | |||
854 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
855 | memset(mgmt, 0, 24); | ||
856 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
857 | IEEE80211_STYPE_PROBE_REQ); | ||
858 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
859 | if (dst) { | ||
860 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
861 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
862 | } else { | ||
863 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
864 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
865 | } | ||
866 | pos = skb_put(skb, 2 + ssid_len); | ||
867 | *pos++ = WLAN_EID_SSID; | ||
868 | *pos++ = ssid_len; | ||
869 | memcpy(pos, ssid, ssid_len); | ||
870 | |||
871 | supp_rates = skb_put(skb, 2); | ||
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 | |||
896 | ieee80211_tx_skb(sdata, skb, 0); | ||
897 | } | ||
898 | |||
899 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
900 | struct ieee802_11_elems *elems, | ||
901 | enum ieee80211_band band) | ||
902 | { | ||
903 | struct ieee80211_supported_band *sband; | ||
904 | struct ieee80211_rate *bitrates; | ||
905 | size_t num_rates; | ||
906 | u32 supp_rates; | ||
907 | int i, j; | ||
908 | sband = local->hw.wiphy->bands[band]; | ||
909 | |||
910 | if (!sband) { | ||
911 | WARN_ON(1); | ||
912 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
913 | } | ||
914 | |||
915 | bitrates = sband->bitrates; | ||
916 | num_rates = sband->n_bitrates; | ||
917 | supp_rates = 0; | ||
918 | for (i = 0; i < elems->supp_rates_len + | ||
919 | elems->ext_supp_rates_len; i++) { | ||
920 | u8 rate = 0; | ||
921 | int own_rate; | ||
922 | if (i < elems->supp_rates_len) | ||
923 | rate = elems->supp_rates[i]; | ||
924 | else if (elems->ext_supp_rates) | ||
925 | rate = elems->ext_supp_rates | ||
926 | [i - elems->supp_rates_len]; | ||
927 | own_rate = 5 * (rate & 0x7f); | ||
928 | for (j = 0; j < num_rates; j++) | ||
929 | if (bitrates[j].bitrate == own_rate) | ||
930 | supp_rates |= BIT(j); | ||
931 | } | ||
932 | return supp_rates; | ||
933 | } | ||