Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 183401
b: refs/heads/master
c: 77c8144
h: refs/heads/master
i:
  183399: 0ba96ea
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed Dec 28, 2009
1 parent fca7b72 commit 91afc45
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 110 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7d3a1c3b03c3a571a2c8c393b75558a5f4a7532a
refs/heads/master: 77c8144ad3ee7fae834e13cb7e83f5b7c8c5329e
7 changes: 7 additions & 0 deletions trunk/net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
ifmgd->ap_smps = ifmgd->req_smps;

wk->assoc.smps = ifmgd->ap_smps;
/*
* IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode.
* We still associate in non-HT mode (11a/b/g) if any one of these
* ciphers is configured as pairwise.
* We can set this to true for non-11n hardware, that'll be checked
* separately along with the peer capabilities.
*/
wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N);
wk->assoc.capability = req->bss->capability;
wk->assoc.wmm_used = wk->assoc.bss->wmm_used;
Expand Down
239 changes: 130 additions & 109 deletions trunk/net/mac80211/work.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,31 +100,144 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,

/* frame sending functions */

static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
struct ieee80211_supported_band *sband,
struct ieee80211_channel *channel,
enum ieee80211_smps_mode smps)
{
struct ieee80211_ht_info *ht_info;
u8 *pos;
u32 flags = channel->flags;
u16 cap = sband->ht_cap.cap;
__le16 tmp;

if (!sband->ht_cap.ht_supported)
return;

if (!ht_info_ie)
return;

if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
return;

ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);

/* determine capability flags */

if (ieee80211_disable_40mhz_24ghz &&
sband->band == IEEE80211_BAND_2GHZ) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
cap &= ~IEEE80211_HT_CAP_SGI_40;
}

switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
cap &= ~IEEE80211_HT_CAP_SGI_40;
}
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
cap &= ~IEEE80211_HT_CAP_SGI_40;
}
break;
}

/* set SM PS mode properly */
cap &= ~IEEE80211_HT_CAP_SM_PS;
switch (smps) {
case IEEE80211_SMPS_AUTOMATIC:
case IEEE80211_SMPS_NUM_MODES:
WARN_ON(1);
case IEEE80211_SMPS_OFF:
cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
IEEE80211_HT_CAP_SM_PS_SHIFT;
break;
case IEEE80211_SMPS_STATIC:
cap |= WLAN_HT_CAP_SM_PS_STATIC <<
IEEE80211_HT_CAP_SM_PS_SHIFT;
break;
case IEEE80211_SMPS_DYNAMIC:
cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
IEEE80211_HT_CAP_SM_PS_SHIFT;
break;
}

/* reserve and fill IE */

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));

/* capability flags */
tmp = cpu_to_le16(cap);
memcpy(pos, &tmp, sizeof(u16));
pos += sizeof(u16);

/* AMPDU parameters */
*pos++ = sband->ht_cap.ampdu_factor |
(sband->ht_cap.ampdu_density <<
IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);

/* MCS set */
memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
pos += sizeof(sband->ht_cap.mcs);

/* extended capabilities */
pos += sizeof(__le16);

/* BF capabilities */
pos += sizeof(__le32);

/* antenna selection */
pos += sizeof(u8);
}

static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_work *wk)
{
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos;
const u8 *ies, *ht_ie;
const u8 *ies;
int i, len, count, rates_len, supp_rates_len;
u16 capab;
struct ieee80211_supported_band *sband;
u32 rates = 0;

skb = dev_alloc_skb(local->hw.extra_tx_headroom +
sizeof(*mgmt) + 200 + wk->ie_len +
wk->assoc.ssid_len);
sband = local->hw.wiphy->bands[wk->chan->band];

/*
* Get all rates supported by the device and the AP as
* some APs don't like getting a superset of their rates
* in the association request (e.g. D-Link DAP 1353 in
* b-only mode)...
*/
rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates,
wk->assoc.supp_rates_len,
sband, &rates);

skb = alloc_skb(local->hw.extra_tx_headroom +
sizeof(*mgmt) + /* bit too much but doesn't matter */
2 + wk->assoc.ssid_len + /* SSID */
4 + rates_len + /* (extended) rates */
4 + /* power capability */
2 + 2 * sband->n_channels + /* supported channels */
2 + sizeof(struct ieee80211_ht_cap) + /* HT */
wk->ie_len + /* extra IEs */
9, /* WMM */
GFP_KERNEL);
if (!skb) {
printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
"frame\n", sdata->name);
return;
}
skb_reserve(skb, local->hw.extra_tx_headroom);

