Skip to contentSkip to conversation

Radiotap on Monitor Mode interfaces for rx and tx

PATCH In review [email protected] 3 participants 15 messages Mar 17, 2007 – Mar 18, 2007 mac80211

lore
Share & tools
lore
#0 lore raw

cover Radiotap on Monitor Mode interfaces for rx and tx

Hi folks -

This pair of patches change the Monitor Mode wireless interfaces to use radiotap both for monitoring and for packet injection. The monitoring side is done by a patch from Michael Wu. Tcpdump knows how to handle the result.

For injecting packets, the you issue a packet using libpcap or a SOCK_PACKET socket down an interface to the wireless device that is in Monitor Mode. The packet has a normal radiotap header prepended to the IEEE80211 header. The radiotap header is variable length depending on what the user wants to specify, currently the transmit rate, power and antenna can be specified using normal radiotap semantics. Any other entries are skipped.

A usermode app packetspammer is available from here

http://penumbra.warmcat.com/_twk/tiki-index.php?page=packetspammer

which allows easy injection of these packets from the commandline. At the moment it loops issuing packets at a variety of rates which can be seen from another machine's monitor mode interface on the same channel. There are instructions for build and using it on the page above.

Currently it has been tested for both rx and tx using zd1211rw-mac80211 and works except for 1Mbps TX (54Mbps - 2Mbps works) and the rx radiotap rate is not shown in tcpdump.

The patches should be based against wireless-dev.

#1 lore raw

PATCH 1/2 mac80211: Add radiotap support

From: Michael Wu <[email protected]>

---

 include/net/mac80211.h         |    3 ++
 net/mac80211/ieee80211.c       |   69 +++++++++++++++++++++++++++++++++-------
 net/mac80211/ieee80211_iface.c |    2 +
 3 files changed, 61 insertions(+), 13 deletions(-)
include/net/mac80211.h +3 -0
index 916b21b..050f126 100644
@@ -529,6 +529,9 @@ struct ieee80211_hw {
 	 * per-packet RC4 key with each TX frame when doing hwcrypto */
 #define IEEE80211_HW_TKIP_REQ_PHASE2_KEY (1<<14)
 
+	/* Driver supports radiotap. Temporary until all drivers support it. */
+#define IEEE80211_HW_RADIOTAP_SUPPORTED (1<<20)
+
 	u32 flags;			/* hardware flags defined above */
 
 	/* Set to the size of a needed device specific skb headroom for TX skbs. */
net/mac80211/ieee80211.c +57 -12

120 lines not on this page · raw message

net/mac80211/ieee80211_iface.c +1 -1
index 3e0b4fa..51197b1 100644
@@ -199,7 +199,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
 		break;
 	}
 	case IEEE80211_IF_TYPE_MNTR:
-		dev->type = ARPHRD_IEEE80211_PRISM;
+		dev->type = ARPHRD_IEEE80211_RADIOTAP;
 		break;
 	default:
 		printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
#2 lore raw

PATCH 2/2 mac80211: Monitor mode radiotap-based packet injection

In reply to [email protected]

From: Andy Green <[email protected]>

Try #2
- took Michael Wu's advice about better tools and basing on wireless-dev
- took Luis Rodriguez's advice about coding style makeover
- took Pavel Roskin's advice about little-endian radiotap

Index: linux-2.6.20.i386/include/net/mac80211.h
===================================================

