diff options
author | Ron Rindjunsky <ron.rindjunsky@intel.com> | 2007-11-26 09:14:31 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:55:31 -0500 |
commit | c715350828b12ce3b29e655fec7a7d6b22245d00 (patch) | |
tree | e452f028a68e88b8f071bb9298d961d018f88bba /net/mac80211 | |
parent | 10816d40f2e9500057cb46d7608a362a1d10bb9b (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')
-rw-r--r-- | net/mac80211/ieee80211_i.h | 8 | ||||
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 89 |
2 files changed, 94 insertions, 3 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e2aed0b2d8be..982f99672994 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -89,6 +89,8 @@ struct ieee80211_sta_bss { | |||
89 | size_t rsn_ie_len; | 89 | size_t rsn_ie_len; |
90 | u8 *wmm_ie; | 90 | u8 *wmm_ie; |
91 | size_t wmm_ie_len; | 91 | size_t wmm_ie_len; |
92 | u8 *ht_ie; | ||
93 | size_t ht_ie_len; | ||
92 | #define IEEE80211_MAX_SUPP_RATES 32 | 94 | #define IEEE80211_MAX_SUPP_RATES 32 |
93 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | 95 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; |
94 | size_t supp_rates_len; | 96 | size_t supp_rates_len; |
@@ -759,7 +761,11 @@ int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason); | |||
759 | int ieee80211_sta_disassociate(struct net_device *dev, u16 reason); | 761 | int ieee80211_sta_disassociate(struct net_device *dev, u16 reason); |
760 | void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes); | 762 | void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes); |
761 | void ieee80211_reset_erp_info(struct net_device *dev); | 763 | void ieee80211_reset_erp_info(struct net_device *dev); |
762 | 764 | int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, | |
765 | struct ieee80211_ht_info *ht_info); | ||
766 | int ieee80211_ht_addt_info_ie_to_ht_bss_info( | ||
767 | struct ieee80211_ht_addt_info *ht_add_info_ie, | ||
768 | struct ieee80211_ht_bss_info *bss_info); | ||
763 | /* ieee80211_iface.c */ | 769 | /* ieee80211_iface.c */ |
764 | int ieee80211_if_add(struct net_device *dev, const char *name, | 770 | int ieee80211_if_add(struct net_device *dev, const char *name, |
765 | struct net_device **new_dev, int type); | 771 | struct net_device **new_dev, int type); |
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 | ||
111 | static void ieee802_11_parse_elems(u8 *start, size_t len, | 114 | static 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 | ||
346 | int 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 | |||
371 | int 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 | ||
336 | static void ieee80211_sta_send_associnfo(struct net_device *dev, | 392 | static 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; |