Skip to contentSkip to conversation

d80211: Add software sequence support

PATCH Superseded Ivo van Doorn 7 participants 28 messages Feb 14, 2007 – Mar 23, 2007

Subsystems (2)

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 d80211: Add software sequence support

Most hardware can keep track of sequence numbers themselves, unfortunately *most* doesn't cover all devices. ;) This patch will keep track of the (per-bss) sequence number if the flag IEEE80211_HW_SOFTWARE_SEQUENCE has been set.

---

include/net/d80211.h +3 -0
index 326def5..5dd4943 100644
@@ -534,6 +534,9 @@ struct ieee80211_hw {
 	 * per-packet RC4 key with each TX frame when doing hwcrypto */
 #define IEEE80211_HW_TKIP_REQ_PHASE2_KEY (1<<14)
 
+	/* Does the HOST need to insert the frame sequence counter */
+#define IEEE80211_HW_SOFTWARE_SEQUENCE (1<<15)
+
 	u32 flags;			/* hardware flags defined above */
 
 	/* Set to the size of a needed device specific skb headroom for TX skbs. */
net/d80211/ieee80211.c +42 -1

85 lines not on this page · raw message

net/d80211/ieee80211_i.h +5 -0
index 5ab9eb5..1891e05 100644
@@ -80,6 +80,7 @@ struct ieee80211_sta_bss {
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	size_t ssid_len;
 	u16 capability; /* host byte order */
+	u16 sequence;
 	int hw_mode;
 	int channel;
 	int freq;
@@ -682,6 +683,10 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
 					 u8 *addr);
 int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
 int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
+struct ieee80211_sta_bss *
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid);
+void ieee80211_rx_bss_put(struct net_device *dev,
+			  struct ieee80211_sta_bss *bss);
 
 /* ieee80211_dev.c */
 int ieee80211_dev_alloc_index(struct ieee80211_local *local);
net/d80211/ieee80211_sta.c +3 -7
index 433a11b..64c9c9f 100644
@@ -57,10 +57,6 @@
 
 static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
 				     u8 *ssid, size_t ssid_len);
-static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid);
-static void ieee80211_rx_bss_put(struct net_device *dev,
-				 struct ieee80211_sta_bss *bss);
 static int ieee80211_sta_find_ibss(struct net_device *dev,
 				   struct ieee80211_if_sta *ifsta);
 static int ieee80211_sta_wep_configured(struct net_device *dev);
@@ -1274,7 +1270,7 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
 }
 
 
-static struct ieee80211_sta_bss *
+struct ieee80211_sta_bss *
 ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid)
 {
 	struct ieee80211_local *local = dev->ieee80211_ptr;
@@ -1303,8 +1299,8 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
 }
 
 
