2012-02-20 23:17:33

by Lars Bro

[permalink] [raw]
Subject: [PATCH] mac80211 radiotap injection

Building on the work of Sam Leffler, adding the possibility of setting
the tx-power also.

diff --git a/Documentation/networking/mac80211-injection.txt
b/Documentation/networking/mac80211-injection.txt
index 3a93007..cd3d3ef 100644
--- a/Documentation/networking/mac80211-injection.txt
+++ b/Documentation/networking/mac80211-injection.txt
@@ -23,11 +23,28 @@ radiotap headers and used to control injection:
IEEE80211_RADIOTAP_F_FRAG: frame will be fragmented if longer than the
current fragmentation threshold.

+ * IEEE80211_RADIOTAP_RATE
+ legacy transmit rate in .5 Mb/s units (u8)
+
+ * IEEE80211_RADIOTAP_DBM_TX_POWER
+ TX power in dBm for this packet. When not set, default to tx-power, set
+ for the device.
+
* IEEE80211_RADIOTAP_TX_FLAGS

IEEE80211_RADIOTAP_F_TX_NOACK: frame should be sent without waiting for
an ACK even if it is a unicast frame

+ * IEEE80211_RADIOTAP_DATA_RETRIES
+ transmit retry count (u8): may be ignored if NOACK set or bcast/mcast
+ address
+
+ * IEEE80211_RADIOTAP_MCS
+ have_flags(u8), flags(u8), mcs(u8)
+
+ IEEE80211_RADIOTAP_MCS_HAVE_MCS: use MCS value in mcs
+ IEEE80211_RADIOTAP_MCS_HAVE_GI: set GI according to flags
+ IEEE80211_RADIOTAP_MCS_HAVE_BW: set BW according to flags
+
The injection code can also skip all other currently defined radiotap fields
facilitating replay of captured radiotap headers directly.

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index cbff4f9..2821b87 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -378,6 +378,9 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_CTL_DONTFRAG: Don't fragment this packet even if it
* would be fragmented by size (this is optional, only used for
* monitor injection).
+ * @IEEE80211_TX_CTL_NO_RC: This frame does not require rate control.
+ * This flag is used when an injected frame includes a transmit
+ * rate (and possibly flags and retry count) in the radiotap header.
*
* Note: If you have to add new flags to the enumeration, then don't
* forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -412,6 +415,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_NO_RC = BIT(31),
};

#define IEEE80211_TX_CTL_STBC_SHIFT 23
@@ -555,6 +559,7 @@ struct ieee80211_tx_info {
struct ieee80211_vif *vif;
struct ieee80211_key_conf *hw_key;
struct ieee80211_sta *sta;
+ u8 tx_power;
} control;
struct {
struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1be0ca2..692b6c4 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1320,7 +1320,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_NO_RC))
CALL_TXH(ieee80211_tx_h_rate_ctrl);

if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
@@ -1469,7 +1470,8
@@ void
ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
rcu_read_unlock();
}

-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 =
@@ -1477,6 +1479,8
@@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
NULL);
+ u8 fixed_rate, fixed_rate_data_retries;
+ u32 fixed_rate_flags;
u16 txflags;

info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
@@ -1522,12 +1526,41
@@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
info->flags &= ~IEEE80211_TX_CTL_DONTFRAG;
break;

+ case IEEE80211_RADIOTAP_RATE: /* u8 */
+ fixed_rate = *iterator.this_arg;
+ break;
+
case IEEE80211_RADIOTAP_TX_FLAGS:
txflags = get_unaligned_le16(iterator.this_arg);
if (txflags & IEEE80211_RADIOTAP_F_TX_NOACK)
info->flags |= IEEE80211_TX_CTL_NO_ACK;
break;