include/net/mac80211.h +1 -0
index 4fc8edc..bb5777e 100644
@@ -189,6 +189,7 @@ struct ieee80211_tx_control {
 #define IEEE80211_TXCTL_FIRST_FRAGMENT	(1<<8) /* this is a first fragment of
 						* the frame */
 #define IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY (1<<9)
+#define IEEE80211_TXCTL_INJECTED_PACKET (1<<10) /* tx into monitor IF */
 	u32 flags;			       /* tx control flags defined
 						* above */
 	u8 retry_limit;		/* 1 = only first attempt, 2 = one retry, .. */
net/mac80211/ieee80211.c +242 -9

303 lines not on this page · raw message

net/mac80211/ieee80211_i.h +1 -0
index 9df8ef0..617d297 100644
@@ -162,6 +162,7 @@ struct ieee80211_tx_packet_data {
 	unsigned int requeue:1;
 	unsigned int mgmt_iface:1;
 	unsigned int queue:4;
+	unsigned int is_injected_into_monitor:1;
 };
 
 struct ieee80211_tx_stored_packet {
#3 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

Quoted 15 lines · On Saturday 17 March 2007 11:58, [email protected] wrote:

From: Andy Green <[email protected]>

Try #2
- took Michael Wu's advice about better tools and basing on wireless-dev
- took Luis Rodriguez's advice about coding style makeover
- took Pavel Roskin's advice about little-endian radiotap

Index: linux-2.6.20.i386/include/net/mac80211.h
===================================================

include/net/mac80211.h +0 -0
index 4fc8edc..bb5777e 100644

include/net/mac80211.h struct ieee80211_tx_control { · line 192

Quoted 4 lines
include/net/mac80211.h +1 -0
@@ -189,6 +189,7 @@ struct ieee80211_tx_control {
 #define IEEE80211_TXCTL_FIRST_FRAGMENT	(1<<8) /* this is a first fragment of
 						* the frame */
 #define IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY (1<<9)
+#define IEEE80211_TXCTL_INJECTED_PACKET (1<<10) /* tx into monitor IF */

What is a driver supposed to do on this flag? More documentation, please.

Signature · 1 line
Greetings Michael.
author
#4 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

Quoted 3 lines · Michael Buesch
Quoted 1 line

+#define IEEE80211_TXCTL_INJECTED_PACKET (1<<10) /* tx into monitor IF */

What is a driver supposed to do on this flag? More documentation, please.

Hi Michael -

The driver doesn't have to do anything with that flag... it's a private mac80211-internal flag to get the attribute that the packet was injected into a Monitor interface into ieee80211_tx_control where __ieee80211_tx_prepare() can access that information. By then as I understood it the information that the packet came in on the monitor interface isn't available because we redirected it to the master interface. That one bit of state, that the packet originated from a send() to a Montitor Mode interface is the meaning of the flag.

Currently the information travels like this:

- ieee80211_subif_start_xmit() sees that it is a monitor mode interface getting the packet.

- It sets ieee80211_tx_packet_data.is_injected_into_monitor, which
travels with the packet inside skb.cb.

- ieee80211_master_start_xmit() eventually gets the packet and
examines the ieee80211_tx_packet_data in the skb.cb. If is_injected_into_monitor is set, it sets control.flags |= IEEE80211_TXCTL_INJECTED_PACKET. This is done because at the start of ieee80211_master_start_xmit() there is a comment

	/*
	 * copy control out of the skb so other people can use skb->cb
	 */

- finally the end user __ieee80211_tx_prepare() is able to find the
state information in control->flags & IEEE80211_TXCTL_INJECTED_PACKET and work out if it expects a radiotap header prepended or not from that.

If there's a simpler way I'm happy to use it.

-Andy

#5 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

Quoted 4 lines · Andy Green
Quoted 2 lines · Michael Buesch
Quoted 1 line

+#define IEEE80211_TXCTL_INJECTED_PACKET (1<<10) /* tx into monitor IF */

Quoted 8 lines
Quoted 1 line

What is a driver supposed to do on this flag? More documentation, please.

Hi Michael -

The driver doesn't have to do anything with that flag... it's a private mac80211-internal flag to get the attribute that the packet was injected

If there's a simpler way I'm happy to use it.

Ok, no. I'm fine with this. But please mark it as mac80211-internal flag, so driver authors don't waste time on thinking about wtf this is. ;) Either by documenting it in a comment or by doing a special define (two underscores or something). Or both.

Signature · 1 line
Greetings Michael.
author
#6 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

Quoted 7 lines · Michael Buesch
Quoted 6 lines · Andy Green
Quoted 2 lines · Michael Buesch
Quoted 1 line

+#define IEEE80211_TXCTL_INJECTED_PACKET (1<<10) /* tx into monitor IF */

What is a driver supposed to do on this flag? More documentation, please.

Hi Michael -

Quoted 8 lines
Quoted 3 lines

The driver doesn't have to do anything with that flag... it's a private mac80211-internal flag to get the attribute that the packet was injected

If there's a simpler way I'm happy to use it.

Ok, no. I'm fine with this. But please mark it as mac80211-internal flag, so driver authors don't waste time on thinking about wtf this is. ;) Either by documenting it in a comment or by doing a special define (two underscores or something). Or both.

Both sounds like a good idea, thanks: I will wait a bit for any more comments and then add this to a try #3. I noticed Michael Wu set his flag to 1<<20 and I guess he had this in mind, so I will change mine to 1<<21 to further distance it from the other flags in bits and in meaning.

-Andy

#7 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

In reply to [email protected]

net/mac80211/ieee80211.c line 39

Quoted 10 lines · On Saturday 17 March 2007 06:58, [email protected] wrote:
net/mac80211/ieee80211.c +1 -0
index fb33b90..3873262 100644
@@ -35,6 +35,7 @@
 #include "ieee80211_led.h"
 #include "ieee80211_cfg.h"
 #include "ieee80211_sysfs.h"
+#include <net/ieee80211_radiotap.h>
 

Already included by my patch.

net/mac80211/ieee80211.c ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) · line 1103

Quoted 4 lines
net/mac80211/ieee80211.c +4 -0
+	int tap_index = 0;
+	u8 *tap_arg = skb->data + sizeof(struct ieee80211_radiotap_header);
+	u32 *curr_arg_bitmap = &rthdr->it_present;
+	u32 arg_bitmap=le32_to_cpu(*curr_arg_bitmap);

Space before and after the =.

net/mac80211/ieee80211.c

Quoted 2 lines
net/mac80211/ieee80211.c +2 -0
+
+	if(rthdr->it_version) return TXRX_DROP; /* version byte used as magic */

Space after the if.

net/mac80211/ieee80211.c

Quoted 2 lines
net/mac80211/ieee80211.c +2 -0
+
+		/* sanity check for skb length and radiotap length field */

Keep comments indented the same as everything else.

net/mac80211/ieee80211.c ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) · line 1109