-static void ieee80211_rx_bss_put(struct net_device *dev,
-				 struct ieee80211_sta_bss *bss)
+void ieee80211_rx_bss_put(struct net_device *dev,
+			  struct ieee80211_sta_bss *bss)
 {
 	struct ieee80211_local *local = dev->ieee80211_ptr;
 	if (!atomic_dec_and_test(&bss->users))
maintainer
#1 lore raw
Quoted 4 lines · Ivo van Doorn

Most hardware can keep track of sequence numbers themselves, unfortunately *most* doesn't cover all devices. ;) This patch will keep track of the (per-bss) sequence number if the flag IEEE80211_HW_SOFTWARE_SEQUENCE has been set.

Can this be a library function instead? Our TX path is already cluttered enough...

Quoted 12 lines
net/d80211/ieee80211.c +12 -0
+static void ieee80211_include_sequence(struct net_device *dev,
+				       struct ieee80211_hdr *hdr)
+{
+	struct ieee80211_sta_bss *bss;
+	u8 *bssid = ieee80211_get_bssid(hdr, sizeof(*hdr));
+
+	bss = ieee80211_rx_bss_get(dev, bssid);
+	if (!bss)
+		return;
+
+       /*
+        * Set the sequence number for this frame.

net/d80211/ieee80211.c static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); · line 74

Quoted 10 lines
net/d80211/ieee80211.c +10 -0
+        */
+	hdr->seq_ctrl = cpu_to_le16(bss->sequence & IEEE80211_SCTL_SEQ);
+
+       /*
+        * Increase the sequence number.
+        */
+	bss->sequence = (bss->sequence + 0x10) & IEEE80211_SCTL_SEQ;
+
+	ieee80211_rx_bss_put(dev, bss);
+}

This could be exported getting an skb instead of the ieee80211_hdr.

Then the driver can just call it whenever it needs the sequence number for a frame. It'll need to be a bit smart about fragmentation but I think that's ok.

I may be radical, but I think that a lot of things hardware can do belong into library functions the driver can use instead of cluttering the stack with it.

johannes

#2 lore raw
Quoted 7 lines · Johannes Berg

Then the driver can just call it whenever it needs the sequence number for a frame. It'll need to be a bit smart about fragmentation but I think that's ok.

I may be radical, but I think that a lot of things hardware can do belong into library functions the driver can use instead of cluttering the stack with it.

I'm inclined to agree, FWIW...

Signature · 2 lines
John W. Linville
[email protected]
#3 lore raw

Hi,

Quoted 9 lines
Quoted 7 lines

Then the driver can just call it whenever it needs the sequence number for a frame. It'll need to be a bit smart about fragmentation but I think that's ok.

I may be radical, but I think that a lot of things hardware can do belong into library functions the driver can use instead of cluttering the stack with it.

I'm inclined to agree, FWIW...

Ok, I'll change it. New patch will arrive in a few days.

Ivo

#4 lore raw
In reply to Johannes Berg
Quoted 9 lines · Johannes Berg
Quoted 4 lines · Ivo van Doorn

Most hardware can keep track of sequence numbers themselves, unfortunately *most* doesn't cover all devices. ;) This patch will keep track of the (per-bss) sequence number if the flag IEEE80211_HW_SOFTWARE_SEQUENCE has been set.

Can this be a library function instead? Our TX path is already cluttered enough...

If we're going to switch to a library approach, let's do it all at once. I don't want some features requiring flags to toggle and others requiring a function to call.

-Michael Wu

#5 lore raw
Quoted 3 lines · Michael Wu

If we're going to switch to a library approach, let's do it all at once. I don't want some features requiring flags to toggle and others requiring a function to call.

Entirely library approach is not possible. So we're going to end up with mixed environment in any case.

Jiri

Signature · 2 lines
Jiri Benc
SUSE Labs
#6 lore raw
In reply to Michael Wu
Quoted 4 lines · Michael Wu

If we're going to switch to a library approach, let's do it all at once. I don't want some features requiring flags to toggle and others requiring a function to call.

To be specific, I don't like the library approach when we can simply set a flag and let the stack handle it. It may clutter the TX path, but it reduces complexity on the driver end. Also, this particular test can be moved from the TX path to device registration with some changes to the way the TX handlers are handled. I will need to check if there are other TX handlers that would benefit from this to make it worthwhile. For things like encryption, I think library functions or callbacks will really be needed to do things right, but for software sequence numbers, I'd rather stick with a simple flag to enable/disable it. It also allows us to report if a particular device supports software sequence numbers which the use of a library function would not specify so directly.

-Michael Wu

#7 lore raw
Quoted 2 lines · Michael Wu

To be specific, I don't like the library approach when we can simply set a flag and let the stack handle it.

In general, I would prefer not to use library approach for things like this sequence number support. In this case, there may not even be need for that flag if the operation itself is fast enough. In other words, I don't think it would cause problems for other drivers if the seq# were set regardless of whether it is neede or not. Just doing this without the flag may be the cleanest way and not likely to use much more CPU than verification of a flag before doing this..

Signature · 1 line
Jouni Malinen                                            PGP id EFC895FA
#8 lore raw
In reply to Johannes Berg
Quoted 2 lines · Johannes Berg

Can this be a library function instead? Our TX path is already cluttered enough...

The advantage of non-library approach in this case is that you don't need to search for a BSS the frame belongs to. Ivo's patch searches for it but I think it's possible to remember it from the past.

If this feature is implemented as a library function you need to search for a BSS in any case. That's way more overhead than one condition in the tx path.

Jiri

Signature · 2 lines
Jiri Benc
SUSE Labs
#9 lore raw
In reply to Ivo van Doorn

net/d80211/ieee80211_i.h struct ieee80211_sta_bss { · line 86

Quoted 12 lines · Ivo van Doorn
net/d80211/ieee80211_i.h +1 -0
index 5ab9eb5..1891e05 100644
@@ -80,6 +80,7 @@ struct ieee80211_sta_bss {
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	size_t ssid_len;
 	u16 capability; /* host byte order */
+	u16 sequence;
 	int hw_mode;
 	int channel;
 	int freq;

I am not so sure that storing this information in struct ieee80211_sta_bss is correct. As far as I can tell, that is strictly for storing information scan results and beacon information. Nothing outside of ieee80211_sta.c uses it. struct sta_info or struct ieee80211_if_ap (sta interfaces have a pointer to the struct ieee80211_if_ap on the master device) may be a better choice. I think struct sta_info is the right one though there is a problem - it isn't allocated until a successful association.

-Michael Wu

#10 lore raw
Quoted 7 lines · Michael Wu

I am not so sure that storing this information in struct ieee80211_sta_bss is correct. As far as I can tell, that is strictly for storing information scan results and beacon information. Nothing outside of ieee80211_sta.c uses it. struct sta_info or struct ieee80211_if_ap (sta interfaces have a pointer to the struct ieee80211_if_ap on the master device) may be a better choice. I think struct sta_info is the right one though there is a problem - it isn't allocated until a successful association.

Thinking about it more, sdata should be the correct place. It's more per-interface thing than per-BSS (although the difference is small in this particular case).

Thanks,

Jiri

Signature · 2 lines
Jiri Benc
SUSE Labs
#11 lore raw
Quoted 8 lines
Quoted 1 line

I am not so sure that storing this information in struct ieee80211_sta_bss

is

Quoted 1 line

correct. As far as I can tell, that is strictly for storing information

scan

Quoted 1 line

results and beacon information. Nothing outside of ieee80211_sta.c uses

it.

Quoted 1 line

struct sta_info or struct ieee80211_if_ap (sta interfaces have a pointer

to

Quoted 8 lines
Quoted 2 lines

the struct ieee80211_if_ap on the master device) may be a better choice. I think struct sta_info is the right one though there is a problem - it

isn't

Quoted 1 line

allocated until a successful association.

Thinking about it more, sdata should be the correct place. It's more per-interface thing than per-BSS (although the difference is small in this particular case).

That would also optimize the sequence handler since the BSS
does not have to be looked up anymore. I'll create the patch to do this asap.

Ivo

#12 lore raw
In reply to Jiri Benc
Quoted 3 lines · Jiri Benc

Thinking about it more, sdata should be the correct place. It's more per-interface thing than per-BSS (although the difference is small in this particular case).

...and thinking about it even more, that won't work with WDS.

Jiri

Signature · 2 lines
Jiri Benc
SUSE Labs
#13 lore raw
Quoted 6 lines · Jiri Benc
Quoted 3 lines · Jiri Benc

Thinking about it more, sdata should be the correct place. It's more per-interface thing than per-BSS (although the difference is small in this particular case).

...and thinking about it even more, that won't work with WDS.

You mean storing the sequence counter per-interface won't work, or per-bss?

Ivo

#14 lore raw
Quoted 10 lines · Ivo van Doorn
Quoted 6 lines · Jiri Benc
Quoted 3 lines · Jiri Benc

Thinking about it more, sdata should be the correct place. It's more per-interface thing than per-BSS (although the difference is small in this particular case).

...and thinking about it even more, that won't work with WDS.

You mean storing the sequence counter per-interface won't work, or per-bss?

Both.

When you have a WDS link and some other wireless interface at the same time, their source addresses are (in most cases) the same. You want to have the sequence control counter shared by them. Actually, it will probably work most of time even when they have different counters. The situation where it won't work is if you have two virtual interfaces, one in STA and second in WDS mode, both connected to the same AP. I can't figure out how this particular setup could be useful but it's generally not disallowed.

Anyway, using different counter for a WDS interface probably violates 802.11 (although it's not much specific in this case). I believe it will work in most cases, though.

Any ideas how to solve that?

Thanks,

Jiri

Signature · 2 lines
Jiri Benc
SUSE Labs
#15 lore raw
Quoted 23 lines · Jiri Benc
Quoted 10 lines · Ivo van Doorn
Quoted 6 lines · Jiri Benc
Quoted 3 lines · Jiri Benc

Thinking about it more, sdata should be the correct place. It's more per-interface thing than per-BSS (although the difference is small in this particular case).

...and thinking about it even more, that won't work with WDS.

You mean storing the sequence counter per-interface won't work, or per-bss?

Both.

When you have a WDS link and some other wireless interface at the same time, their source addresses are (in most cases) the same. You want to have the sequence control counter shared by them. Actually, it will probably work most of time even when they have different counters. The situation where it won't work is if you have two virtual interfaces, one in STA and second in WDS mode, both connected to the same AP. I can't figure out how this particular setup could be useful but it's generally not disallowed.

Quoted 5 lines

Anyway, using different counter for a WDS interface probably violates 802.11 (although it's not much specific in this case). I believe it will work in most cases, though.

Any ideas how to solve that?

Are there more situations where it might be important to know
if the WDS interface has to keep in mind that there is a virtual STA interface on the same network? Because it might be worthwhile to make a check for that in the creation of the WDS interface (and in the STA interface).

Ivo

maintainer
#16 lore raw
In reply to Jiri Benc
Quoted 11 lines · Jiri Benc

Both.

When you have a WDS link and some other wireless interface at the same time, their source addresses are (in most cases) the same. You want to have the sequence control counter shared by them. Actually, it will probably work most of time even when they have different counters. The situation where it won't work is if you have two virtual interfaces, one in STA and second in WDS mode, both connected to the same AP. I can't figure out how this particular setup could be useful but it's generally not disallowed.

Quoted 5 lines

Anyway, using different counter for a WDS interface probably violates 802.11 (although it's not much specific in this case). I believe it will work in most cases, though.

Any ideas how to solve that?

Make the counter per-mac address?

johannes

#17 lore raw
Quoted 13 lines · Johannes Berg
Quoted 11 lines · Jiri Benc

Both.

When you have a WDS link and some other wireless interface at the same time, their source addresses are (in most cases) the same. You want to have the sequence control counter shared by them. Actually, it will probably work most of time even when they have different counters. The situation where it won't work is if you have two virtual interfaces, one in STA and second in WDS mode, both connected to the same AP. I can't figure out how this particular setup could be useful but it's generally not disallowed.

Quoted 7 lines
Quoted 5 lines

Anyway, using different counter for a WDS interface probably violates 802.11 (although it's not much specific in this case). I believe it will work in most cases, though.

Any ideas how to solve that?

Make the counter per-mac address?

Wouldn't that be the same as per-interface?

Ivo

maintainer
#18 lore raw
Quoted 18 lines · Ivo van Doorn
Quoted 17 lines · Johannes Berg
Quoted 15 lines · Jiri Benc

Both.

When you have a WDS link and some other wireless interface at the same time, their source addresses are (in most cases) the same. You want to have the sequence control counter shared by them. Actually, it will probably work most of time even when they have different counters. The situation where it won't work is if you have two virtual interfaces, one in STA and second in WDS mode, both connected to the same AP. I can't figure out how this particular setup could be useful but it's generally not disallowed.

Anyway, using different counter for a WDS interface probably violates 802.11 (although it's not much specific in this case). I believe it will work in most cases, though.

Quoted 5 lines
Quoted 3 lines
Quoted 1 line

Any ideas how to solve that?

Make the counter per-mac address?

Wouldn't that be the same as per-interface?

Don't WDS interfaces have the same MAC as the corresponding AP interface?

johannes

#19 lore raw
Quoted 8 lines · Johannes Berg
Quoted 4 lines · Ivo van Doorn
Quoted 1 line · Johannes Berg

Make the counter per-mac address?

Wouldn't that be the same as per-interface?

Don't WDS interfaces have the same MAC as the corresponding AP interface?

They do.

Per-MAC address counters would work but it's another overhead we need to add (allocate a new reference-counted structure, put a pointer to it into sdata, correctly deal with it when MAC address changes).

I think we can live with the counter in sdata. It's not perfect but it should work for all useful cases. The only situation where it won't work I have been able to imagine is the case I described (STA and WDS with the same address) and this particular setup is currently being denied by d80211 (and it's not allowed by 802.11, btw).

If we consider this as a problem later, we can always change to per-MAC address counters or something as it's completely internal to the stack and no driver changes would be required.

Jiri

Signature · 2 lines
Jiri Benc
SUSE Labs
maintainer
#20 lore raw
Quoted 3 lines · Jiri Benc

Per-MAC address counters would work but it's another overhead we need to add (allocate a new reference-counted structure, put a pointer to it into sdata, correctly deal with it when MAC address changes).

Yup, I agree. Put it into drivers :P

Quoted 9 lines

I think we can live with the counter in sdata. It's not perfect but it should work for all useful cases. The only situation where it won't work I have been able to imagine is the case I described (STA and WDS with the same address) and this particular setup is currently being denied by d80211 (and it's not allowed by 802.11, btw).

If we consider this as a problem later, we can always change to per-MAC address counters or something as it's completely internal to the stack and no driver changes would be required.

Ok. I'm fine with putting it into the stack. I'll take Michael by the word though that he'll do dynamically registered tx handlers later ;)

johannes

#21 lore raw
Quoted 6 lines
Quoted 3 lines

If we consider this as a problem later, we can always change to per-MAC address counters or something as it's completely internal to the stack and no driver changes would be required.

Ok. I'm fine with putting it into the stack. I'll take Michael by the word though that he'll do dynamically registered tx handlers later ;)

So just to be clear, this patch does not need any tweaking anymore right? Latest patch series for rt2x00 accidently had software sequence handling removed out of rt2400pci and rt2500pci so it is actually broken and at the moment. So I need to either restore it back into the rt2x00 drivers or the mac80211 stack needs to get the support so rt2x00 can use it. :)

Ivo

#22 lore raw
Quoted 1 line · Ivo van Doorn

So just to be clear, this patch does not need any tweaking anymore right?

Just stick the counter in sdata if you haven't done so already. Should be fine once that's done.

Thanks,
-Michael Wu

#23 lore raw
Quoted 4 lines · Michael Wu
Quoted 1 line · Ivo van Doorn

So just to be clear, this patch does not need any tweaking anymore right?

Just stick the counter in sdata if you haven't done so already. Should be fine once that's done.

Ah ok. I had it in ieee80211_sta_bss.
I'll create a new patch with the sequence number in the right location.

Thanks.

Ivo

#24 lore raw

PATCH v3 1/1 d80211: Add software sequence support

Most hardware can keep track of sequence numbers themselves, unfortunately *most* doesn't cover all devices. ;) This patch will keep track of the (per-bss) sequence number if the flag IEEE80211_HW_SOFTWARE_SEQUENCE has been set.

This 3rd version of the patch has the sequence number stored in the ieee80211_sub_if_data structure.

---

include/net/mac80211.h +3 -0
index 82ea43f..e32e28a 100644
@@ -515,6 +515,9 @@ struct ieee80211_hw {
 	 * normal operation. */
 #define IEEE80211_HW_MONITOR_DURING_OPER (1<<9)
 
+	/* Does the HOST need to insert the frame sequence counter */
+#define IEEE80211_HW_SOFTWARE_SEQUENCE (1<<10)
+
 	/* please fill this gap when adding new flags */
 
 	/* calculate Michael MIC for an MSDU when doing hwcrypto */
net/mac80211/ieee80211.c +33 -1
index 577dbe3..79c2a60 100644
@@ -54,6 +54,20 @@ static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len);
 static int ieee80211_mgmt_start_xmit(struct sk_buff *skb,
 				     struct net_device *dev);
 
+static void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
+				       struct ieee80211_hdr *hdr)
+{
+	/*
+	 * Set the sequence number for this frame.
+	 */
+	hdr->seq_ctrl = cpu_to_le16(sdata->sequence & IEEE80211_SCTL_SEQ);
+
+	/*
+	 * Increase the sequence number.
+	 */
+	sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ;
+}
+
 struct ieee80211_key_conf *
 ieee80211_key_data2conf(struct ieee80211_local *local,
 			const struct ieee80211_key *data)
@@ -445,6 +459,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 	size_t hdrlen, per_fragm, num_fragm, payload_len, left;
 	struct sk_buff **frags, *first, *frag;
 	int i;
+	u16 seq;
 	u8 *pos;
 	int frag_threshold = tx->local->fragmentation_threshold;
 
@@ -463,6 +478,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 		goto fail;
 
 	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
+	seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ;
 	pos = first->data + hdrlen + per_fragm;
 	left = payload_len - per_fragm;
 	for (i = 0; i < num_fragm - 1; i++) {
@@ -490,7 +506,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 		memcpy(fhdr, first->data, hdrlen);
 		if (i == num_fragm - 2)
 			fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
-		fhdr->seq_ctrl = cpu_to_le16(i + 1);
+		fhdr->seq_ctrl = cpu_to_le16(seq + ((i + 1) & IEEE80211_SCTL_FRAG));
 		copylen = left > per_fragm ? per_fragm : left;
 		memcpy(skb_put(frag, copylen), pos, copylen);
 
@@ -900,6 +916,17 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
 	return TXRX_CONTINUE;
 }
 
+static ieee80211_txrx_result
+ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+
+	if ((tx->local->hw.flags & IEEE80211_HW_SOFTWARE_SEQUENCE) &&
+	    ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
+		ieee80211_include_sequence(tx->sdata, hdr);
+
+	return TXRX_CONTINUE;
+}
 
 /* This function is called whenever the AP is about to exceed the maximum limit
  * of buffered frames for power saving STAs. This situation should not really
@@ -1770,6 +1797,10 @@ struct sk_buff * ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
 	skb_reserve(skb, local->hw.extra_tx_headroom);
 	memcpy(skb_put(skb, bh_len), b_head, bh_len);
 
+	if (hw->flags & IEEE80211_HW_SOFTWARE_SEQUENCE)
+		ieee80211_include_sequence(sdata,
+			(struct ieee80211_hdr *)skb->data);
+
 	ieee80211_beacon_add_tim(local, ap, skb);
 
 	if (b_tail) {
@@ -4381,6 +4412,7 @@ static ieee80211_rx_handler ieee80211_rx_handlers[] =
 static ieee80211_tx_handler ieee80211_tx_handlers[] =
 {
 	ieee80211_tx_h_check_assoc,
+	ieee80211_tx_h_sequence,
 	ieee80211_tx_h_ps_buf,
 	ieee80211_tx_h_select_key,
 	ieee80211_tx_h_michael_mic_add,
net/mac80211/ieee80211_i.h +2 -0
index 9df8ef0..4b7c427 100644
@@ -317,6 +317,8 @@ struct ieee80211_sub_if_data {
 	int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized
 			 * port */
 
+	u16 sequence;
+
 	/* Fragment table for host-based reassembly */
 	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
 	unsigned int fragment_next;
#25 lore raw
Quoted 4 lines · Ivo van Doorn

Most hardware can keep track of sequence numbers themselves, unfortunately *most* doesn't cover all devices. ;) This patch will keep track of the (per-bss) sequence number if the flag IEEE80211_HW_SOFTWARE_SEQUENCE has been set.

The question has been asked (by Jouni), but I didn't see a good answer (maybe I missed it).
Why is this a flag at all? The sequence counter is such a trivial thing that having an extra conditional is just _more_ overhead. Why not simply calculate the seq all the time and let hardware override it, if it has the capability to do so? Calculation of the seq is cheap. No need to bloat code.

Quoted 127 lines

This 3rd version of the patch has the sequence number stored in the ieee80211_sub_if_data structure.

---

include/net/mac80211.h +3 -0
index 82ea43f..e32e28a 100644
@@ -515,6 +515,9 @@ struct ieee80211_hw {
 	 * normal operation. */
 #define IEEE80211_HW_MONITOR_DURING_OPER (1<<9)
 
+	/* Does the HOST need to insert the frame sequence counter */
+#define IEEE80211_HW_SOFTWARE_SEQUENCE (1<<10)
+
 	/* please fill this gap when adding new flags */
 
 	/* calculate Michael MIC for an MSDU when doing hwcrypto */
net/mac80211/ieee80211.c +33 -1
index 577dbe3..79c2a60 100644
@@ -54,6 +54,20 @@ static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len);
 static int ieee80211_mgmt_start_xmit(struct sk_buff *skb,
 				     struct net_device *dev);
 
+static void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
+				       struct ieee80211_hdr *hdr)
+{
+	/*
+	 * Set the sequence number for this frame.
+	 */
+	hdr->seq_ctrl = cpu_to_le16(sdata->sequence & IEEE80211_SCTL_SEQ);
+
+	/*
+	 * Increase the sequence number.
+	 */
+	sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ;
+}
+
 struct ieee80211_key_conf *
 ieee80211_key_data2conf(struct ieee80211_local *local,
 			const struct ieee80211_key *data)
@@ -445,6 +459,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 	size_t hdrlen, per_fragm, num_fragm, payload_len, left;
 	struct sk_buff **frags, *first, *frag;
 	int i;
+	u16 seq;
 	u8 *pos;
 	int frag_threshold = tx->local->fragmentation_threshold;
 
@@ -463,6 +478,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 		goto fail;
 
 	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
+	seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ;
 	pos = first->data + hdrlen + per_fragm;
 	left = payload_len - per_fragm;
 	for (i = 0; i < num_fragm - 1; i++) {
@@ -490,7 +506,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 		memcpy(fhdr, first->data, hdrlen);
 		if (i == num_fragm - 2)
 			fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
-		fhdr->seq_ctrl = cpu_to_le16(i + 1);
+		fhdr->seq_ctrl = cpu_to_le16(seq + ((i + 1) & IEEE80211_SCTL_FRAG));
 		copylen = left > per_fragm ? per_fragm : left;
 		memcpy(skb_put(frag, copylen), pos, copylen);
 
@@ -900,6 +916,17 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
 	return TXRX_CONTINUE;
 }
 
+static ieee80211_txrx_result
+ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+
+	if ((tx->local->hw.flags & IEEE80211_HW_SOFTWARE_SEQUENCE) &&
+	    ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
+		ieee80211_include_sequence(tx->sdata, hdr);
+
+	return TXRX_CONTINUE;
+}
 
 /* This function is called whenever the AP is about to exceed the maximum limit
  * of buffered frames for power saving STAs. This situation should not really
@@ -1770,6 +1797,10 @@ struct sk_buff * ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
 	skb_reserve(skb, local->hw.extra_tx_headroom);
 	memcpy(skb_put(skb, bh_len), b_head, bh_len);
 
+	if (hw->flags & IEEE80211_HW_SOFTWARE_SEQUENCE)
+		ieee80211_include_sequence(sdata,
+			(struct ieee80211_hdr *)skb->data);
+
 	ieee80211_beacon_add_tim(local, ap, skb);
 
 	if (b_tail) {
@@ -4381,6 +4412,7 @@ static ieee80211_rx_handler ieee80211_rx_handlers[] =
 static ieee80211_tx_handler ieee80211_tx_handlers[] =
 {
 	ieee80211_tx_h_check_assoc,
+	ieee80211_tx_h_sequence,
 	ieee80211_tx_h_ps_buf,
 	ieee80211_tx_h_select_key,
 	ieee80211_tx_h_michael_mic_add,
net/mac80211/ieee80211_i.h +2 -1
index 9df8ef0..4b7c427 100644
@@ -317,6 +317,8 @@ struct ieee80211_sub_if_data {
 	int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized
 			 * port */
 
+	u16 sequence;
+
 	/* Fragment table for host-based reassembly */
 	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
 	unsigned int fragment_next;
-

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

Signature · 1 line
Greetings Michael.
#26 lore raw
Quoted 6 lines · Michael Buesch
Quoted 4 lines · Ivo van Doorn

Most hardware can keep track of sequence numbers themselves, unfortunately *most* doesn't cover all devices. ;) This patch will keep track of the (per-bss) sequence number if the flag IEEE80211_HW_SOFTWARE_SEQUENCE has been set.

Quoted 7 lines

The question has been asked (by Jouni), but I didn't see a good answer (maybe I missed it).
Why is this a flag at all? The sequence counter is such a trivial thing that having an extra conditional is just _more_ overhead. Why not simply calculate the seq all the time and let hardware override it, if it has the capability to do so? Calculation of the seq is cheap. No need to bloat code.

It would also safe me a patch for rt2400pci and rt2500pci as well. ;)

Well if nobody objects against setting the sequence number always, then below patch would be sufficient. :)

---

net/mac80211/ieee80211.c +30 -1
index 577dbe3..05a0929 100644
@@ -54,6 +54,20 @@ static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len);
 static int ieee80211_mgmt_start_xmit(struct sk_buff *skb,
 				     struct net_device *dev);
 
+static void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
+				       struct ieee80211_hdr *hdr)
+{
+	/*
+	 * Set the sequence number for this frame.
+	 */
+	hdr->seq_ctrl = cpu_to_le16(sdata->sequence & IEEE80211_SCTL_SEQ);
+
+	/*
+	 * Increase the sequence number.
+	 */
+	sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ;
+}
+
 struct ieee80211_key_conf *
 ieee80211_key_data2conf(struct ieee80211_local *local,
 			const struct ieee80211_key *data)
@@ -445,6 +459,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 	size_t hdrlen, per_fragm, num_fragm, payload_len, left;
 	struct sk_buff **frags, *first, *frag;
 	int i;
+	u16 seq;
 	u8 *pos;
 	int frag_threshold = tx->local->fragmentation_threshold;
 
@@ -463,6 +478,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 		goto fail;
 
 	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
+	seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ;
 	pos = first->data + hdrlen + per_fragm;
 	left = payload_len - per_fragm;
 	for (i = 0; i < num_fragm - 1; i++) {
@@ -490,7 +506,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 		memcpy(fhdr, first->data, hdrlen);
 		if (i == num_fragm - 2)
 			fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
-		fhdr->seq_ctrl = cpu_to_le16(i + 1);
+		fhdr->seq_ctrl = cpu_to_le16(seq + ((i + 1) & IEEE80211_SCTL_FRAG));
 		copylen = left > per_fragm ? per_fragm : left;
 		memcpy(skb_put(frag, copylen), pos, copylen);
 
@@ -900,6 +916,16 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
 	return TXRX_CONTINUE;
 }
 
+static ieee80211_txrx_result
+ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+
+	if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
+		ieee80211_include_sequence(tx->sdata, hdr);
+
+	return TXRX_CONTINUE;
+}
 
 /* This function is called whenever the AP is about to exceed the maximum limit
  * of buffered frames for power saving STAs. This situation should not really
@@ -1770,6 +1796,8 @@ struct sk_buff * ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
 	skb_reserve(skb, local->hw.extra_tx_headroom);
 	memcpy(skb_put(skb, bh_len), b_head, bh_len);
 
+	ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
+
 	ieee80211_beacon_add_tim(local, ap, skb);
 
 	if (b_tail) {
@@ -4381,6 +4409,7 @@ static ieee80211_rx_handler ieee80211_rx_handlers[] =
 static ieee80211_tx_handler ieee80211_tx_handlers[] =
 {
 	ieee80211_tx_h_check_assoc,
+	ieee80211_tx_h_sequence,
 	ieee80211_tx_h_ps_buf,
 	ieee80211_tx_h_select_key,
 	ieee80211_tx_h_michael_mic_add,
net/mac80211/ieee80211_i.h +2 -0
index 9df8ef0..4b7c427 100644
@@ -317,6 +317,8 @@ struct ieee80211_sub_if_data {
 	int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized
 			 * port */
 
+	u16 sequence;
+
 	/* Fragment table for host-based reassembly */
 	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
 	unsigned int fragment_next;
#27 lore raw

net/mac80211/ieee80211.c static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); · line 58

Quoted 2 lines · Ivo van Doorn
net/mac80211/ieee80211.c +2 -0
+static void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
+				       struct ieee80211_hdr *hdr)

