diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 363 |
1 files changed, 283 insertions, 80 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e6c08da8da26..53af57047435 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/skbuff.h> | 18 | #include <linux/skbuff.h> |
19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
20 | #include <linux/if_arp.h> | 20 | #include <linux/if_arp.h> |
21 | #include <linux/wireless.h> | ||
22 | #include <linux/bitmap.h> | 21 | #include <linux/bitmap.h> |
23 | #include <linux/crc32.h> | 22 | #include <linux/crc32.h> |
24 | #include <net/net_namespace.h> | 23 | #include <net/net_namespace.h> |
@@ -269,6 +268,7 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
269 | enum queue_stop_reason reason) | 268 | enum queue_stop_reason reason) |
270 | { | 269 | { |
271 | struct ieee80211_local *local = hw_to_local(hw); | 270 | struct ieee80211_local *local = hw_to_local(hw); |
271 | struct ieee80211_sub_if_data *sdata; | ||
272 | 272 | ||
273 | if (WARN_ON(queue >= hw->queues)) | 273 | if (WARN_ON(queue >= hw->queues)) |
274 | return; | 274 | return; |
@@ -279,7 +279,12 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
279 | /* someone still has this queue stopped */ | 279 | /* someone still has this queue stopped */ |
280 | return; | 280 | return; |
281 | 281 | ||
282 | if (!skb_queue_empty(&local->pending[queue])) | 282 | if (skb_queue_empty(&local->pending[queue])) { |
283 | rcu_read_lock(); | ||
284 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
285 | netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue)); | ||
286 | rcu_read_unlock(); | ||
287 | } else | ||
283 | tasklet_schedule(&local->tx_pending_tasklet); | 288 | tasklet_schedule(&local->tx_pending_tasklet); |
284 | } | 289 | } |
285 | 290 | ||
@@ -305,11 +310,17 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
305 | enum queue_stop_reason reason) | 310 | enum queue_stop_reason reason) |
306 | { | 311 | { |
307 | struct ieee80211_local *local = hw_to_local(hw); | 312 | struct ieee80211_local *local = hw_to_local(hw); |
313 | struct ieee80211_sub_if_data *sdata; | ||
308 | 314 | ||
309 | if (WARN_ON(queue >= hw->queues)) | 315 | if (WARN_ON(queue >= hw->queues)) |
310 | return; | 316 | return; |
311 | 317 | ||
312 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 318 | __set_bit(reason, &local->queue_stop_reasons[queue]); |
319 | |||
320 | rcu_read_lock(); | ||
321 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
322 | netif_tx_stop_queue(netdev_get_tx_queue(sdata->dev, queue)); | ||
323 | rcu_read_unlock(); | ||
313 | } | 324 | } |
314 | 325 | ||
315 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 326 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
@@ -468,8 +479,8 @@ void ieee80211_iterate_active_interfaces( | |||
468 | case NL80211_IFTYPE_MESH_POINT: | 479 | case NL80211_IFTYPE_MESH_POINT: |
469 | break; | 480 | break; |
470 | } | 481 | } |
471 | if (netif_running(sdata->dev)) | 482 | if (ieee80211_sdata_running(sdata)) |
472 | iterator(data, sdata->dev->dev_addr, | 483 | iterator(data, sdata->vif.addr, |
473 | &sdata->vif); | 484 | &sdata->vif); |
474 | } | 485 | } |
475 | 486 | ||
@@ -502,8 +513,8 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
502 | case NL80211_IFTYPE_MESH_POINT: | 513 | case NL80211_IFTYPE_MESH_POINT: |
503 | break; | 514 | break; |
504 | } | 515 | } |
505 | if (netif_running(sdata->dev)) | 516 | if (ieee80211_sdata_running(sdata)) |
506 | iterator(data, sdata->dev->dev_addr, | 517 | iterator(data, sdata->vif.addr, |
507 | &sdata->vif); | 518 | &sdata->vif); |
508 | } | 519 | } |
509 | 520 | ||
@@ -579,7 +590,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
579 | if (elen > left) | 590 | if (elen > left) |
580 | break; | 591 | break; |
581 | 592 | ||
582 | if (calc_crc && id < 64 && (filter & BIT(id))) | 593 | if (calc_crc && id < 64 && (filter & (1ULL << id))) |
583 | crc = crc32_be(crc, pos - 2, elen + 2); | 594 | crc = crc32_be(crc, pos - 2, elen + 2); |
584 | 595 | ||
585 | switch (id) { | 596 | switch (id) { |
@@ -666,8 +677,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
666 | elems->mesh_id_len = elen; | 677 | elems->mesh_id_len = elen; |
667 | break; | 678 | break; |
668 | case WLAN_EID_MESH_CONFIG: | 679 | case WLAN_EID_MESH_CONFIG: |
669 | elems->mesh_config = pos; | 680 | if (elen >= sizeof(struct ieee80211_meshconf_ie)) |
670 | elems->mesh_config_len = elen; | 681 | elems->mesh_config = (void *)pos; |
671 | break; | 682 | break; |
672 | case WLAN_EID_PEER_LINK: | 683 | case WLAN_EID_PEER_LINK: |
673 | elems->peer_link = pos; | 684 | elems->peer_link = pos; |
@@ -685,6 +696,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
685 | elems->perr = pos; | 696 | elems->perr = pos; |
686 | elems->perr_len = elen; | 697 | elems->perr_len = elen; |
687 | break; | 698 | break; |
699 | case WLAN_EID_RANN: | ||
700 | if (elen >= sizeof(struct ieee80211_rann_ie)) | ||
701 | elems->rann = (void *)pos; | ||
702 | break; | ||
688 | case WLAN_EID_CHANNEL_SWITCH: | 703 | case WLAN_EID_CHANNEL_SWITCH: |
689 | elems->ch_switch_elem = pos; | 704 | elems->ch_switch_elem = pos; |
690 | elems->ch_switch_elem_len = elen; | 705 | elems->ch_switch_elem_len = elen; |
@@ -777,6 +792,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | |||
777 | break; | 792 | break; |
778 | } | 793 | } |
779 | 794 | ||
795 | qparam.uapsd = false; | ||
796 | |||
780 | drv_conf_tx(local, queue, &qparam); | 797 | drv_conf_tx(local, queue, &qparam); |
781 | } | 798 | } |
782 | } | 799 | } |
@@ -844,7 +861,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
844 | sizeof(*mgmt) + 6 + extra_len); | 861 | sizeof(*mgmt) + 6 + extra_len); |
845 | if (!skb) { | 862 | if (!skb) { |
846 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | 863 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " |
847 | "frame\n", sdata->dev->name); | 864 | "frame\n", sdata->name); |
848 | return; | 865 | return; |
849 | } | 866 | } |
850 | skb_reserve(skb, local->hw.extra_tx_headroom); | 867 | skb_reserve(skb, local->hw.extra_tx_headroom); |
@@ -854,7 +871,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
854 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 871 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
855 | IEEE80211_STYPE_AUTH); | 872 | IEEE80211_STYPE_AUTH); |
856 | memcpy(mgmt->da, bssid, ETH_ALEN); | 873 | memcpy(mgmt->da, bssid, ETH_ALEN); |
857 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 874 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
858 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | 875 | memcpy(mgmt->bssid, bssid, ETH_ALEN); |
859 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); | 876 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); |
860 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | 877 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); |
@@ -868,50 +885,96 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
868 | WARN_ON(err); | 885 | WARN_ON(err); |
869 | } | 886 | } |
870 | 887 | ||
871 | ieee80211_tx_skb(sdata, skb, 0); | 888 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
889 | ieee80211_tx_skb(sdata, skb); | ||
872 | } | 890 | } |
873 | 891 | ||
874 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 892 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
875 | const u8 *ie, size_t ie_len) | 893 | const u8 *ie, size_t ie_len, |
894 | enum ieee80211_band band) | ||
876 | { | 895 | { |
877 | struct ieee80211_supported_band *sband; | 896 | struct ieee80211_supported_band *sband; |
878 | u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; | 897 | u8 *pos; |
879 | int i; | 898 | size_t offset = 0, noffset; |
899 | int supp_rates_len, i; | ||
880 | 900 | ||
881 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 901 | sband = local->hw.wiphy->bands[band]; |
882 | 902 | ||
883 | pos = buffer; | 903 | pos = buffer; |
884 | 904 | ||
905 | supp_rates_len = min_t(int, sband->n_bitrates, 8); | ||
906 | |||
885 | *pos++ = WLAN_EID_SUPP_RATES; | 907 | *pos++ = WLAN_EID_SUPP_RATES; |
886 | supp_rates_len = pos; | 908 | *pos++ = supp_rates_len; |
887 | *pos++ = 0; | ||
888 | |||
889 | for (i = 0; i < sband->n_bitrates; i++) { | ||
890 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
891 | |||
892 | if (esupp_rates_len) { | ||
893 | *esupp_rates_len += 1; | ||
894 | } else if (*supp_rates_len == 8) { | ||
895 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
896 | esupp_rates_len = pos; | ||
897 | *pos++ = 1; | ||
898 | } else | ||
899 | *supp_rates_len += 1; | ||
900 | 909 | ||
901 | *pos++ = rate->bitrate / 5; | 910 | for (i = 0; i < supp_rates_len; i++) { |
911 | int rate = sband->bitrates[i].bitrate; | ||
912 | *pos++ = (u8) (rate / 5); | ||
913 | } | ||
914 | |||
915 | /* insert "request information" if in custom IEs */ | ||
916 | if (ie && ie_len) { | ||
917 | static const u8 before_extrates[] = { | ||
918 | WLAN_EID_SSID, | ||
919 | WLAN_EID_SUPP_RATES, | ||
920 | WLAN_EID_REQUEST, | ||
921 | }; | ||
922 | noffset = ieee80211_ie_split(ie, ie_len, | ||
923 | before_extrates, | ||
924 | ARRAY_SIZE(before_extrates), | ||
925 | offset); | ||
926 | memcpy(pos, ie + offset, noffset - offset); | ||
927 | pos += noffset - offset; | ||
928 | offset = noffset; | ||
929 | } | ||
930 | |||
931 | if (sband->n_bitrates > i) { | ||
932 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
933 | *pos++ = sband->n_bitrates - i; | ||
934 | |||
935 | for (; i < sband->n_bitrates; i++) { | ||
936 | int rate = sband->bitrates[i].bitrate; | ||
937 | *pos++ = (u8) (rate / 5); | ||
938 | } | ||
939 | } | ||
940 | |||
941 | /* insert custom IEs that go before HT */ | ||
942 | if (ie && ie_len) { | ||
943 | static const u8 before_ht[] = { | ||
944 | WLAN_EID_SSID, | ||
945 | WLAN_EID_SUPP_RATES, | ||
946 | WLAN_EID_REQUEST, | ||
947 | WLAN_EID_EXT_SUPP_RATES, | ||
948 | WLAN_EID_DS_PARAMS, | ||
949 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
950 | }; | ||
951 | noffset = ieee80211_ie_split(ie, ie_len, | ||
952 | before_ht, ARRAY_SIZE(before_ht), | ||
953 | offset); | ||
954 | memcpy(pos, ie + offset, noffset - offset); | ||
955 | pos += noffset - offset; | ||
956 | offset = noffset; | ||
902 | } | 957 | } |
903 | 958 | ||
904 | if (sband->ht_cap.ht_supported) { | 959 | if (sband->ht_cap.ht_supported) { |
905 | __le16 tmp = cpu_to_le16(sband->ht_cap.cap); | 960 | u16 cap = sband->ht_cap.cap; |
961 | __le16 tmp; | ||
962 | |||
963 | if (ieee80211_disable_40mhz_24ghz && | ||
964 | sband->band == IEEE80211_BAND_2GHZ) { | ||
965 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
966 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
967 | } | ||
906 | 968 | ||
907 | *pos++ = WLAN_EID_HT_CAPABILITY; | 969 | *pos++ = WLAN_EID_HT_CAPABILITY; |
908 | *pos++ = sizeof(struct ieee80211_ht_cap); | 970 | *pos++ = sizeof(struct ieee80211_ht_cap); |
909 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | 971 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); |
972 | tmp = cpu_to_le16(cap); | ||
910 | memcpy(pos, &tmp, sizeof(u16)); | 973 | memcpy(pos, &tmp, sizeof(u16)); |
911 | pos += sizeof(u16); | 974 | pos += sizeof(u16); |
912 | /* TODO: needs a define here for << 2 */ | ||
913 | *pos++ = sband->ht_cap.ampdu_factor | | 975 | *pos++ = sband->ht_cap.ampdu_factor | |
914 | (sband->ht_cap.ampdu_density << 2); | 976 | (sband->ht_cap.ampdu_density << |
977 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); | ||
915 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 978 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); |
916 | pos += sizeof(sband->ht_cap.mcs); | 979 | pos += sizeof(sband->ht_cap.mcs); |
917 | pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ | 980 | pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ |
@@ -922,9 +985,11 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
922 | * that calculates local->scan_ies_len. | 985 | * that calculates local->scan_ies_len. |
923 | */ | 986 | */ |
924 | 987 | ||
925 | if (ie) { | 988 | /* add any remaining custom IEs */ |
926 | memcpy(pos, ie, ie_len); | 989 | if (ie && ie_len) { |
927 | pos += ie_len; | 990 | noffset = ie_len; |
991 | memcpy(pos, ie + offset, noffset - offset); | ||
992 | pos += noffset - offset; | ||
928 | } | 993 | } |
929 | 994 | ||
930 | return pos - buffer; | 995 | return pos - buffer; |
@@ -937,38 +1002,33 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
937 | struct ieee80211_local *local = sdata->local; | 1002 | struct ieee80211_local *local = sdata->local; |
938 | struct sk_buff *skb; | 1003 | struct sk_buff *skb; |
939 | struct ieee80211_mgmt *mgmt; | 1004 | struct ieee80211_mgmt *mgmt; |
940 | u8 *pos; | 1005 | size_t buf_len; |
941 | 1006 | u8 *buf; | |
942 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | 1007 | |
943 | ie_len); | 1008 | /* FIXME: come up with a proper value */ |
944 | if (!skb) { | 1009 | buf = kmalloc(200 + ie_len, GFP_KERNEL); |
945 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 1010 | if (!buf) { |
946 | "request\n", sdata->dev->name); | 1011 | printk(KERN_DEBUG "%s: failed to allocate temporary IE " |
1012 | "buffer\n", sdata->name); | ||
947 | return; | 1013 | return; |
948 | } | 1014 | } |
949 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
950 | 1015 | ||
951 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 1016 | buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, |
952 | memset(mgmt, 0, 24); | 1017 | local->hw.conf.channel->band); |
953 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 1018 | |
954 | IEEE80211_STYPE_PROBE_REQ); | 1019 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, |
955 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 1020 | ssid, ssid_len, |
1021 | buf, buf_len); | ||
1022 | |||
956 | if (dst) { | 1023 | if (dst) { |
1024 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
957 | memcpy(mgmt->da, dst, ETH_ALEN); | 1025 | memcpy(mgmt->da, dst, ETH_ALEN); |
958 | memcpy(mgmt->bssid, dst, ETH_ALEN); | 1026 | memcpy(mgmt->bssid, dst, ETH_ALEN); |
959 | } else { | ||
960 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
961 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
962 | } | 1027 | } |
963 | pos = skb_put(skb, 2 + ssid_len); | ||
964 | *pos++ = WLAN_EID_SSID; | ||
965 | *pos++ = ssid_len; | ||
966 | memcpy(pos, ssid, ssid_len); | ||
967 | pos += ssid_len; | ||
968 | 1028 | ||
969 | skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len)); | 1029 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
970 | 1030 | ieee80211_tx_skb(sdata, skb); | |
971 | ieee80211_tx_skb(sdata, skb, 0); | 1031 | kfree(buf); |
972 | } | 1032 | } |
973 | 1033 | ||
974 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | 1034 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, |
@@ -1012,18 +1072,16 @@ void ieee80211_stop_device(struct ieee80211_local *local) | |||
1012 | ieee80211_led_radio(local, false); | 1072 | ieee80211_led_radio(local, false); |
1013 | 1073 | ||
1014 | cancel_work_sync(&local->reconfig_filter); | 1074 | cancel_work_sync(&local->reconfig_filter); |
1015 | drv_stop(local); | ||
1016 | 1075 | ||
1017 | flush_workqueue(local->workqueue); | 1076 | flush_workqueue(local->workqueue); |
1077 | drv_stop(local); | ||
1018 | } | 1078 | } |
1019 | 1079 | ||
1020 | int ieee80211_reconfig(struct ieee80211_local *local) | 1080 | int ieee80211_reconfig(struct ieee80211_local *local) |
1021 | { | 1081 | { |
1022 | struct ieee80211_hw *hw = &local->hw; | 1082 | struct ieee80211_hw *hw = &local->hw; |
1023 | struct ieee80211_sub_if_data *sdata; | 1083 | struct ieee80211_sub_if_data *sdata; |
1024 | struct ieee80211_if_init_conf conf; | ||
1025 | struct sta_info *sta; | 1084 | struct sta_info *sta; |
1026 | unsigned long flags; | ||
1027 | int res; | 1085 | int res; |
1028 | 1086 | ||
1029 | if (local->suspended) | 1087 | if (local->suspended) |
@@ -1031,7 +1089,19 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1031 | 1089 | ||
1032 | /* restart hardware */ | 1090 | /* restart hardware */ |
1033 | if (local->open_count) { | 1091 | if (local->open_count) { |
1092 | /* | ||
1093 | * Upon resume hardware can sometimes be goofy due to | ||
1094 | * various platform / driver / bus issues, so restarting | ||
1095 | * the device may at times not work immediately. Propagate | ||
1096 | * the error. | ||
1097 | */ | ||
1034 | res = drv_start(local); | 1098 | res = drv_start(local); |
1099 | if (res) { | ||
1100 | WARN(local->suspended, "Hardware became unavailable " | ||
1101 | "upon resume. This could be a software issue " | ||
1102 | "prior to suspend or a hardware issue.\n"); | ||
1103 | return res; | ||
1104 | } | ||
1035 | 1105 | ||
1036 | ieee80211_led_radio(local, true); | 1106 | ieee80211_led_radio(local, true); |
1037 | } | 1107 | } |
@@ -1040,29 +1110,24 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1040 | list_for_each_entry(sdata, &local->interfaces, list) { | 1110 | list_for_each_entry(sdata, &local->interfaces, list) { |
1041 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 1111 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
1042 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | 1112 | sdata->vif.type != NL80211_IFTYPE_MONITOR && |
1043 | netif_running(sdata->dev)) { | 1113 | ieee80211_sdata_running(sdata)) |
1044 | conf.vif = &sdata->vif; | 1114 | res = drv_add_interface(local, &sdata->vif); |
1045 | conf.type = sdata->vif.type; | ||
1046 | conf.mac_addr = sdata->dev->dev_addr; | ||
1047 | res = drv_add_interface(local, &conf); | ||
1048 | } | ||
1049 | } | 1115 | } |
1050 | 1116 | ||
1051 | /* add STAs back */ | 1117 | /* add STAs back */ |
1052 | if (local->ops->sta_notify) { | 1118 | mutex_lock(&local->sta_mtx); |
1053 | spin_lock_irqsave(&local->sta_lock, flags); | 1119 | list_for_each_entry(sta, &local->sta_list, list) { |
1054 | list_for_each_entry(sta, &local->sta_list, list) { | 1120 | if (sta->uploaded) { |
1055 | sdata = sta->sdata; | 1121 | sdata = sta->sdata; |
1056 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1122 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
1057 | sdata = container_of(sdata->bss, | 1123 | sdata = container_of(sdata->bss, |
1058 | struct ieee80211_sub_if_data, | 1124 | struct ieee80211_sub_if_data, |
1059 | u.ap); | 1125 | u.ap); |
1060 | 1126 | ||
1061 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, | 1127 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); |
1062 | &sta->sta); | ||
1063 | } | 1128 | } |
1064 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
1065 | } | 1129 | } |
1130 | mutex_unlock(&local->sta_mtx); | ||
1066 | 1131 | ||
1067 | /* Clear Suspend state so that ADDBA requests can be processed */ | 1132 | /* Clear Suspend state so that ADDBA requests can be processed */ |
1068 | 1133 | ||
@@ -1087,7 +1152,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1087 | /* Finally also reconfigure all the BSS information */ | 1152 | /* Finally also reconfigure all the BSS information */ |
1088 | list_for_each_entry(sdata, &local->interfaces, list) { | 1153 | list_for_each_entry(sdata, &local->interfaces, list) { |
1089 | u32 changed = ~0; | 1154 | u32 changed = ~0; |
1090 | if (!netif_running(sdata->dev)) | 1155 | if (!ieee80211_sdata_running(sdata)) |
1091 | continue; | 1156 | continue; |
1092 | switch (sdata->vif.type) { | 1157 | switch (sdata->vif.type) { |
1093 | case NL80211_IFTYPE_STATION: | 1158 | case NL80211_IFTYPE_STATION: |
@@ -1113,9 +1178,17 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1113 | } | 1178 | } |
1114 | } | 1179 | } |
1115 | 1180 | ||
1181 | rcu_read_lock(); | ||
1182 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
1183 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
1184 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
1185 | } | ||
1186 | } | ||
1187 | rcu_read_unlock(); | ||
1188 | |||
1116 | /* add back keys */ | 1189 | /* add back keys */ |
1117 | list_for_each_entry(sdata, &local->interfaces, list) | 1190 | list_for_each_entry(sdata, &local->interfaces, list) |
1118 | if (netif_running(sdata->dev)) | 1191 | if (ieee80211_sdata_running(sdata)) |
1119 | ieee80211_enable_keys(sdata); | 1192 | ieee80211_enable_keys(sdata); |
1120 | 1193 | ||
1121 | ieee80211_wake_queues_by_reason(hw, | 1194 | ieee80211_wake_queues_by_reason(hw, |
@@ -1152,13 +1225,143 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1152 | 1225 | ||
1153 | add_timer(&local->sta_cleanup); | 1226 | add_timer(&local->sta_cleanup); |
1154 | 1227 | ||
1155 | spin_lock_irqsave(&local->sta_lock, flags); | 1228 | mutex_lock(&local->sta_mtx); |
1156 | list_for_each_entry(sta, &local->sta_list, list) | 1229 | list_for_each_entry(sta, &local->sta_list, list) |
1157 | mesh_plink_restart(sta); | 1230 | mesh_plink_restart(sta); |
1158 | spin_unlock_irqrestore(&local->sta_lock, flags); | 1231 | mutex_unlock(&local->sta_mtx); |
1159 | #else | 1232 | #else |
1160 | WARN_ON(1); | 1233 | WARN_ON(1); |
1161 | #endif | 1234 | #endif |
1162 | return 0; | 1235 | return 0; |
1163 | } | 1236 | } |
1164 | 1237 | ||
1238 | static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, | ||
1239 | enum ieee80211_smps_mode *smps_mode) | ||
1240 | { | ||
1241 | if (ifmgd->associated) { | ||
1242 | *smps_mode = ifmgd->ap_smps; | ||
1243 | |||
1244 | if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { | ||
1245 | if (ifmgd->powersave) | ||
1246 | *smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
1247 | else | ||
1248 | *smps_mode = IEEE80211_SMPS_OFF; | ||
1249 | } | ||
1250 | |||
1251 | return 1; | ||
1252 | } | ||
1253 | |||
1254 | return 0; | ||
1255 | } | ||
1256 | |||
1257 | /* must hold iflist_mtx */ | ||
1258 | void ieee80211_recalc_smps(struct ieee80211_local *local, | ||
1259 | struct ieee80211_sub_if_data *forsdata) | ||
1260 | { | ||
1261 | struct ieee80211_sub_if_data *sdata; | ||
1262 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; | ||
1263 | int count = 0; | ||
1264 | |||
1265 | if (forsdata) | ||
1266 | WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx)); | ||
1267 | |||
1268 | WARN_ON(!mutex_is_locked(&local->iflist_mtx)); | ||
1269 | |||
1270 | /* | ||
1271 | * This function could be improved to handle multiple | ||
1272 | * interfaces better, but right now it makes any | ||
1273 | * non-station interfaces force SM PS to be turned | ||
1274 | * off. If there are multiple station interfaces it | ||
1275 | * could also use the best possible mode, e.g. if | ||
1276 | * one is in static and the other in dynamic then | ||
1277 | * dynamic is ok. | ||
1278 | */ | ||
1279 | |||
1280 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1281 | if (!netif_running(sdata->dev)) | ||
1282 | continue; | ||
1283 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
1284 | goto set; | ||
1285 | if (sdata != forsdata) { | ||
1286 | /* | ||
1287 | * This nested is ok -- we are holding the iflist_mtx | ||
1288 | * so can't get here twice or so. But it's required | ||
1289 | * since normally we acquire it first and then the | ||
1290 | * iflist_mtx. | ||
1291 | */ | ||
1292 | mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING); | ||
1293 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1294 | mutex_unlock(&sdata->u.mgd.mtx); | ||
1295 | } else | ||
1296 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1297 | |||
1298 | if (count > 1) { | ||
1299 | smps_mode = IEEE80211_SMPS_OFF; | ||
1300 | break; | ||
1301 | } | ||
1302 | } | ||
1303 | |||
1304 | if (smps_mode == local->smps_mode) | ||
1305 | return; | ||
1306 | |||
1307 | set: | ||
1308 | local->smps_mode = smps_mode; | ||
1309 | /* changed flag is auto-detected for this */ | ||
1310 | ieee80211_hw_config(local, 0); | ||
1311 | } | ||
1312 | |||
1313 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | ||
1314 | { | ||
1315 | int i; | ||
1316 | |||
1317 | for (i = 0; i < n_ids; i++) | ||
1318 | if (ids[i] == id) | ||
1319 | return true; | ||
1320 | return false; | ||
1321 | } | ||
1322 | |||
1323 | /** | ||
1324 | * ieee80211_ie_split - split an IE buffer according to ordering | ||
1325 | * | ||
1326 | * @ies: the IE buffer | ||
1327 | * @ielen: the length of the IE buffer | ||
1328 | * @ids: an array with element IDs that are allowed before | ||
1329 | * the split | ||
1330 | * @n_ids: the size of the element ID array | ||
1331 | * @offset: offset where to start splitting in the buffer | ||
1332 | * | ||
1333 | * This function splits an IE buffer by updating the @offset | ||
1334 | * variable to point to the location where the buffer should be | ||
1335 | * split. | ||
1336 | * | ||
1337 | * It assumes that the given IE buffer is well-formed, this | ||
1338 | * has to be guaranteed by the caller! | ||
1339 | * | ||
1340 | * It also assumes that the IEs in the buffer are ordered | ||
1341 | * correctly, if not the result of using this function will not | ||
1342 | * be ordered correctly either, i.e. it does no reordering. | ||
1343 | * | ||
1344 | * The function returns the offset where the next part of the | ||
1345 | * buffer starts, which may be @ielen if the entire (remainder) | ||
1346 | * of the buffer should be used. | ||
1347 | */ | ||
1348 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
1349 | const u8 *ids, int n_ids, size_t offset) | ||
1350 | { | ||
1351 | size_t pos = offset; | ||
1352 | |||
1353 | while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) | ||
1354 | pos += 2 + ies[pos + 1]; | ||
1355 | |||
1356 | return pos; | ||
1357 | } | ||
1358 | |||
1359 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) | ||
1360 | { | ||
1361 | size_t pos = offset; | ||
1362 | |||
1363 | while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC) | ||
1364 | pos += 2 + ies[pos + 1]; | ||
1365 | |||
1366 | return pos; | ||
1367 | } | ||