mac80211 re-transmission repair
Johannes Berg
maintainercover mac80211 re-transmission repair
I sent this series a long time ago as RFC and have been running it ever since ... never totally confirmed it works correctly but at this point it's probably good enough for wider deployment.
Basically it revamps some tx handling so we can do encryption and other stuff separate from each other for re-transmissions with frames that a device has rejected because the destination station was asleep.
johannes
Johannes Berg
maintainerPATCH 1/5 mac80211: move and rename misc tx handler
This TX handler is used only for assigning the
station pointer in the control information, so
give it a better name. Also move it before rate
control.
--- net/mac80211/tx.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
net/mac80211/tx.c +12 -12
@@ -560,6 +560,17 @@ ieee80211_tx_h_select_key(struct ieee802 } static ieee80211_tx_result debug_noinline +ieee80211_tx_h_sta (struct ieee80211_tx_data *tx) +{ +struct ieee80211_tx_info *info =IEEE80211_SKB_CB (tx->skb); + +if (tx->sta) + info->control.sta = &tx->sta->sta; + +return TX_CONTINUE ; +} + +static ieee80211_tx_result debug_noinlineieee80211_tx_h_rate_ctrl (struct ieee80211_tx_data *tx) {struct ieee80211_tx_info *info =IEEE80211_SKB_CB (tx->skb);
@@ -734,17 +745,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 } static ieee80211_tx_result debug_noinline -ieee80211_tx_h_misc (struct ieee80211_tx_data *tx) -{ -struct ieee80211_tx_info *info =IEEE80211_SKB_CB (tx->skb); - -if (tx->sta) - info->control.sta = &tx->sta->sta; - -return TX_CONTINUE ; -} - -static ieee80211_tx_result debug_noinlineieee80211_tx_h_sequence (struct ieee80211_tx_data *tx) {struct ieee80211_tx_info *info =IEEE80211_SKB_CB (tx->skb);
@@ -1292,10 +1292,10 @@ static int invoke_tx_handlers(struct ieeCALL_TXH (ieee80211_tx_h_check_assoc);CALL_TXH (ieee80211_tx_h_ps_buf);CALL_TXH (ieee80211_tx_h_select_key); +CALL_TXH (ieee80211_tx_h_sta);CALL_TXH (ieee80211_tx_h_michael_mic_add);if (!(tx->local->hw.flags &IEEE80211_HW_HAS_RATE_CONTROL ))CALL_TXH (ieee80211_tx_h_rate_ctrl); -CALL_TXH (ieee80211_tx_h_misc);CALL_TXH (ieee80211_tx_h_sequence);CALL_TXH (ieee80211_tx_h_fragment);/* handlers after fragment must be aware of tx info fragmentation! */
Johannes Berg
maintainerPATCH 2/5 mac80211: clear TX control on filtered frames
In reply to Johannes BergWhen an skb survived a round-trip through the driver and needs to be re-used, its control information is definitely not valid any more, the driver will have overwritten it.
--- net/mac80211/status.c | 8 ++++++++ 1 file changed, 8 insertions(+)
net/mac80211/status.c +8 -0
@@ -69,6 +69,14 @@ static void ieee80211_handle_filtered_fr*/ goto drop; +/* +* This skb 'survived' a round-trip through the driver, and +* hopefully the driver didn't mangle it too badly. However, +* we can definitely not rely on the the control information +* being correct. Clear it so we don't get junk there. +*/ +memset (&info->control,0 ,sizeof (info->control)); + sta->tx_filtered_count++;/*
Johannes Berg
maintainerPATCH 3/5 mac80211: remove useless setting of IEEE80211_TX_INTFL_DONT_ENCRYPT
In reply to Johannes BergThere's no value in setting a flag that will never be checked after this point, this seems to be legacy code -- I think previously the flag was used to check whether to encrypt the frame or not. Now, however, the flag need not be set, and setting it actually interferes if the frame will be processed again later.
--- net/mac80211/tx.c | 3 --- 1 file changed, 3 deletions(-)
net/mac80211/tx.c +0 -3
@@ -553,9 +553,6 @@ ieee80211_tx_h_select_key(struct ieee802 } } -if (!tx->key || !(tx->key->flags &KEY_FLAG_UPLOADED_TO_HARDWARE )) - info->flags |=IEEE80211_TX_INTFL_DONT_ENCRYPT ; -return TX_CONTINUE ; }
Johannes Berg
maintainerPATCH 4/5 mac80211: move control.hw_key assignment
In reply to Johannes BergWhen mac80211 asks a driver to encrypt a frame, it must assign the control.hw_key pointer for it to know which key to use etc. Currently, mac80211 does this whenever it would software-encrypt a frame.
Change the logic of this code to assign the hw_key pointer when selecting the key, and later check it when deciding whether to encrypt the frame or let it be encrypted by the hardware. This allows us to later simply skip the encryption function since it no longer modifies the TX control.
--- net/mac80211/tkip.c | 11 +++++----- net/mac80211/tx.c | 9 ++++++++ net/mac80211/wep.c | 18 ++++++++-------- net/mac80211/wpa.c | 57 ++++++++++++++++++++-------------------------------- 4 files changed, 46 insertions(+), 49 deletions(-)
net/mac80211/tkip.c +6 -5
@@ -195,11 +195,13 @@ void ieee80211_get_tkip_key(struct ieee8 }EXPORT_SYMBOL (ieee80211_get_tkip_key); -/* Encrypt packet payload with TKIP using @key. @pos is a pointer to the +/* +* Encrypt packet payload with TKIP using @key. @pos is a pointer to the * beginning of the buffer containing payload. This payload must include -* headroom of eight octets for IV and Ext. IV and taildroom of four octets -* for ICV. @payload_len is the length of payload (_not_ including extra -* headroom and tailroom). @ta is the transmitter addresses. */ +* the IV/Ext.IV and space for (taildroom) four octets for ICV. +* @payload_len is the length of payload (_not_ including IV/ICV length). +* @ta is the transmitter addresses. +*/ void ieee80211_tkip_encrypt_data (struct crypto_blkcipher *tfm,struct ieee80211_key *key,u8 *pos,size_t payload_len,u8 *ta)
@@ -214,7 +216,6 @@ void ieee80211_tkip_encrypt_data(structtkip_mixing_phase2 (tk, ctx, ctx->iv16, rc4key); - pos =ieee80211_tkip_add_iv (pos, key, key->u.tkip.tx.iv16);ieee80211_wep_encrypt_data (tfm, rc4key,16 , pos, payload_len); }
net/mac80211/wpa.c +22 -35
122 lines not on this page · raw message
net/mac80211/wep.c +9 -9
@@ -305,20 +305,20 @@ static int wep_encrypt_skb(struct ieee80 {struct ieee80211_tx_info *info =IEEE80211_SKB_CB (skb); -if (!(tx->key->flags &KEY_FLAG_UPLOADED_TO_HARDWARE )) { +if (!info->control.hw_key) {if (ieee80211_wep_encrypt (tx->local, skb, tx->key->conf.key, tx->key->conf.keylen, tx->key->conf.keyidx))return -1 ; - }else { - info->control.hw_key = &tx->key->conf; -if (tx->key->conf.flags &IEEE80211_KEY_FLAG_GENERATE_IV ) { -if (!ieee80211_wep_add_iv (tx->local, skb, - tx->key->conf.keylen, - tx->key->conf.keyidx)) -return -1 ; - } } + +if (info->control.hw_key->flags &IEEE80211_KEY_FLAG_GENERATE_IV ) { +if (!ieee80211_wep_add_iv (tx->local, skb, + tx->key->conf.keylen, + tx->key->conf.keyidx)) +return -1 ; + } +return 0 ; }
net/mac80211/tx.c +9 -0
@@ -529,6 +529,8 @@ ieee80211_tx_h_select_key(struct ieee802 tx->key =NULL ;if (tx->key) { +bool skip_hw = false; + tx->key->tx_rx_count++;/* TODO: add threshold stuff again */
@@ -545,12 +547,19 @@ ieee80211_tx_h_select_key(struct ieee802 !ieee80211_use_mfp (hdr->frame_control, tx->sta, tx->skb)) tx->key = NULL; + skip_hw = (tx->key->conf.flags & +IEEE80211_KEY_FLAG_SW_MGMT ) && +ieee80211_is_mgmt (hdr->frame_control);break ;case ALG_AES_CMAC :if (!ieee80211_is_mgmt (hdr->frame_control)) tx->key =NULL ;break ; } + +if (!skip_hw && + tx->key->conf.flags &KEY_FLAG_UPLOADED_TO_HARDWARE ) + info->control.hw_key = &tx->key->conf; }return TX_CONTINUE ;
Re: [PATCH 4/5] mac80211: move control.hw_key assignment
Quoted 5 lines · On Sunday 17 January 2010 01:47:58 Johannes Berg wrote:
When mac80211 asks a driver to encrypt a frame, it must assign the control.hw_key pointer for it to know which key to use etc. Currently, mac80211 does this whenever it would software-encrypt a frame.
Quoted 8 lines
Change the logic of this code to assign the
hw_keypointer when selecting the key, and later check it when deciding whether to encrypt the frame or let it be encrypted by the hardware. This allows us to later simply skip the encryption function since it no longer modifies the TX control.Signed-off-by Johannes Berg <[email protected]>
Hi Johannes,
this patch breaks my wireless connection. I'm able to authenticate and associate to my AP but I can't use the connection, a simple ping towards my AP doesn't work. I bisected the problem and your patch is the bad commit.
I have the latest wireless-testing.git (v2.6.33-rc5-47285-g96ada3c). After having removed all the commits related to this patch, i.e.
- commit f12553ebe045a8a40ab33fa500fb57d10706e226
- commit e4fca007b06165900d0e44e8d5e251376819bf5d
- commit 813d76694043d00b59475baa1fbfaf54a2eb7fad
the connection is working again.
Fabio
Johannes Berg
maintainerRe: [PATCH 4/5] mac80211: move control.hw_key assignment
Hi,
Quoted 4 lines · Fabio Rossi
this patch breaks my wireless connection. I'm able to authenticate and associate to my AP but I can't use the connection, a simple ping towards my AP doesn't work. I bisected the problem and your patch is the bad commit.
Quoted 8 lines
I have the latest wireless-testing.git (v2.6.33-rc5-47285-g96ada3c). After having removed all the commits related to this patch, i.e.
- commit
f12553ebe045a8a40ab33fa500fb57d10706e226
- commite4fca007b06165900d0e44e8d5e251376819bf5d
- commit813d76694043d00b59475baa1fbfaf54a2eb7fadthe connection is working again.
Hmm. Are you using hw crypto?
johannes
Re: [PATCH 4/5] mac80211: move control.hw_key assignment
Quoted 11 lines · On Sunday 24 January 2010 12:29:51 Johannes Berg wrote:
Hi,
Quoted 8 lines · Fabio Rossi
this patch breaks my wireless connection. I'm able to authenticate and associate to my AP but I can't use the connection, a simple ping towards my AP doesn't work. I bisected the problem and your patch is the bad commit.
I have the latest wireless-testing.git (v2.6.33-rc5-47285-g96ada3c). After having removed all the commits related to this patch, i.e.
Quoted 7 lines
Quoted 5 lines
- commit
f12553ebe045a8a40ab33fa500fb57d10706e226
- commite4fca007b06165900d0e44e8d5e251376819bf5d
- commit813d76694043d00b59475baa1fbfaf54a2eb7fadthe connection is working again.
Hmm. Are you using hw crypto?
Yes, from what I have understood it should be the default using ath5k. Anyway I added your last patch
[PATCH] mac80211: fix sw crypto
fixing my problem.
Thanks,
Fabio
Re: [PATCH 4/5] mac80211: move control.hw_key assignment
In reply to Fabio RossiQuoted 21 lines · Fabio Rossi
Quoted 5 lines · On Sunday 17 January 2010 01:47:58 Johannes Berg wrote:
When mac80211 asks a driver to encrypt a frame, it must assign the control.hw_key pointer for it to know which key to use etc. Currently, mac80211 does this whenever it would software-encrypt a frame.
Quoted 8 lines
Change the logic of this code to assign the
hw_keypointer when selecting the key, and later check it when deciding whether to encrypt the frame or let it be encrypted by the hardware. This allows us to later simply skip the encryption function since it no longer modifies the TX control.Signed-off-by Johannes Berg <[email protected]>Hi Johannes,
this patch breaks my wireless connection. I'm able to authenticate and associate to my AP but I can't use the connection, a simple ping towards my AP doesn't work. I bisected the problem and your patch is the bad commit.
Quoted 8 lines
I have the latest wireless-testing.git (v2.6.33-rc5-47285-g96ada3c). After having removed all the commits related to this patch, i.e.
- commit
f12553ebe045a8a40ab33fa500fb57d10706e226
- commite4fca007b06165900d0e44e8d5e251376819bf5d
- commit813d76694043d00b59475baa1fbfaf54a2eb7fadthe connection is working again.
Exactly same problem, here with iwl3945.
I am using software encryption (CCMP), and I noticed that it is the default in iwl3945. Also hardware encryption doesn't work (unrelated issue)
Best regards,
Maxim Levitsky
Johannes Berg
maintainerPATCH 5/5 mac80211: re-enable re-transmission of filtered frames
In reply to Johannes BergIn an earlier commit,
mac80211: disable software retry for now
Pavel Roskin reported a problem that seems to be due to software retry of already transmitted frames. It turns out that we've never done that correctly, but due to some recent changes it now crashes in the TX code. I've added a comment in the patch that explains the problem better and also points to possible solutions -- which I can't implement right now.
I disabled software retry of failed/filtered frames because it was broken. With the work of the previous patches, it now becomes fairly easy to re-enable it by adding a flag indicating that the frame shouldn't be modified, but still running it through the transmit handlers to populate the control information.
--- include/net/mac80211.h | 4 ++++ net/mac80211/status.c | 32 +++++--------------------------- net/mac80211/tx.c | 7 ++++++- 3 files changed, 15 insertions(+), 28 deletions(-)
net/mac80211/status.c +5 -27
@@ -45,37 +45,16 @@ static void ieee80211_handle_filtered_frstruct ieee80211_tx_info *info =IEEE80211_SKB_CB (skb);/* -* XXX: This is temporary! -* -* The problem here is that when we get here, the driver will -* quite likely have pretty much overwritten info->control by -* using info->driver_data or info->rate_driver_data. Thus, -* when passing out the frame to the driver again, we would be -* passing completely bogus data since the driver would then -* expect a properly filled info->control. In mac80211 itself -* the same problem occurs, since we need info->control.vif -* internally. -* -* To fix this, we should send the frame through TX processing -* again. However, it's not that simple, since the frame will -* have been software-encrypted (if applicable) already, and -* encrypting it again doesn't do much good. So to properly do -* that, we not only have to skip the actual 'raw' encryption -* (key selection etc. still has to be done!) but also the -* sequence number assignment since that impacts the crypto -* encapsulation, of course. -* -* Hence, for now, fix the bug by just dropping the frame. -*/ - goto drop; - -/* * This skb 'survived' a round-trip through the driver, and * hopefully the driver didn't mangle it too badly. However, * we can definitely not rely on the the control information -* being correct. Clear it so we don't get junk there. +* being correct. Clear it so we don't get junk there, and +* indicate that it needs new processing, but must not be +* modified/encrypted again. */ memset (&info->control,0 ,sizeof (info->control)); + info->flags |=IEEE80211_TX_INTFL_NEED_TXPROCESSING | +IEEE80211_TX_INTFL_RETRANSMISSION ; sta->tx_filtered_count++;
@@ -130,7 +109,6 @@ static void ieee80211_handle_filtered_frreturn ; } - drop:#ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit ()) printk(KERN_DEBUG "%s: dropped TX filtered frame, "
include/net/mac80211.h +4 -0
@@ -271,6 +271,9 @@ struct ieee80211_bss_conf {* transmit function after the current frame, this can be used * by drivers to kick the DMA queue only if unset or when the * queue gets full. +* @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted +* after TX status because the destination was asleep, it must not +* be modified again (no seqno assignment, crypto, etc.) */ enum mac80211_tx_control_flags {IEEE80211_TX_CTL_REQ_TX_STATUS =BIT (0 ),
@@ -291,6 +294,7 @@ enum mac80211_tx_control_flags {IEEE80211_TX_INTFL_DONT_ENCRYPT =BIT (16 ),IEEE80211_TX_CTL_PSPOLL_RESPONSE =BIT (17 ),IEEE80211_TX_CTL_MORE_FRAMES =BIT (18 ), + IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), };/**
net/mac80211/tx.c +6 -1
@@ -1285,6 +1285,7 @@ static int __ieee80211_tx(struct ieee802static int invoke_tx_handlers (struct ieee80211_tx_data *tx) {struct sk_buff *skb = tx->skb; +struct ieee80211_tx_info *info =IEEE80211_SKB_CB (skb);ieee80211_tx_result res =TX_DROP ;#define CALL_TXH (txh) \
@@ -1299,9 +1300,13 @@ static int invoke_tx_handlers(struct ieeCALL_TXH (ieee80211_tx_h_ps_buf);CALL_TXH (ieee80211_tx_h_select_key);CALL_TXH (ieee80211_tx_h_sta); -CALL_TXH (ieee80211_tx_h_michael_mic_add);if (!(tx->local->hw.flags &IEEE80211_HW_HAS_RATE_CONTROL ))CALL_TXH (ieee80211_tx_h_rate_ctrl); + +if (unlikely (info->flags &IEEE80211_TX_INTFL_RETRANSMISSION )) + goto txh_done; + +CALL_TXH (ieee80211_tx_h_michael_mic_add);CALL_TXH (ieee80211_tx_h_sequence);CALL_TXH (ieee80211_tx_h_fragment);/* handlers after fragment must be aware of tx info fragmentation! */