aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2008-08-15 15:21:27 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-08-29 16:24:05 -0400
commit43ac2ca3840f64f699a239535c590fa7ebaaac27 (patch)
tree4d60ba05ba1ba39635533f1dbf1a1babd75f52b5 /net/mac80211/mlme.c
parent19b73c7f68fb2eeb180eafa70f9859409ec9aa08 (diff)
mac80211: Handle scan result IEs in one block
Clean up and extend scan result processing by storing all the IEs from Beacon/Probe Response frames in a single block instead of allocating memory for each specific IE separately. This removes lot of unnecessary code and automatically supports reporting of new IEs (e.g., IEEE 802.11r) into user space without need to manually extend mac80211 scanning code whenever a new protocol adds IE(s). Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
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 */