aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c230
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
239static 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
237static int ecw2cw(int ecw) 260static 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
2373static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) 2397static 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
4062static 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
4149static char * 4103static char *
4150ieee80211_sta_scan_result(struct ieee80211_local *local, 4104ieee80211_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, &current_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 */