Quoted 2 lines
net/mac80211/ieee80211.c +2 -0
+	if (skb->len < (le16_to_cpu(rthdr->it_len) +
+		sizeof(struct ieee80211_hdr)))

Using some spaces to align the start of the second line with the parenthesis often looks better.

net/mac80211/ieee80211.c __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, · line 1243

Quoted 3 lines
net/mac80211/ieee80211.c +3 -0
+		/* process and remove the injection radiotap header */
+
+	if(control->flags & IEEE80211_TXCTL_INJECTED_PACKET) {

dev points to the virtual interface that the frame originally came in on. You can get sdata from that and figure out if the interface was a monitor interface.

Thanks,
-Michael Wu

#8 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

Quoted 8 lines · Michael Wu

net/mac80211/ieee80211.c __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, · line 1243

Quoted 3 lines
net/mac80211/ieee80211.c +3 -0
+		/* process and remove the injection radiotap header */
+
+	if(control->flags & IEEE80211_TXCTL_INJECTED_PACKET) {

dev points to the virtual interface that the frame originally came in on. You can get sdata from that and figure out if the interface was a monitor interface.

Of course, this depends on ifindex being set properly.

You added:

	pkt_data->ifindex =  local->mdev->ifindex;

but in that same function, this is used instead:

	pkt_data->ifindex = sdata->dev->ifindex;

Which allows the master device to figure out which virtual interface the skb came from.

-Michael Wu

author
#9 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

Quoted 10 lines · Michael Wu
Quoted 7 lines · Michael Wu

net/mac80211/ieee80211.c __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, · line 1243

Quoted 3 lines
net/mac80211/ieee80211.c +3 -0
+		/* process and remove the injection radiotap header */
+
+	if(control->flags & IEEE80211_TXCTL_INJECTED_PACKET) {

dev points to the virtual interface that the frame originally came in on. You can get sdata from that and figure out if the interface was a monitor interface.

Of course, this depends on ifindex being set properly.

Quoted 7 lines

You added:

	pkt_data->ifindex =  local->mdev->ifindex;

but in that same function, this is used instead:

	pkt_data->ifindex = sdata->dev->ifindex;

Which allows the master device to figure out which virtual interface the skb came from.

Yeah naturally it was my first move to use what was there, but the result was a panic that went away when I moved the skb to belong to the "master" interface's index and separately persistently tagged the packet as being injected.

Is it safe against race problems on interface removal to consider to look up against the interface index at actual send time?

-Andy

#10 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

Quoted 5 lines · Andy Green

Yeah naturally it was my first move to use what was there, but the result was a panic that went away when I moved the skb to belong to the "master" interface's index and separately persistently tagged the packet as being injected.

I don't see anything that would prevent this from working.. if you have a patch which does this and crashes, I'll take a look at it.

Quoted 3 lines

Is it safe against race problems on interface removal to consider to look up against the interface index at actual send time?

Yes. dev_get_by_index in ieee80211_master_start_xmit calls dev_hold. When it is done, dev_put is called. The headroom reservation code looks suspicious though.. it doesn't call dev_put if it fails. Fortunately, this is unlikely to happen.

Thanks,
-Michael Wu

author
#11 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

Quoted 7 lines · Michael Wu
Quoted 5 lines · Andy Green

Yeah naturally it was my first move to use what was there, but the result was a panic that went away when I moved the skb to belong to the "master" interface's index and separately persistently tagged the packet as being injected.

I don't see anything that would prevent this from working.. if you have a patch which does this and crashes, I'll take a look at it.

Okay I will try to regenerate this situation tomorrow afternoon, which will be my next chance.

-Andy

author
#12 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

Quoted 10 lines · Andy Green
Quoted 7 lines · Michael Wu
Quoted 5 lines · Andy Green

Yeah naturally it was my first move to use what was there, but the result was a panic that went away when I moved the skb to belong to the "master" interface's index and separately persistently tagged the packet as being injected.

I don't see anything that would prevent this from working.. if you have a patch which does this and crashes, I'll take a look at it.

Okay I will try to regenerate this situation tomorrow afternoon, which will be my next chance.

Well the panic did not return, I guess whatever I was doing that provoked it I am not doing any more. So I changed it back to the sdata->dev->ifindex that the normal code path uses and confirmed that continued to worked okay.

However when I went on to look at leveraging that to find out if the originating interface was in Monitor mode, it seems that it might be a little bit more expensive to do that -- and it would have to be done for every tx packet in order to find out if it was injected. By contrast with the currently proposed staged system at each level the information is always available without processing, and the overhead for the common case where the packet was not injected is just testing if the if type was monitor, and then later testing a bit in flags that are already available.

From looking around the existing code, it seems something like this is called for to use the ifindex instead:

__ieee80211_tx_prepare(...)

{
	struct ieee80211_tx_packet_data *pkt_data;

	/* skb->cb is still valid by this time? */

	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;

	/* dev_get_by_index holds a read lock and iterates
	 * a hlist, done for every tx packet */

	originating_dev = dev_get_by_index(pkt_data->ifindex);
	if(!originating_dev) goto skipped;
	if (unlikely(!is_ieee80211_device(originating_dev, dev))) {
		goto give_up_dev;
	}

	originating__sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	if(!originating__sdata) goto give_up_dev;

	if (unlikely(originating__sdata->type==IEEE80211_IF_TYPE_MNTR)){
...
	}
	give_up_dev:
	dev_put(originating_dev);
	skipped:

...
}

Given this, if it is actually the leanest implementation of using ifindex, is it still preferred?

-Andy

author
#13 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

Quoted 4 lines · Andy Green

However when I went on to look at leveraging that to find out if the originating interface was in Monitor mode, it seems that it might be a little bit more expensive to do that -- and it would have to be done for every tx packet in order to find out if it was injected. By contrast with the currently proposed staged system at each level the information is always available without processing, and the overhead for the common case where the packet was not injected is just testing if the if type was monitor, and then later testing a bit in flags that are already available.

From looking around the existing code, it seems something like this is
called for to use the ifindex instead:

Ha, ignore this, Michael's method works just with what is to hand. Try #3 coming up.

-Andy

author
#14 lore raw

Re: [PATCH 2/2] mac80211: Monitor mode radiotap-based packet injection

In reply to Michael Wu
Quoted 12 lines · Michael Wu

net/mac80211/ieee80211.c line 39

Quoted 10 lines · On Saturday 17 March 2007 06:58, [email protected] wrote:
net/mac80211/ieee80211.c +1 -0
index fb33b90..3873262 100644
@@ -35,6 +35,7 @@
 #include "ieee80211_led.h"
 #include "ieee80211_cfg.h"
 #include "ieee80211_sysfs.h"
+#include <net/ieee80211_radiotap.h>
 

Already included by my patch.

OK. Not sure why that appears in my patch any longer then since I am using guilt thanks to your advice, and your patch is applied first.

Quoted 5 lines

net/mac80211/ieee80211.c ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) · line 1103

Quoted 4 lines
net/mac80211/ieee80211.c +4 -0
+	int tap_index = 0;
+	u8 *tap_arg = skb->data + sizeof(struct ieee80211_radiotap_header);
+	u32 *curr_arg_bitmap = &rthdr->it_present;
+	u32 arg_bitmap=le32_to_cpu(*curr_arg_bitmap);

Space before and after the =.

Fixed.

Quoted 3 lines

net/mac80211/ieee80211.c

Quoted 2 lines
net/mac80211/ieee80211.c +2 -0
+
+	if(rthdr->it_version) return TXRX_DROP; /* version byte used as magic */

Space after the if.

Fixed.

Quoted 3 lines

net/mac80211/ieee80211.c

Quoted 2 lines
net/mac80211/ieee80211.c +2 -0
+
+		/* sanity check for skb length and radiotap length field */

Keep comments indented the same as everything else.

Fixed.

Quoted 3 lines

net/mac80211/ieee80211.c ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) · line 1109

Quoted 2 lines
net/mac80211/ieee80211.c +2 -0
+	if (skb->len < (le16_to_cpu(rthdr->it_len) +
+		sizeof(struct ieee80211_hdr)))

Using some spaces to align the start of the second line with the parenthesis often looks better.

Fixed and noted.

Quoted 4 lines

net/mac80211/ieee80211.c __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, · line 1243

Quoted 3 lines
net/mac80211/ieee80211.c +3 -0
+		/* process and remove the injection radiotap header */
+
+	if(control->flags & IEEE80211_TXCTL_INJECTED_PACKET) {

dev points to the virtual interface that the frame originally came in on. You can get sdata from that and figure out if the interface was a monitor interface.

replied in next mail...

-Andy