aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2012-01-28 11:25:33 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-01-30 15:48:26 -0500
commit19468413e8d98d44be8daf0acaf8d576dfc53fa2 (patch)
tree99d7df720566824c4588ccff03c65e60c381e60d /net/mac80211
parent24db78c05b1e3ccb5a78aedd17aa1008c91dab5a (diff)
mac80211: add support for mcs masks
* Handle MCS masks set by the user. * Match rates provided by the rate control algorithm to the mask set, also in HT mode, and switch back to legacy mode if necessary. * add debugfs files to observate the rate selection Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/cfg.c5
-rw-r--r--net/mac80211/debugfs_netdev.c34
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/iface.c7
-rw-r--r--net/mac80211/rate.c124
-rw-r--r--net/mac80211/tx.c5
6 files changed, 167 insertions, 9 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index dc7420441574..d15ba0d0de94 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1902,8 +1902,11 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
1902 return ret; 1902 return ret;
1903 } 1903 }
1904 1904
1905 for (i = 0; i < IEEE80211_NUM_BANDS; i++) 1905 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
1906 sdata->rc_rateidx_mask[i] = mask->control[i].legacy; 1906 sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
1907 memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs,
1908 sizeof(mask->control[i].mcs));
1909 }
1907 1910
1908 return 0; 1911 return 0;
1909} 1912}
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 81d12e65a23c..510ed1dab3c7 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -87,6 +87,21 @@ static ssize_t ieee80211_if_fmt_##name( \
87#define IEEE80211_IF_FMT_SIZE(name, field) \ 87#define IEEE80211_IF_FMT_SIZE(name, field) \
88 IEEE80211_IF_FMT(name, field, "%zd\n") 88 IEEE80211_IF_FMT(name, field, "%zd\n")
89 89
90#define IEEE80211_IF_FMT_HEXARRAY(name, field) \
91static ssize_t ieee80211_if_fmt_##name( \
92 const struct ieee80211_sub_if_data *sdata, \
93 char *buf, int buflen) \
94{ \
95 char *p = buf; \
96 int i; \
97 for (i = 0; i < sizeof(sdata->field); i++) { \
98 p += scnprintf(p, buflen + buf - p, "%.2x ", \
99 sdata->field[i]); \
100 } \
101 p += scnprintf(p, buflen + buf - p, "\n"); \
102 return p - buf; \
103}
104
90#define IEEE80211_IF_FMT_ATOMIC(name, field) \ 105#define IEEE80211_IF_FMT_ATOMIC(name, field) \
91static ssize_t ieee80211_if_fmt_##name( \ 106static ssize_t ieee80211_if_fmt_##name( \
92 const struct ieee80211_sub_if_data *sdata, \ 107 const struct ieee80211_sub_if_data *sdata, \
@@ -148,6 +163,11 @@ IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ],
148 HEX); 163 HEX);
149IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ], 164IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
150 HEX); 165 HEX);
166IEEE80211_IF_FILE(rc_rateidx_mcs_mask_2ghz,
167 rc_rateidx_mcs_mask[IEEE80211_BAND_2GHZ], HEXARRAY);
168IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,
169 rc_rateidx_mcs_mask[IEEE80211_BAND_5GHZ], HEXARRAY);
170
151IEEE80211_IF_FILE(flags, flags, HEX); 171IEEE80211_IF_FILE(flags, flags, HEX);
152IEEE80211_IF_FILE(state, state, LHEX); 172IEEE80211_IF_FILE(state, state, LHEX);
153IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); 173IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC);
@@ -442,6 +462,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
442 DEBUGFS_ADD(channel_type); 462 DEBUGFS_ADD(channel_type);
443 DEBUGFS_ADD(rc_rateidx_mask_2ghz); 463 DEBUGFS_ADD(rc_rateidx_mask_2ghz);
444 DEBUGFS_ADD(rc_rateidx_mask_5ghz); 464 DEBUGFS_ADD(rc_rateidx_mask_5ghz);
465 DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
466 DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
445 467
446 DEBUGFS_ADD(bssid); 468 DEBUGFS_ADD(bssid);
447 DEBUGFS_ADD(aid); 469 DEBUGFS_ADD(aid);
@@ -459,6 +481,8 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
459 DEBUGFS_ADD(channel_type); 481 DEBUGFS_ADD(channel_type);
460 DEBUGFS_ADD(rc_rateidx_mask_2ghz); 482 DEBUGFS_ADD(rc_rateidx_mask_2ghz);
461 DEBUGFS_ADD(rc_rateidx_mask_5ghz); 483 DEBUGFS_ADD(rc_rateidx_mask_5ghz);
484 DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
485 DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
462 486
463 DEBUGFS_ADD(num_sta_authorized); 487 DEBUGFS_ADD(num_sta_authorized);
464 DEBUGFS_ADD(num_sta_ps); 488 DEBUGFS_ADD(num_sta_ps);
@@ -469,6 +493,12 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
469 493
470static void add_ibss_files(struct ieee80211_sub_if_data *sdata) 494static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
471{ 495{
496 DEBUGFS_ADD(channel_type);
497 DEBUGFS_ADD(rc_rateidx_mask_2ghz);
498 DEBUGFS_ADD(rc_rateidx_mask_5ghz);
499 DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
500 DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
501
472 DEBUGFS_ADD_MODE(tsf, 0600); 502 DEBUGFS_ADD_MODE(tsf, 0600);
473} 503}
474 504
@@ -480,6 +510,8 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata)
480 DEBUGFS_ADD(channel_type); 510 DEBUGFS_ADD(channel_type);
481 DEBUGFS_ADD(rc_rateidx_mask_2ghz); 511 DEBUGFS_ADD(rc_rateidx_mask_2ghz);
482 DEBUGFS_ADD(rc_rateidx_mask_5ghz); 512 DEBUGFS_ADD(rc_rateidx_mask_5ghz);
513 DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
514 DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
483 515
484 DEBUGFS_ADD(peer); 516 DEBUGFS_ADD(peer);
485} 517}
@@ -492,6 +524,8 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
492 DEBUGFS_ADD(channel_type); 524 DEBUGFS_ADD(channel_type);
493 DEBUGFS_ADD(rc_rateidx_mask_2ghz); 525 DEBUGFS_ADD(rc_rateidx_mask_2ghz);
494 DEBUGFS_ADD(rc_rateidx_mask_5ghz); 526 DEBUGFS_ADD(rc_rateidx_mask_5ghz);
527 DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
528 DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
495} 529}
496 530
497static void add_monitor_files(struct ieee80211_sub_if_data *sdata) 531static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ca6486b941b6..d47e8c110b16 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -646,6 +646,7 @@ struct ieee80211_sub_if_data {
646 646
647 /* bitmap of allowed (non-MCS) rate indexes for rate control */ 647 /* bitmap of allowed (non-MCS) rate indexes for rate control */
648 u32 rc_rateidx_mask[IEEE80211_NUM_BANDS]; 648 u32 rc_rateidx_mask[IEEE80211_NUM_BANDS];
649 u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN];
649 650
650 union { 651 union {
651 struct ieee80211_if_ap ap; 652 struct ieee80211_if_ap ap;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 6b0d70e960d4..c33feede5dca 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1181,6 +1181,13 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
1181 sband = local->hw.wiphy->bands[i]; 1181 sband = local->hw.wiphy->bands[i];
1182 sdata->rc_rateidx_mask[i] = 1182 sdata->rc_rateidx_mask[i] =
1183 sband ? (1 << sband->n_bitrates) - 1 : 0; 1183 sband ? (1 << sband->n_bitrates) - 1 : 0;
1184 if (sband)
1185 memcpy(sdata->rc_rateidx_mcs_mask[i],
1186 sband->ht_cap.mcs.rx_mask,
1187 sizeof(sdata->rc_rateidx_mcs_mask[i]));
1188 else
1189 memset(sdata->rc_rateidx_mcs_mask[i], 0,
1190 sizeof(sdata->rc_rateidx_mcs_mask[i]));
1184 } 1191 }
1185 1192
1186 /* setup type-dependent data */ 1193 /* setup type-dependent data */
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index a21110aecd1a..3fef26d8898a 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -289,8 +289,8 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
289} 289}
290EXPORT_SYMBOL(rate_control_send_low); 290EXPORT_SYMBOL(rate_control_send_low);
291 291
292static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, 292static bool rate_idx_match_legacy_mask(struct ieee80211_tx_rate *rate,
293 int n_bitrates, u32 mask) 293 int n_bitrates, u32 mask)
294{ 294{
295 int j; 295 int j;
296 296
@@ -299,7 +299,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
299 if (mask & (1 << j)) { 299 if (mask & (1 << j)) {
300 /* Okay, found a suitable rate. Use it. */ 300 /* Okay, found a suitable rate. Use it. */
301 rate->idx = j; 301 rate->idx = j;
302 return; 302 return true;
303 } 303 }
304 } 304 }
305 305
@@ -308,6 +308,112 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
308 if (mask & (1 << j)) { 308 if (mask & (1 << j)) {
309 /* Okay, found a suitable rate. Use it. */ 309 /* Okay, found a suitable rate. Use it. */
310 rate->idx = j; 310 rate->idx = j;
311 return true;
312 }
313 }
314 return false;
315}
316
317static bool rate_idx_match_mcs_mask(struct ieee80211_tx_rate *rate,
318 u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
319{
320 int i, j;
321 int ridx, rbit;
322
323 ridx = rate->idx / 8;
324 rbit = rate->idx % 8;
325
326 /* sanity check */
327 if (ridx < 0 || ridx > IEEE80211_HT_MCS_MASK_LEN)
328 return false;
329
330 /* See whether the selected rate or anything below it is allowed. */
331 for (i = ridx; i >= 0; i--) {
332 for (j = rbit; j >= 0; j--)
333 if (mcs_mask[i] & BIT(j)) {
334 rate->idx = i * 8 + j;
335 return true;
336 }
337 rbit = 7;
338 }
339
340 /* Try to find a higher rate that would be allowed */
341 ridx = (rate->idx + 1) / 8;
342 rbit = (rate->idx + 1) % 8;
343
344 for (i = ridx; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
345 for (j = rbit; j < 8; j++)
346 if (mcs_mask[i] & BIT(j)) {
347 rate->idx = i * 8 + j;
348 return true;
349 }
350 rbit = 0;
351 }
352 return false;
353}
354
355
356
357static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
358 struct ieee80211_tx_rate_control *txrc,
359 u32 mask,
360 u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
361{
362 struct ieee80211_tx_rate alt_rate;
363
364 /* handle HT rates */
365 if (rate->flags & IEEE80211_TX_RC_MCS) {
366 if (rate_idx_match_mcs_mask(rate, mcs_mask))
367 return;
368
369 /* also try the legacy rates. */
370 alt_rate.idx = 0;
371 /* keep protection flags */
372 alt_rate.flags = rate->flags &
373 (IEEE80211_TX_RC_USE_RTS_CTS |
374 IEEE80211_TX_RC_USE_CTS_PROTECT |
375 IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
376 alt_rate.count = rate->count;
377 if (rate_idx_match_legacy_mask(&alt_rate,
378 txrc->sband->n_bitrates,
379 mask)) {
380 *rate = alt_rate;
381 return;
382 }
383 } else {
384 struct sk_buff *skb = txrc->skb;
385 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
386 __le16 fc;
387
388 /* handle legacy rates */
389 if (rate_idx_match_legacy_mask(rate, txrc->sband->n_bitrates,
390 mask))
391 return;
392
393 /* if HT BSS, and we handle a data frame, also try HT rates */
394 if (txrc->bss_conf->channel_type == NL80211_CHAN_NO_HT)
395 return;
396
397 fc = hdr->frame_control;
398 if (!ieee80211_is_data(fc))
399 return;
400
401 alt_rate.idx = 0;
402 /* keep protection flags */
403 alt_rate.flags = rate->flags &
404 (IEEE80211_TX_RC_USE_RTS_CTS |
405 IEEE80211_TX_RC_USE_CTS_PROTECT |
406 IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
407 alt_rate.count = rate->count;
408
409 alt_rate.flags |= IEEE80211_TX_RC_MCS;
410
411 if ((txrc->bss_conf->channel_type == NL80211_CHAN_HT40MINUS) ||
412 (txrc->bss_conf->channel_type == NL80211_CHAN_HT40PLUS))
413 alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
414
415 if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) {
416 *rate = alt_rate;
311 return; 417 return;
312 } 418 }
313 } 419 }
@@ -331,6 +437,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
331 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); 437 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
332 int i; 438 int i;
333 u32 mask; 439 u32 mask;
440 u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
334 441
335 if (sta) { 442 if (sta) {
336 ista = &sta->sta; 443 ista = &sta->sta;
@@ -354,10 +461,14 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
354 * the common case. 461 * the common case.
355 */ 462 */
356 mask = sdata->rc_rateidx_mask[info->band]; 463 mask = sdata->rc_rateidx_mask[info->band];
464 memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band],
465 sizeof(mcs_mask));
357 if (mask != (1 << txrc->sband->n_bitrates) - 1) { 466 if (mask != (1 << txrc->sband->n_bitrates) - 1) {
358 if (sta) { 467 if (sta) {
359 /* Filter out rates that the STA does not support */ 468 /* Filter out rates that the STA does not support */
360 mask &= sta->sta.supp_rates[info->band]; 469 mask &= sta->sta.supp_rates[info->band];
470 for (i = 0; i < sizeof(mcs_mask); i++)
471 mcs_mask[i] &= sta->sta.ht_cap.mcs.rx_mask[i];
361 } 472 }
362 /* 473 /*
363 * Make sure the rate index selected for each TX rate is 474 * Make sure the rate index selected for each TX rate is
@@ -368,11 +479,8 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
368 /* Skip invalid rates */ 479 /* Skip invalid rates */
369 if (info->control.rates[i].idx < 0) 480 if (info->control.rates[i].idx < 0)
370 break; 481 break;
371 /* Rate masking supports only legacy rates for now */ 482 rate_idx_match_mask(&info->control.rates[i], txrc,
372 if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) 483 mask, mcs_mask);
373 continue;
374 rate_idx_match_mask(&info->control.rates[i],
375 txrc->sband->n_bitrates, mask);
376 } 484 }
377 } 485 }
378 486
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index e05667cd5e76..1be0ca2b5936 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -635,6 +635,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
635 txrc.max_rate_idx = -1; 635 txrc.max_rate_idx = -1;
636 else 636 else
637 txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; 637 txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
638 memcpy(txrc.rate_idx_mcs_mask,
639 tx->sdata->rc_rateidx_mcs_mask[tx->channel->band],
640 sizeof(txrc.rate_idx_mcs_mask));
638 txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || 641 txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
639 tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT || 642 tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
640 tx->sdata->vif.type == NL80211_IFTYPE_ADHOC); 643 tx->sdata->vif.type == NL80211_IFTYPE_ADHOC);
@@ -2431,6 +2434,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2431 txrc.max_rate_idx = -1; 2434 txrc.max_rate_idx = -1;
2432 else 2435 else
2433 txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; 2436 txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
2437 memcpy(txrc.rate_idx_mcs_mask, sdata->rc_rateidx_mcs_mask[band],
2438 sizeof(txrc.rate_idx_mcs_mask));
2434 txrc.bss = true; 2439 txrc.bss = true;
2435 rate_control_get_rate(sdata, NULL, &txrc); 2440 rate_control_get_rate(sdata, NULL, &txrc);
2436 2441