+ case IEEE80211_RADIOTAP_DATA_RETRIES: /* u8 */
+ fixed_rate_data_retries = *iterator.this_arg;
+ break;
+
+ case IEEE80211_RADIOTAP_MCS: { /* u8,u8,u8 */
+ u8 mcs_have = iterator.this_arg[0];
+ if (mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_MCS) {
+ fixed_rate = iterator.this_arg[2];
+ fixed_rate_flags |= IEEE80211_TX_RC_MCS;
+ }
+ if ((mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_GI) &&
+ (iterator.this_arg[1] & IEEE80211_RADIOTAP_MCS_SGI))
+ fixed_rate_flags |= IEEE80211_TX_RC_SHORT_GI;
+ if ((mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_BW) &&
+ (iterator.this_arg[1]&IEEE80211_RADIOTAP_MCS_BW_40))
+ fixed_rate_flags |=
+ IEEE80211_TX_RC_40_MHZ_WIDTH;
+ break;
+ }
+
+ case IEEE80211_RADIOTAP_DBM_TX_POWER: /* u8 */
+ info->control.tx_power = *iterator.this_arg;
+ break;
+
+
/*
* Please update the file
* Documentation/networking/mac80211-injection.txt
@@ -1542,6 +1575,41
@@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
return false;

+ if (fixed_rate != -1) {
+ struct ieee80211_channel *chan = local->hw.conf.channel;
+ struct ieee80211_supported_band *sband =
+ local->hw.wiphy->bands[chan->band];
+ struct ieee80211_tx_rate *rates = info->control.rates;
+ int i;
+
+ if (fixed_rate_flags & IEEE80211_TX_RC_MCS) {
+ WARN_ON(!sband->ht_cap.ht_supported);
+ rates[0].idx = fixed_rate;
+ } else {
+ /* convert legacy rate; NB: .5 Mb/s -> 100 kb/s */
+ int bitrate = fixed_rate*5;
+ rates[0].idx = 0; /* default to lowest rate */
+ for (i = 0; i < sband->n_bitrates; i++)
+ if (bitrate == sband->bitrates[i].bitrate) {
+ rates[0].idx = i;
+ break;
+ }
+ }
+
+ rates[0].count = 1+fixed_rate_data_retries;
+ if (rates[0].count > local->hw.max_rate_tries)
+ rates[0].count = local->hw.max_rate_tries;
+ rates[0].flags = fixed_rate_flags;
+
+ for (i = 1; i < IEEE80211_TX_MAX_RATES; i++) {
+ rates[i].idx = -1;
+ rates[i].count = 0;
+ rates[i].flags = 0;
+ }
+
+ info->flags |= IEEE80211_TX_CTL_NO_RC;
+ }
+
/*
* remove the radiotap header
* iterator->_max_length was sanity-checked against
@@ -1642,7 +1710,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();
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c
index c4ad795..0e99cb7 100644
--- a/net/wireless/radiotap.c
+++ b/net/wireless/radiotap.c
@@ -41,6 +41,7
@@ static const struct radiotap_align_size rtap_namespace_sizes[] = {
[IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, },
[IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, },
[IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
/*
* add more here as they are defined in radiotap.h
*/




2012-02-23 13:43:11

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH] mac80211 radiotap injection

On Mon, 2012-02-20 at 23:17 +0000, Lars Bro wrote:
> Building on the work of Sam Leffler, adding the possibility of setting
> the tx-power also.

Please read
http://wireless.kernel.org/en/developers/Documentation/SubmittingPatches, particularly the references at the bottom of the page.

Please also follow the style of the surrounding code.

> diff --git a/Documentation/networking/mac80211-injection.txt
> b/Documentation/networking/mac80211-injection.txt
> index 3a93007..cd3d3ef 100644
> --- a/Documentation/networking/mac80211-injection.txt
> +++ b/Documentation/networking/mac80211-injection.txt
> @@ -23,11 +23,28 @@ radiotap headers and used to control injection:
> IEEE80211_RADIOTAP_F_FRAG: frame will be fragmented if longer than the
> current fragmentation threshold.
>
> + * IEEE80211_RADIOTAP_RATE
> + legacy transmit rate in .5 Mb/s units (u8)

This looks quite strange, for example.

> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index cbff4f9..2821b87 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -378,6 +378,9 @@ struct ieee80211_bss_conf {
> * @IEEE80211_TX_CTL_DONTFRAG: Don't fragment this packet even if it
> * would be fragmented by size (this is optional, only used for
> * monitor injection).
> + * @IEEE80211_TX_CTL_NO_RC: This frame does not require rate control.
> + * This flag is used when an injected frame includes a transmit
> + * rate (and possibly flags and retry count) in the radiotap header.

Does that really have to be here? This is the last bit we have, and it
seems this is internal so ... ?

> #define IEEE80211_TX_CTL_STBC_SHIFT 23
> @@ -555,6 +559,7 @@ struct ieee80211_tx_info {
> struct ieee80211_vif *vif;
> struct ieee80211_key_conf *hw_key;
> struct ieee80211_sta *sta;
> + u8 tx_power;

That's not going to be honoured by a lot of devices.

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

that's a very unusual argument order for the mac80211 code

I promise to actually look at the code when you fix all the surrounding
issues, right now I'm quite busy though so not very keen on looking
through this.

johannes


2012-02-24 07:15:15

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH] mac80211 radiotap injection

On Thu, 2012-02-23 at 14:11 -0800, Sam Leffler wrote:
> On Thu, Feb 23, 2012 at 10:47 AM, Johannes Berg
> <[email protected]> wrote:
> > On Thu, 2012-02-23 at 10:45 -0800, Sam Leffler wrote:
>
> >> >> + * @IEEE80211_TX_CTL_NO_RC: This frame does not require rate control.
> >> >> + * This flag is used when an injected frame includes a transmit
> >> >> + * rate (and possibly flags and retry count) in the radiotap header.
> >> >
> >> > Does that really have to be here? This is the last bit we have, and it
> >> > seems this is internal so ... ?
> >>
> >> So ... what? I saw it was the last bit didn't see another way to tag
> >> state in the skb (and the cb looked to be max size so there was no
> >> room to expand it).
> >
> > I was thinking it could be in struct ieee80211_tx_data.flags?
>
> I don't see how to get a handle on a ieee80211_tx_data struct in
> ieee80211_monitor_start_xmit. It looks like the tx path allocates it
> on the stack for all the subhandlers but this is called through the
> netdevice ops vector.

Ok, fair enough. I wasn't sure any more if it was allocated early enough
or if maybe it would be possible to move it. Felix had promised to make
some space in the tx info anyway :)

johannes


2012-02-23 22:11:31

by Sam Leffler

[permalink] [raw]
Subject: Re: [PATCH] mac80211 radiotap injection

On Thu, Feb 23, 2012 at 10:47 AM, Johannes Berg
<[email protected]> wrote:
> On Thu, 2012-02-23 at 10:45 -0800, Sam Leffler wrote:

>> >> + * @IEEE80211_TX_CTL_NO_RC: This frame does not require rate control.
>> >> + * ? This flag is used when an injected frame includes a transmit
>> >> + * ? rate (and possibly flags and retry count) in the radiotap header.
>> >
>> > Does that really have to be here? This is the last bit we have, and it
>> > seems this is internal so ... ?
>>
>> So ... what? ?I saw it was the last bit didn't see another way to tag
>> state in the skb (and the cb looked to be max size so there was no
>> room to expand it).
>
> I was thinking it could be in struct ieee80211_tx_data.flags?

I don't see how to get a handle on a ieee80211_tx_data struct in
ieee80211_monitor_start_xmit. It looks like the tx path allocates it
on the stack for all the subhandlers but this is called through the
netdevice ops vector.

I'll revise the original patch and let Lars work on his separate
change for tx power.

-Sam

2012-02-23 18:45:00

by Sam Leffler

[permalink] [raw]
Subject: Re: [PATCH] mac80211 radiotap injection

On Thu, Feb 23, 2012 at 5:43 AM, Johannes Berg
<[email protected]> wrote:
> On Mon, 2012-02-20 at 23:17 +0000, Lars Bro wrote:
>> Building on the work of Sam Leffler, adding the possibility of setting
>> the tx-power also.
>
> Please read
> http://wireless.kernel.org/en/developers/Documentation/SubmittingPatches, particularly the references at the bottom of the page.
>
> Please also follow the style of the surrounding code.

I tried (for my stuff); it's helpful if you can point out at least one
specific issue. The code went through checkpatch for example.

>
>> diff --git a/Documentation/networking/mac80211-injection.txt
>> b/Documentation/networking/mac80211-injection.txt
>> index 3a93007..cd3d3ef 100644
>> --- a/Documentation/networking/mac80211-injection.txt
>> +++ b/Documentation/networking/mac80211-injection.txt
>> @@ -23,11 +23,28 @@ radiotap headers and used to control injection:
>> ? ? IEEE80211_RADIOTAP_F_FRAG: frame will be fragmented if longer than the
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? current fragmentation threshold.
>>
>> + * IEEE80211_RADIOTAP_RATE
>> + ? legacy transmit rate in .5 Mb/s units (u8)
>
> This looks quite strange, for example.

