2013-12-11 18:24:29

by Cedric VONCKEN

[permalink] [raw]
Subject: [RFC mac80211] Add field in radiotap parser

In radiotap parser I added the field management for
IEEE80211_RADIOTAP_RATE and IEEE80211_RADIOTAP_MCS (to inject packet at
specific rate).
My modifications worked on compat 2013-04-16 and ath9K.

I preparing the patch for the latest wireless version, and all value for
the flags field in struct ieee80211_tx_info are used (declared in enum
mac80211_tx_control_flags in mac80211.h).

I need to add this to bypass the RC in mac80211.

How I can add the new flag ?
- I change the flags type to u64
- I add a second flag field in the struct ieee80211_tx_info (for
exemple flags_ext)

My patch for the compat 2013-04-16 (the bit 31 is not used in this
version)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 87a8e0b..0445c27 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -494,6 +494,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_STATUS_EOSP = BIT(28),
IEEE80211_TX_CTL_USE_MINRATE = BIT(29),
IEEE80211_TX_CTL_DONTFRAG = BIT(30),
+ IEEE80211_TX_CTL_RC_BYPASS = BIT(31),
};

#define IEEE80211_TX_CTL_STBC_SHIFT 23
@@ -509,7 +510,8 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK |
\
IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_NO_PS_BUFFER
| \
IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC |
\
- IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP)
+ IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP |
\
+ IEEE80211_TX_CTL_RC_BYPASS)

/**
* enum mac80211_rate_control_flags - per-rate flags set by the
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 904c3b6..dc414d5 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1308,7 +1308,8 @@ static int invoke_tx_handlers(struct
ieee80211_tx_data *tx)
CALL_TXH(ieee80211_tx_h_ps_buf);
CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
CALL_TXH(ieee80211_tx_h_select_key);
- if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
+ if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) &&
+ !(info->flags & IEEE80211_TX_CTL_RC_BYPASS))
CALL_TXH(ieee80211_tx_h_rate_ctrl);

if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
@@ -1462,16 +1463,25 @@ void ieee80211_xmit(struct ieee80211_sub_if_data
*sdata, struct sk_buff *skb,
ieee80211_tx(sdata, skb, false, band);
}

-static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
+static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
+ struct ieee80211_local *local)
{
struct ieee80211_radiotap_iterator iterator;
struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr,
skb->len,
- NULL);
+ struct ieee80211_channel *chan = local->monitor_chandef.chan;
+ struct ieee80211_supported_band *sband =
+ local->hw.wiphy->bands[chan->band];
u16 txflags;
+ s8 rate_idx;
+ u16 bit_rate;
+ int i;
+ unsigned char known;
+ unsigned char flags;

+ int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr,
skb->len,
+ NULL);
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
IEEE80211_TX_CTL_DONTFRAG;

@@ -1521,6 +1531,58 @@ static bool ieee80211_parse_tx_radiotap(struct
sk_buff *skb)
info->flags |= IEEE80211_TX_CTL_NO_ACK;
break;

+ case IEEE80211_RADIOTAP_RATE:
+ rate_idx = -1;
+ /* convert legacy rate; NB: .5 Mb/s -> 100 kb/s
*/
+ bit_rate = *iterator.this_arg * 5;
+ for (i = 0; i< sband->n_bitrates; i++){
+ if (sband->bitrates[i].bitrate ==
bit_rate) {
+ rate_idx = i;
+ break;
+ }
+ }
+ /* Rate not available - rejecting */
+ if (rate_idx< 0)
+ return false;
+
+ info->flags |= IEEE80211_TX_CTL_RC_BYPASS;
+ info->control.rates[0].idx = rate_idx;
+ info->control.rates[0].count = 1;
+ break;
+
+ case IEEE80211_RADIOTAP_MCS:
+ known = iterator.this_arg[0];
+ flags = iterator.this_arg[1];
+ rate_idx = iterator.this_arg[2];
+
+ /* 11n not supported - rejecting */
+ if(!sband->ht_cap.ht_supported) {
+ return false;
+ }
+
+ /* set mcs */
+ if(known & IEEE80211_RADIOTAP_MCS_HAVE_MCS) {
+ info->control.rates[0].idx = rate_idx;
+ info->control.rates[0].flags |=
+ IEEE80211_TX_RC_MCS;
+ }
+
+ /* set GI */
+ if ((known & IEEE80211_RADIOTAP_MCS_HAVE_GI) &&
+ ( flags & IEEE80211_RADIOTAP_MCS_SGI))
+ info->control.rates[0].flags |=
+ IEEE80211_TX_RC_SHORT_GI;
+
+ /* set bandwith */
+ if ((known & IEEE80211_RADIOTAP_MCS_HAVE_BW) &&
+ (flags & IEEE80211_RADIOTAP_MCS_BW_40))
+ info->control.rates[0].flags |=
+ IEEE80211_TX_RC_40_MHZ_WIDTH;
+
+ info->control.rates[0].count = 1;
+ info->flags |= IEEE80211_TX_CTL_RC_BYPASS;
+ break;
+
/*
* Please update the file
* Documentation/networking/mac80211-injection.txt
@@ -1616,7 +1678,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct
sk_buff *skb,
IEEE80211_TX_CTL_INJECTED;

/* process and remove the injection radiotap header */
- if (!ieee80211_parse_tx_radiotap(skb))
+ if (!ieee80211_parse_tx_radiotap(skb,local))
goto fail;

rcu_read_lock();

Cedric Voncken