diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 230 |
1 files changed, 81 insertions, 149 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 84999791a332..e088b440aafa 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -98,6 +98,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | |||
98 | u8 *pos = start; | 98 | u8 *pos = start; |
99 | 99 | ||
100 | memset(elems, 0, sizeof(*elems)); | 100 | memset(elems, 0, sizeof(*elems)); |
101 | elems->ie_start = start; | ||
102 | elems->total_len = len; | ||
101 | 103 | ||
102 | while (left >= 2) { | 104 | while (left >= 2) { |
103 | u8 id, elen; | 105 | u8 id, elen; |
@@ -234,6 +236,27 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | |||
234 | } | 236 | } |
235 | 237 | ||
236 | 238 | ||
239 | static u8 * ieee80211_bss_get_ie(struct ieee80211_sta_bss *bss, u8 ie) | ||
240 | { | ||
241 | u8 *end, *pos; | ||
242 | |||
243 | pos = bss->ies; | ||
244 | if (pos == NULL) | ||
245 | return NULL; | ||
246 | end = pos + bss->ies_len; | ||
247 | |||
248 | while (pos + 1 < end) { | ||
249 | if (pos + 2 + pos[1] > end) | ||
250 | break; | ||
251 | if (pos[0] == ie) | ||
252 | return pos; | ||
253 | pos += 2 + pos[1]; | ||
254 | } | ||
255 | |||
256 | return NULL; | ||
257 | } | ||
258 | |||
259 | |||
237 | static int ecw2cw(int ecw) | 260 | static int ecw2cw(int ecw) |
238 | { | 261 | { |
239 | return (1 << ecw) - 1; | 262 | return (1 << ecw) - 1; |
@@ -737,7 +760,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
737 | struct ieee80211_local *local = sdata->local; | 760 | struct ieee80211_local *local = sdata->local; |
738 | struct sk_buff *skb; | 761 | struct sk_buff *skb; |
739 | struct ieee80211_mgmt *mgmt; | 762 | struct ieee80211_mgmt *mgmt; |
740 | u8 *pos, *ies; | 763 | u8 *pos, *ies, *ht_add_ie; |
741 | int i, len, count, rates_len, supp_rates_len; | 764 | int i, len, count, rates_len, supp_rates_len; |
742 | u16 capab; | 765 | u16 capab; |
743 | struct ieee80211_sta_bss *bss; | 766 | struct ieee80211_sta_bss *bss; |
@@ -772,7 +795,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
772 | if (bss) { | 795 | if (bss) { |
773 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | 796 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) |
774 | capab |= WLAN_CAPABILITY_PRIVACY; | 797 | capab |= WLAN_CAPABILITY_PRIVACY; |
775 | if (bss->wmm_ie) | 798 | if (bss->wmm_used) |
776 | wmm = 1; | 799 | wmm = 1; |
777 | 800 | ||
778 | /* get all rates supported by the device and the AP as | 801 | /* get all rates supported by the device and the AP as |
@@ -894,9 +917,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
894 | 917 | ||
895 | /* wmm support is a must to HT */ | 918 | /* wmm support is a must to HT */ |
896 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && | 919 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && |
897 | sband->ht_info.ht_supported && bss->ht_add_ie) { | 920 | sband->ht_info.ht_supported && |
921 | (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) { | ||
898 | struct ieee80211_ht_addt_info *ht_add_info = | 922 | struct ieee80211_ht_addt_info *ht_add_info = |
899 | (struct ieee80211_ht_addt_info *)bss->ht_add_ie; | 923 | (struct ieee80211_ht_addt_info *)ht_add_ie; |
900 | u16 cap = sband->ht_info.cap; | 924 | u16 cap = sband->ht_info.cap; |
901 | __le16 tmp; | 925 | __le16 tmp; |
902 | u32 flags = local->hw.conf.channel->flags; | 926 | u32 flags = local->hw.conf.channel->flags; |
@@ -2372,11 +2396,7 @@ ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_i | |||
2372 | 2396 | ||
2373 | static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) | 2397 | static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) |
2374 | { | 2398 | { |
2375 | kfree(bss->wpa_ie); | 2399 | kfree(bss->ies); |
2376 | kfree(bss->rsn_ie); | ||
2377 | kfree(bss->wmm_ie); | ||
2378 | kfree(bss->ht_ie); | ||
2379 | kfree(bss->ht_add_ie); | ||
2380 | kfree(bss_mesh_id(bss)); | 2400 | kfree(bss_mesh_id(bss)); |
2381 | kfree(bss_mesh_cfg(bss)); | 2401 | kfree(bss_mesh_cfg(bss)); |
2382 | kfree(bss); | 2402 | kfree(bss); |
@@ -2662,43 +2682,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2662 | bss->has_erp_value = 1; | 2682 | bss->has_erp_value = 1; |
2663 | } | 2683 | } |
2664 | 2684 | ||
2665 | if (elems->ht_cap_elem && | ||
2666 | (!bss->ht_ie || bss->ht_ie_len != elems->ht_cap_elem_len || | ||
2667 | memcmp(bss->ht_ie, elems->ht_cap_elem, elems->ht_cap_elem_len))) { | ||
2668 | kfree(bss->ht_ie); | ||
2669 | bss->ht_ie = kmalloc(elems->ht_cap_elem_len + 2, GFP_ATOMIC); | ||
2670 | if (bss->ht_ie) { | ||
2671 | memcpy(bss->ht_ie, elems->ht_cap_elem - 2, | ||
2672 | elems->ht_cap_elem_len + 2); | ||
2673 | bss->ht_ie_len = elems->ht_cap_elem_len + 2; | ||
2674 | } else | ||
2675 | bss->ht_ie_len = 0; | ||
2676 | } else if (!elems->ht_cap_elem && bss->ht_ie) { | ||
2677 | kfree(bss->ht_ie); | ||
2678 | bss->ht_ie = NULL; | ||
2679 | bss->ht_ie_len = 0; | ||
2680 | } | ||
2681 | |||
2682 | if (elems->ht_info_elem && | ||
2683 | (!bss->ht_add_ie || | ||
2684 | bss->ht_add_ie_len != elems->ht_info_elem_len || | ||
2685 | memcmp(bss->ht_add_ie, elems->ht_info_elem, | ||
2686 | elems->ht_info_elem_len))) { | ||
2687 | kfree(bss->ht_add_ie); | ||
2688 | bss->ht_add_ie = | ||
2689 | kmalloc(elems->ht_info_elem_len + 2, GFP_ATOMIC); | ||
2690 | if (bss->ht_add_ie) { | ||
2691 | memcpy(bss->ht_add_ie, elems->ht_info_elem - 2, | ||
2692 | elems->ht_info_elem_len + 2); | ||
2693 | bss->ht_add_ie_len = elems->ht_info_elem_len + 2; | ||
2694 | } else | ||
2695 | bss->ht_add_ie_len = 0; | ||
2696 | } else if (!elems->ht_info_elem && bss->ht_add_ie) { | ||
2697 | kfree(bss->ht_add_ie); | ||
2698 | bss->ht_add_ie = NULL; | ||
2699 | bss->ht_add_ie_len = 0; | ||
2700 | } | ||
2701 | |||
2702 | bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); | 2685 | bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); |
2703 | bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); | 2686 | bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); |
2704 | 2687 | ||
@@ -2749,88 +2732,17 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2749 | return; | 2732 | return; |
2750 | } | 2733 | } |
2751 | 2734 | ||
2752 | if (elems->wpa && | 2735 | if (bss->ies == NULL || bss->ies_len < elems->total_len) { |
2753 | (!bss->wpa_ie || bss->wpa_ie_len != elems->wpa_len || | 2736 | kfree(bss->ies); |
2754 | memcmp(bss->wpa_ie, elems->wpa, elems->wpa_len))) { | 2737 | bss->ies = kmalloc(elems->total_len, GFP_ATOMIC); |
2755 | kfree(bss->wpa_ie); | ||
2756 | bss->wpa_ie = kmalloc(elems->wpa_len + 2, GFP_ATOMIC); | ||
2757 | if (bss->wpa_ie) { | ||
2758 | memcpy(bss->wpa_ie, elems->wpa - 2, elems->wpa_len + 2); | ||
2759 | bss->wpa_ie_len = elems->wpa_len + 2; | ||
2760 | } else | ||
2761 | bss->wpa_ie_len = 0; | ||
2762 | } else if (!elems->wpa && bss->wpa_ie) { | ||
2763 | kfree(bss->wpa_ie); | ||
2764 | bss->wpa_ie = NULL; | ||
2765 | bss->wpa_ie_len = 0; | ||
2766 | } | ||
2767 | |||
2768 | if (elems->rsn && | ||
2769 | (!bss->rsn_ie || bss->rsn_ie_len != elems->rsn_len || | ||
2770 | memcmp(bss->rsn_ie, elems->rsn, elems->rsn_len))) { | ||
2771 | kfree(bss->rsn_ie); | ||
2772 | bss->rsn_ie = kmalloc(elems->rsn_len + 2, GFP_ATOMIC); | ||
2773 | if (bss->rsn_ie) { | ||
2774 | memcpy(bss->rsn_ie, elems->rsn - 2, elems->rsn_len + 2); | ||
2775 | bss->rsn_ie_len = elems->rsn_len + 2; | ||
2776 | } else | ||
2777 | bss->rsn_ie_len = 0; | ||
2778 | } else if (!elems->rsn && bss->rsn_ie) { | ||
2779 | kfree(bss->rsn_ie); | ||
2780 | bss->rsn_ie = NULL; | ||
2781 | bss->rsn_ie_len = 0; | ||
2782 | } | 2738 | } |
2739 | if (bss->ies) { | ||
2740 | memcpy(bss->ies, elems->ie_start, elems->total_len); | ||
2741 | bss->ies_len = elems->total_len; | ||
2742 | } else | ||
2743 | bss->ies_len = 0; | ||
2783 | 2744 | ||
2784 | /* | 2745 | bss->wmm_used = elems->wmm_param || elems->wmm_info; |
2785 | * Cf. | ||
2786 | * http://www.wipo.int/pctdb/en/wo.jsp?wo=2007047181&IA=WO2007047181&DISPLAY=DESC | ||
2787 | * | ||
2788 | * quoting: | ||
2789 | * | ||
2790 | * In particular, "Wi-Fi CERTIFIED for WMM - Support for Multimedia | ||
2791 | * Applications with Quality of Service in Wi-Fi Networks," Wi- Fi | ||
2792 | * Alliance (September 1, 2004) is incorporated by reference herein. | ||
2793 | * The inclusion of the WMM Parameters in probe responses and | ||
2794 | * association responses is mandatory for WMM enabled networks. The | ||
2795 | * inclusion of the WMM Parameters in beacons, however, is optional. | ||
2796 | */ | ||
2797 | |||
2798 | if (elems->wmm_param && | ||
2799 | (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_param_len || | ||
2800 | memcmp(bss->wmm_ie, elems->wmm_param, elems->wmm_param_len))) { | ||
2801 | kfree(bss->wmm_ie); | ||
2802 | bss->wmm_ie = kmalloc(elems->wmm_param_len + 2, GFP_ATOMIC); | ||
2803 | if (bss->wmm_ie) { | ||
2804 | memcpy(bss->wmm_ie, elems->wmm_param - 2, | ||
2805 | elems->wmm_param_len + 2); | ||
2806 | bss->wmm_ie_len = elems->wmm_param_len + 2; | ||
2807 | } else | ||
2808 | bss->wmm_ie_len = 0; | ||
2809 | } else if (elems->wmm_info && | ||
2810 | (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_info_len || | ||
2811 | memcmp(bss->wmm_ie, elems->wmm_info, | ||
2812 | elems->wmm_info_len))) { | ||
2813 | /* As for certain AP's Fifth bit is not set in WMM IE in | ||
2814 | * beacon frames.So while parsing the beacon frame the | ||
2815 | * wmm_info structure is used instead of wmm_param. | ||
2816 | * wmm_info structure was never used to set bss->wmm_ie. | ||
2817 | * This code fixes this problem by copying the WME | ||
2818 | * information from wmm_info to bss->wmm_ie and enabling | ||
2819 | * n-band association. | ||
2820 | */ | ||
2821 | kfree(bss->wmm_ie); | ||
2822 | bss->wmm_ie = kmalloc(elems->wmm_info_len + 2, GFP_ATOMIC); | ||
2823 | if (bss->wmm_ie) { | ||
2824 | memcpy(bss->wmm_ie, elems->wmm_info - 2, | ||
2825 | elems->wmm_info_len + 2); | ||
2826 | bss->wmm_ie_len = elems->wmm_info_len + 2; | ||
2827 | } else | ||
2828 | bss->wmm_ie_len = 0; | ||
2829 | } else if (!elems->wmm_param && !elems->wmm_info && bss->wmm_ie) { | ||
2830 | kfree(bss->wmm_ie); | ||
2831 | bss->wmm_ie = NULL; | ||
2832 | bss->wmm_ie_len = 0; | ||
2833 | } | ||
2834 | 2746 | ||
2835 | /* check if we need to merge IBSS */ | 2747 | /* check if we need to merge IBSS */ |
2836 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && | 2748 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && |
@@ -4146,6 +4058,48 @@ int ieee80211_sta_req_scan(struct ieee80211_sub_if_data *sdata, u8 *ssid, size_t | |||
4146 | return 0; | 4058 | return 0; |
4147 | } | 4059 | } |
4148 | 4060 | ||
4061 | |||
4062 | static void ieee80211_sta_add_scan_ies(struct iw_request_info *info, | ||
4063 | struct ieee80211_sta_bss *bss, | ||
4064 | char **current_ev, char *end_buf) | ||
4065 | { | ||
4066 | u8 *pos, *end, *next; | ||
4067 | struct iw_event iwe; | ||
4068 | |||
4069 | if (bss == NULL || bss->ies == NULL) | ||
4070 | return; | ||
4071 | |||
4072 | /* | ||
4073 | * If needed, fragment the IEs buffer (at IE boundaries) into short | ||
4074 | * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. | ||
4075 | */ | ||
4076 | pos = bss->ies; | ||
4077 | end = pos + bss->ies_len; | ||
4078 | |||
4079 | while (end - pos > IW_GENERIC_IE_MAX) { | ||
4080 | next = pos + 2 + pos[1]; | ||
4081 | while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX) | ||
4082 | next = next + 2 + next[1]; | ||
4083 | |||
4084 | memset(&iwe, 0, sizeof(iwe)); | ||
4085 | iwe.cmd = IWEVGENIE; | ||
4086 | iwe.u.data.length = next - pos; | ||
4087 | *current_ev = iwe_stream_add_point(info, *current_ev, | ||
4088 | end_buf, &iwe, pos); | ||
4089 | |||
4090 | pos = next; | ||
4091 | } | ||
4092 | |||
4093 | if (end > pos) { | ||
4094 | memset(&iwe, 0, sizeof(iwe)); | ||
4095 | iwe.cmd = IWEVGENIE; | ||
4096 | iwe.u.data.length = end - pos; | ||
4097 | *current_ev = iwe_stream_add_point(info, *current_ev, | ||
4098 | end_buf, &iwe, pos); | ||
4099 | } | ||
4100 | } | ||
4101 | |||
4102 | |||
4149 | static char * | 4103 | static char * |
4150 | ieee80211_sta_scan_result(struct ieee80211_local *local, | 4104 | ieee80211_sta_scan_result(struct ieee80211_local *local, |
4151 | struct iw_request_info *info, | 4105 | struct iw_request_info *info, |
@@ -4225,29 +4179,7 @@ ieee80211_sta_scan_result(struct ieee80211_local *local, | |||
4225 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | 4179 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4226 | &iwe, ""); | 4180 | &iwe, ""); |
4227 | 4181 | ||
4228 | if (bss && bss->wpa_ie) { | 4182 | ieee80211_sta_add_scan_ies(info, bss, ¤t_ev, end_buf); |
4229 | memset(&iwe, 0, sizeof(iwe)); | ||
4230 | iwe.cmd = IWEVGENIE; | ||
4231 | iwe.u.data.length = bss->wpa_ie_len; | ||
4232 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4233 | &iwe, bss->wpa_ie); | ||
4234 | } | ||
4235 | |||
4236 | if (bss && bss->rsn_ie) { | ||
4237 | memset(&iwe, 0, sizeof(iwe)); | ||
4238 | iwe.cmd = IWEVGENIE; | ||
4239 | iwe.u.data.length = bss->rsn_ie_len; | ||
4240 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4241 | &iwe, bss->rsn_ie); | ||
4242 | } | ||
4243 | |||
4244 | if (bss && bss->ht_ie) { | ||
4245 | memset(&iwe, 0, sizeof(iwe)); | ||
4246 | iwe.cmd = IWEVGENIE; | ||
4247 | iwe.u.data.length = bss->ht_ie_len; | ||
4248 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4249 | &iwe, bss->ht_ie); | ||
4250 | } | ||
4251 | 4183 | ||
4252 | if (bss && bss->supp_rates_len > 0) { | 4184 | if (bss && bss->supp_rates_len > 0) { |
4253 | /* display all supported rates in readable format */ | 4185 | /* display all supported rates in readable format */ |