I'd prefer specifying this as inline function.

net/mac80211/ieee80211.c static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); · line 63

Quoted 5 lines
net/mac80211/ieee80211.c +5 -0
+{
+	/*
+	 * Set the sequence number for this frame.
+	 */
+	hdr->seq_ctrl = cpu_to_le16(sdata->sequence & IEEE80211_SCTL_SEQ);

No need to do "& IEEE80211_SCTL_SEQ" here.

net/mac80211/ieee80211.c static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); · line 67

Quoted 4 lines
net/mac80211/ieee80211.c +4 -0
+
+	/*
+	 * Increase the sequence number.
+	 */

Please reduce this and previous comment to one line each.

Quoted 23 lines
net/mac80211/ieee80211.c +5 -0
+	sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ;
+}
+
 struct ieee80211_key_conf *
 ieee80211_key_data2conf(struct ieee80211_local *local,
 			const struct ieee80211_key *data)
@@ -445,6 +459,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 	size_t hdrlen, per_fragm, num_fragm, payload_len, left;
 	struct sk_buff **frags, *first, *frag;
 	int i;
+	u16 seq;
 	u8 *pos;
 	int frag_threshold = tx->local->fragmentation_threshold;
 
@@ -463,6 +478,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 		goto fail;
 
 	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
+	seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ;
 	pos = first->data + hdrlen + per_fragm;
 	left = payload_len - per_fragm;
 	for (i = 0; i < num_fragm - 1; i++) {

net/mac80211/ieee80211.c ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) · line 509

Quoted 5 lines
net/mac80211/ieee80211.c +1 -1
@@ -490,7 +506,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 		memcpy(fhdr, first->data, hdrlen);
 		if (i == num_fragm - 2)
 			fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
-		fhdr->seq_ctrl = cpu_to_le16(i + 1);
+		fhdr->seq_ctrl = cpu_to_le16(seq + ((i + 1) & IEEE80211_SCTL_FRAG));

I'd prefer | instead of + here.

Thanks,

Jiri

Signature · 2 lines
Jiri Benc
SUSE Labs