aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211_sta.c
diff options
context:
space:
mode:
authorRon Rindjunsky <ron.rindjunsky@intel.com>2007-11-26 09:14:31 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:55:31 -0500
commitc715350828b12ce3b29e655fec7a7d6b22245d00 (patch)
treee452f028a68e88b8f071bb9298d961d018f88bba /net/mac80211/ieee80211_sta.c
parent10816d40f2e9500057cb46d7608a362a1d10bb9b (diff)
mac80211: adding 802.11n IEs handling
This patch presents the ability to parse and compose HT IEs, and to put the IE relevant data inside the mac80211's internal HT structures Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211/ieee80211_sta.c')
-rw-r--r--net/mac80211/ieee80211_sta.c89
1 files changed, 87 insertions, 2 deletions
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 231a663ad914..1f47afeb925d 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -90,7 +90,8 @@ struct ieee802_11_elems {
90 u8 *ext_supp_rates; 90 u8 *ext_supp_rates;
91 u8 *wmm_info; 91 u8 *wmm_info;
92 u8 *wmm_param; 92 u8 *wmm_param;
93 93 u8 *ht_cap_elem;
94 u8 *ht_info_elem;
94 /* length of them, respectively */ 95 /* length of them, respectively */
95 u8 ssid_len; 96 u8 ssid_len;
96 u8 supp_rates_len; 97 u8 supp_rates_len;
@@ -106,6 +107,8 @@ struct ieee802_11_elems {
106 u8 ext_supp_rates_len; 107 u8 ext_supp_rates_len;
107 u8 wmm_info_len; 108 u8 wmm_info_len;
108 u8 wmm_param_len; 109 u8 wmm_param_len;
110 u8 ht_cap_elem_len;
111 u8 ht_info_elem_len;
109}; 112};
110 113
111static void ieee802_11_parse_elems(u8 *start, size_t len, 114static void ieee802_11_parse_elems(u8 *start, size_t len,
@@ -190,6 +193,14 @@ static void ieee802_11_parse_elems(u8 *start, size_t len,
190 elems->ext_supp_rates = pos; 193 elems->ext_supp_rates = pos;
191 elems->ext_supp_rates_len = elen; 194 elems->ext_supp_rates_len = elen;
192 break; 195 break;
196 case WLAN_EID_HT_CAPABILITY:
197 elems->ht_cap_elem = pos;
198 elems->ht_cap_elem_len = elen;
199 break;
200 case WLAN_EID_HT_EXTRA_INFO:
201 elems->ht_info_elem = pos;
202 elems->ht_info_elem_len = elen;
203 break;
193 default: 204 default:
194 break; 205 break;
195 } 206 }
@@ -332,6 +343,51 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value)
332 ieee80211_erp_info_change_notify(dev, changes); 343 ieee80211_erp_info_change_notify(dev, changes);
333} 344}
334 345
346int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
347 struct ieee80211_ht_info *ht_info)
348{
349
350 if (ht_info == NULL)
351 return -EINVAL;
352
353 memset(ht_info, 0, sizeof(*ht_info));
354
355 if (ht_cap_ie) {
356 u8 ampdu_info = ht_cap_ie->ampdu_params_info;
357
358 ht_info->ht_supported = 1;
359 ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
360 ht_info->ampdu_factor =
361 ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
362 ht_info->ampdu_density =
363 (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
364 memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
365 } else
366 ht_info->ht_supported = 0;
367
368 return 0;
369}
370
371int ieee80211_ht_addt_info_ie_to_ht_bss_info(
372 struct ieee80211_ht_addt_info *ht_add_info_ie,
373 struct ieee80211_ht_bss_info *bss_info)
374{
375 if (bss_info == NULL)
376 return -EINVAL;
377
378 memset(bss_info, 0, sizeof(*bss_info));
379
380 if (ht_add_info_ie) {
381 u16 op_mode;
382 op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
383
384 bss_info->primary_channel = ht_add_info_ie->control_chan;
385 bss_info->bss_cap = ht_add_info_ie->ht_param;
386 bss_info->bss_op_mode = (u8)(op_mode & 0xff);
387 }
388
389 return 0;
390}
335 391
336static void ieee80211_sta_send_associnfo(struct net_device *dev, 392static void ieee80211_sta_send_associnfo(struct net_device *dev,
337 struct ieee80211_if_sta *ifsta) 393 struct ieee80211_if_sta *ifsta)
@@ -630,6 +686,19 @@ static void ieee80211_send_assoc(struct net_device *dev,
630 *pos++ = 1; /* WME ver */ 686 *pos++ = 1; /* WME ver */
631 *pos++ = 0; 687 *pos++ = 0;
632 } 688 }
689 /* wmm support is a must to HT */
690 if (wmm && mode->ht_info.ht_supported) {
691 __le16 tmp = cpu_to_le16(mode->ht_info.cap);
692 pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
693 *pos++ = WLAN_EID_HT_CAPABILITY;
694 *pos++ = sizeof(struct ieee80211_ht_cap);
695 memset(pos, 0, sizeof(struct ieee80211_ht_cap));
696 memcpy(pos, &tmp, sizeof(u16));
697 pos += sizeof(u16);
698 *pos++ = (mode->ht_info.ampdu_factor |
699 (mode->ht_info.ampdu_density << 2));
700 memcpy(pos, mode->ht_info.supp_mcs_set, 16);
701 }
633 702
634 kfree(ifsta->assocreq_ies); 703 kfree(ifsta->assocreq_ies);
635 ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; 704 ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
@@ -1380,6 +1449,7 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
1380 kfree(bss->wpa_ie); 1449 kfree(bss->wpa_ie);
1381 kfree(bss->rsn_ie); 1450 kfree(bss->rsn_ie);
1382 kfree(bss->wmm_ie); 1451 kfree(bss->wmm_ie);
1452 kfree(bss->ht_ie);
1383 kfree(bss); 1453 kfree(bss);
1384} 1454}
1385 1455
@@ -1637,7 +1707,22 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
1637 bss->wmm_ie = NULL; 1707 bss->wmm_ie = NULL;
1638 bss->wmm_ie_len = 0; 1708 bss->wmm_ie_len = 0;
1639 } 1709 }
1640 1710 if (elems.ht_cap_elem &&
1711 (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
1712 memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
1713 kfree(bss->ht_ie);
1714 bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
1715 if (bss->ht_ie) {
1716 memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
1717 elems.ht_cap_elem_len + 2);
1718 bss->ht_ie_len = elems.ht_cap_elem_len + 2;
1719 } else
1720 bss->ht_ie_len = 0;
1721 } else if (!elems.ht_cap_elem && bss->ht_ie) {
1722 kfree(bss->ht_ie);
1723 bss->ht_ie = NULL;
1724 bss->ht_ie_len = 0;
1725 }
1641 1726
1642 bss->hw_mode = rx_status->phymode; 1727 bss->hw_mode = rx_status->phymode;
1643 bss->freq = rx_status->freq; 1728 bss->freq = rx_status->freq;