sband = local->hw.wiphy->bands[wk->chan->band];

capab = WLAN_CAPABILITY_ESS;

if (sband->band == IEEE80211_BAND_2GHZ) {
Expand All @@ -137,16 +250,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY)
capab |= WLAN_CAPABILITY_PRIVACY;

/*
* Get all rates supported by the device and the AP as
* some APs don't like getting a superset of their rates
* in the association request (e.g. D-Link DAP 1353 in
* b-only mode)...
*/
rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates,
wk->assoc.supp_rates_len,
sband, &rates);

if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
(local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
Expand Down Expand Up @@ -220,7 +323,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
*pos++ = WLAN_EID_PWR_CAPABILITY;
*pos++ = 2;
*pos++ = 0; /* min tx power */
*pos++ = local->hw.conf.channel->max_power; /* max tx power */
*pos++ = wk->chan->max_power; /* max tx power */

/* 2. supported channels */
/* TODO: get this in reg domain format */
Expand All @@ -234,11 +337,21 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
}
}

/*
* XXX: These IEs could contain (vendor-specified)
* IEs that belong after HT -- the buffer may
* need to be split up.
*/
if (wk->ie_len && wk->ie) {
pos = skb_put(skb, wk->ie_len);
memcpy(pos, wk->ie, wk->ie_len);
}

if (wk->assoc.use_11n && wk->assoc.wmm_used &&
local->hw.queues >= 4)
ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie,
sband, wk->chan, wk->assoc.smps);

if (wk->assoc.wmm_used && local->hw.queues >= 4) {
pos = skb_put(skb, 9);
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
Expand All @@ -252,98 +365,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
*pos++ = 0;
}

/* wmm support is a must to HT */
/*
* IEEE802.11n does not allow TKIP/WEP as pairwise
* ciphers in HT mode. We still associate in non-ht
* mode (11a/b/g) if any one of these ciphers is
* configured as pairwise.
*/
if (wk->assoc.use_11n && wk->assoc.wmm_used &&
(local->hw.queues >= 4) &&
sband->ht_cap.ht_supported &&
(ht_ie = wk->assoc.ht_information_ie) &&
ht_ie[1] >= sizeof(struct ieee80211_ht_info)) {
struct ieee80211_ht_info *ht_info =
(struct ieee80211_ht_info *)(ht_ie + 2);
u16 cap = sband->ht_cap.cap;
__le16 tmp;
u32 flags = local->hw.conf.channel->flags;

/* determine capability flags */

if (ieee80211_disable_40mhz_24ghz &&
sband->band == IEEE80211_BAND_2GHZ) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
cap &= ~IEEE80211_HT_CAP_SGI_40;
}

switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
cap &= ~IEEE80211_HT_CAP_SGI_40;
}
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
cap &= ~IEEE80211_HT_CAP_SGI_40;
}
break;
}

/* set SM PS mode properly */
cap &= ~IEEE80211_HT_CAP_SM_PS;
switch (wk->assoc.smps) {
case IEEE80211_SMPS_AUTOMATIC:
case IEEE80211_SMPS_NUM_MODES:
WARN_ON(1);
case IEEE80211_SMPS_OFF:
cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
IEEE80211_HT_CAP_SM_PS_SHIFT;
break;
case IEEE80211_SMPS_STATIC:
cap |= WLAN_HT_CAP_SM_PS_STATIC <<
IEEE80211_HT_CAP_SM_PS_SHIFT;
break;
case IEEE80211_SMPS_DYNAMIC:
cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
IEEE80211_HT_CAP_SM_PS_SHIFT;
break;
}

/* reserve and fill IE */

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));

/* capability flags */
tmp = cpu_to_le16(cap);
memcpy(pos, &tmp, sizeof(u16));
pos += sizeof(u16);

/* AMPDU parameters */
*pos++ = sband->ht_cap.ampdu_factor |
(sband->ht_cap.ampdu_density <<
IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);

/* MCS set */
memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
pos += sizeof(sband->ht_cap.mcs);

/* extended capabilities */
pos += sizeof(__le16);

/* BF capabilities */
pos += sizeof(__le32);

/* antenna selection */
pos += sizeof(u8);
}

IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
ieee80211_tx_skb(sdata, skb);
}
Expand Down

0 comments on commit 91afc45

Please sign in to comment.