Strange how? The .5 units are consistent w/ IEEE legacy rate codes.
Not sure how you want to express values like 5.5 to the kernel.

>
>> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
>> index cbff4f9..2821b87 100644
>> --- a/include/net/mac80211.h
>> +++ b/include/net/mac80211.h
>> @@ -378,6 +378,9 @@ struct ieee80211_bss_conf {
>> ? * @IEEE80211_TX_CTL_DONTFRAG: Don't fragment this packet even if it
>> ? * ? would be fragmented by size (this is optional, only used for
>> ? * ? monitor injection).
>> + * @IEEE80211_TX_CTL_NO_RC: This frame does not require rate control.
>> + * ? This flag is used when an injected frame includes a transmit
>> + * ? rate (and possibly flags and retry count) in the radiotap header.
>
> Does that really have to be here? This is the last bit we have, and it
> seems this is internal so ... ?

So ... what? I saw it was the last bit didn't see another way to tag
state in the skb (and the cb looked to be max size so there was no
room to expand it).

>
>> ?#define IEEE80211_TX_CTL_STBC_SHIFT ? ? ? ? ?23
>> @@ -555,6 +559,7 @@ struct ieee80211_tx_info {
>> ? ? ? ? ? ? ? ? ? ? ? struct ieee80211_vif *vif;
>> ? ? ? ? ? ? ? ? ? ? ? struct ieee80211_key_conf *hw_key;
>> ? ? ? ? ? ? ? ? ? ? ? struct ieee80211_sta *sta;
>> + ? ? ? ? ? ? ? ? ? ? u8 tx_power;
>
> That's not going to be honoured by a lot of devices.
>
>>
>> ? ? ? /* process and remove the injection radiotap header */
>> - ? ? if (!ieee80211_parse_tx_radiotap(skb))
>> + ? ? if (!ieee80211_parse_tx_radiotap(skb, local))
>
> that's a very unusual argument order for the mac80211 code
>
> I promise to actually look at the code when you fix all the surrounding
> issues, right now I'm quite busy though so not very keen on looking
> through this.
>
> johannes
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html

2012-02-23 18:47:28

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH] mac80211 radiotap injection

On Thu, 2012-02-23 at 10:45 -0800, Sam Leffler wrote:

> > Please read
> > http://wireless.kernel.org/en/developers/Documentation/SubmittingPatches, particularly the references at the bottom of the page.
> >
> > Please also follow the style of the surrounding code.
>
> I tried (for my stuff); it's helpful if you can point out at least one
> specific issue. The code went through checkpatch for example.

Commit log for instance, in this particular patch.

> >> IEEE80211_RADIOTAP_F_FRAG: frame will be fragmented if longer than the
> >> current fragmentation threshold.
> >>
> >> + * IEEE80211_RADIOTAP_RATE
> >> + legacy transmit rate in .5 Mb/s units (u8)
> >
> > This looks quite strange, for example.
>
> Strange how? The .5 units are consistent w/ IEEE legacy rate codes.
> Not sure how you want to express values like 5.5 to the kernel.

Oh, just the formatting -- the above is indented, this isn't.

> >> + * @IEEE80211_TX_CTL_NO_RC: This frame does not require rate control.
> >> + * This flag is used when an injected frame includes a transmit
> >> + * rate (and possibly flags and retry count) in the radiotap header.
> >
> > Does that really have to be here? This is the last bit we have, and it
> > seems this is internal so ... ?
>
> So ... what? I saw it was the last bit didn't see another way to tag
> state in the skb (and the cb looked to be max size so there was no
> room to expand it).

I was thinking it could be in struct ieee80211_tx_data.flags?

johannes


2012-02-24 07:16:40

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH] mac80211 radiotap injection

On Mon, 2012-02-20 at 23:17 +0000, Lars Bro wrote:

> @@ -555,6 +559,7 @@ struct ieee80211_tx_info {
> struct ieee80211_vif *vif;
> struct ieee80211_key_conf *hw_key;
> struct ieee80211_sta *sta;
> + u8 tx_power;
> } control;

Also, have you counted the bytes here and tried to compile this on a
64-bit machine? Not going to work.

johannes