Skip to content

Commit

Permalink
mac80211: adding 802.11n IEs handling
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ron Rindjunsky authored and David S. Miller committed Jan 28, 2008
1 parent 10816d4 commit c715350
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 3 deletions.
8 changes: 7 additions & 1 deletion net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ struct ieee80211_sta_bss {
size_t rsn_ie_len;
u8 *wmm_ie;
size_t wmm_ie_len;
u8 *ht_ie;
size_t ht_ie_len;
#define IEEE80211_MAX_SUPP_RATES 32
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
size_t supp_rates_len;
Expand Down Expand Up @@ -759,7 +761,11 @@ int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes);
void ieee80211_reset_erp_info(struct net_device *dev);

int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
struct ieee80211_ht_info *ht_info);
int ieee80211_ht_addt_info_ie_to_ht_bss_info(
struct ieee80211_ht_addt_info *ht_add_info_ie,
struct ieee80211_ht_bss_info *bss_info);
/* ieee80211_iface.c */
int ieee80211_if_add(struct net_device *dev, const char *name,
struct net_device **new_dev, int type);
Expand Down
89 changes: 87 additions & 2 deletions net/mac80211/ieee80211_sta.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ struct ieee802_11_elems {
u8 *ext_supp_rates;
u8 *wmm_info;
u8 *wmm_param;

u8 *ht_cap_elem;
u8 *ht_info_elem;
/* length of them, respectively */
u8 ssid_len;
u8 supp_rates_len;
Expand All @@ -106,6 +107,8 @@ struct ieee802_11_elems {
u8 ext_supp_rates_len;
u8 wmm_info_len;
u8 wmm_param_len;
u8 ht_cap_elem_len;
u8 ht_info_elem_len;
};

static void ieee802_11_parse_elems(u8 *start, size_t len,
Expand Down Expand Up @@ -190,6 +193,14 @@ static void ieee802_11_parse_elems(u8 *start, size_t len,
elems->ext_supp_rates = pos;
elems->ext_supp_rates_len = elen;
break;
case WLAN_EID_HT_CAPABILITY:
elems->ht_cap_elem = pos;
elems->ht_cap_elem_len = elen;
break;
case WLAN_EID_HT_EXTRA_INFO:
elems->ht_info_elem = pos;
elems->ht_info_elem_len = elen;
break;
default:
break;
}
Expand Down Expand Up @@ -332,6 +343,51 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value)
ieee80211_erp_info_change_notify(dev, changes);
}

int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
struct ieee80211_ht_info *ht_info)
{

if (ht_info == NULL)
return -EINVAL;

memset(ht_info, 0, sizeof(*ht_info));

if (ht_cap_ie) {
u8 ampdu_info = ht_cap_ie->ampdu_params_info;

ht_info->ht_supported = 1;
ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
ht_info->ampdu_factor =
ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
ht_info->ampdu_density =
(ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
} else
ht_info->ht_supported = 0;

return 0;
}

int ieee80211_ht_addt_info_ie_to_ht_bss_info(
struct ieee80211_ht_addt_info *ht_add_info_ie,
struct ieee80211_ht_bss_info *bss_info)
{
if (bss_info == NULL)
return -EINVAL;

memset(bss_info, 0, sizeof(*bss_info));

if (ht_add_info_ie) {
u16 op_mode;
op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);

bss_info->primary_channel = ht_add_info_ie->control_chan;
bss_info->bss_cap = ht_add_info_ie->ht_param;
bss_info->bss_op_mode = (u8)(op_mode & 0xff);
}

return 0;
}

static void ieee80211_sta_send_associnfo(struct net_device *dev,
struct ieee80211_if_sta *ifsta)
Expand Down Expand Up @@ -630,6 +686,19 @@ static void ieee80211_send_assoc(struct net_device *dev,
*pos++ = 1; /* WME ver */
*pos++ = 0;
}
/* wmm support is a must to HT */
if (wmm && mode->ht_info.ht_supported) {
__le16 tmp = cpu_to_le16(mode->ht_info.cap);
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
*pos++ = WLAN_EID_HT_CAPABILITY;
*pos++ = sizeof(struct ieee80211_ht_cap);
memset(pos, 0, sizeof(struct ieee80211_ht_cap));
memcpy(pos, &tmp, sizeof(u16));
pos += sizeof(u16);
*pos++ = (mode->ht_info.ampdu_factor |
(mode->ht_info.ampdu_density << 2));
memcpy(pos, mode->ht_info.supp_mcs_set, 16);
}

kfree(ifsta->assocreq_ies);
ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
Expand Down Expand Up @@ -1380,6 +1449,7 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
kfree(bss->wpa_ie);
kfree(bss->rsn_ie);
kfree(bss->wmm_ie);
kfree(bss->ht_ie);
kfree(bss);
}

Expand Down Expand Up @@ -1637,7 +1707,22 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
bss->wmm_ie = NULL;
bss->wmm_ie_len = 0;
}

if (elems.ht_cap_elem &&
(!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
kfree(bss->ht_ie);
bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
if (bss->ht_ie) {
memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
elems.ht_cap_elem_len + 2);
bss->ht_ie_len = elems.ht_cap_elem_len + 2;
} else
bss->ht_ie_len = 0;
} else if (!elems.ht_cap_elem && bss->ht_ie) {
kfree(bss->ht_ie);
bss->ht_ie = NULL;
bss->ht_ie_len = 0;
}

bss->hw_mode = rx_status->phymode;
bss->freq = rx_status->freq;
Expand Down

0 comments on commit c715350

Please sign in to comment.