[PATCH] d80211: fix get_tsf call

2006-12-20 Thread Hong Liu
get_tsf passes the wrong pointer to driver.


Signed-off-by: Hong Liu [EMAIL PROTECTED]

diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 3b55427..e48295e 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -2482,7 +2482,7 @@ #ifdef CONFIG_D80211_IBSS_DEBUG
static unsigned long last_tsf_debug = 0;
u64 tsf;
if (local-ops-get_tsf)
-   tsf = local-ops-get_tsf(local-mdev);
+   tsf = local-ops-get_tsf(local_to_hw(local));
else
tsf = -1LLU;
if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] d80211: fix softlockup in hw_scan card when rmmod

2006-12-19 Thread Hong Liu
The local-scan_work.data is not clear after scan is completed.

This will cause softlockup when removing driver module because 
the local-scan_work is not initialized for hw_scan card
and we are trying to cancel the scan_work with an uninitialized timer_list.



Signed-off-by: Hong Liu [EMAIL PROTECTED]

diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 507d071..3b55427 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -3641,6 +3641,7 @@ void ieee80211_scan_completed(struct iee
printk(KERN_DEBUG %s: scan completed\n, dev-name);
spin_lock_bh(local-ifsta_data_lock);
local-sta_scanning = 0;
+   local-scan_work.data = NULL;
local-last_scan_completed = jiffies;
spin_unlock_bh(local-ifsta_data_lock);
 
-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [patch 1/2]d80211: hardware TKIP support for ipw3945

2006-11-13 Thread Hong Liu
Resend the patch according to Johannes's comments.
Still put he tkip_key in tx_control structure.


Signed-off-by: Hong Liu [EMAIL PROTECTED]

diff --git a/include/net/d80211.h b/include/net/d80211.h
index 812f2d1..cf87adc 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -159,6 +159,7 @@ #define IEEE80211_TXCTL_CLEAR_DST_MASK  (
 #define IEEE80211_TXCTL_REQUEUE(17)
 #define IEEE80211_TXCTL_FIRST_FRAGMENT (18) /* this is a first fragment of
* the frame */
+#define IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY (19)
u32 flags; /* tx control flags defined
* above */
u16 rts_cts_duration;   /* duration field for RTS/CTS frame */
@@ -169,6 +170,7 @@ #define IEEE80211_TXCTL_FIRST_FRAGMENT  (
 * hw-set_key() */
u8 icv_len; /* length of the ICV/MIC field in octets */
u8 iv_len;  /* length of the IV field in octets */
+   u8 tkip_key[16];/* generated phase2/phase1 key for hw TKIP */
u8 queue;   /* hardware queue to use for this frame;
 * 0 = highest, hw-queues-1 = lowest */
u8 sw_retry_attempt;/* number of times hw has tried to
@@ -487,6 +489,15 @@ #define IEEE80211_HW_MONITOR_DURING_OPER
 * i.e. more than one skb per frame */
 #define IEEE80211_HW_FRAGLIST (111)
 
+   /* calculate Michael MIC for an MSDU when doing hwcrypto */
+#define IEEE80211_HW_TKIP_INCLUDE_MMIC (112)
+   /* Do TKIP phase1 key mixing in stack to support cards only do
+* phase2 key mixing when doing hwcrypto */
+#define IEEE80211_HW_TKIP_REQ_PHASE1_KEY (113)
+   /* Do TKIP phase1 and phase2 key mixing in stack and send the generated
+* per-packet RC4 key with each TX frame when doing hwcrypto */
+#define IEEE80211_HW_TKIP_REQ_PHASE2_KEY (114)
+
u32 flags;  /* hardware flags defined above */
 
 /* This is the time in us to change channels
diff --git a/net/d80211/tkip.c b/net/d80211/tkip.c
index 7e3665a..fd02449 100644
--- a/net/d80211/tkip.c
+++ b/net/d80211/tkip.c
@@ -190,17 +190,16 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, stru
return pos;
 }
 
-
-/* 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. */
-void ieee80211_tkip_encrypt_data(struct crypto_tfm *tfm, struct ieee80211_key 
*key,
-u8 *pos, size_t payload_len, u8 *ta)
+void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
+ u16 *phase1key)
 {
-   u8 rc4key[16];
+   tkip_mixing_phase1(ta, key-key[ALG_TKIP_TEMP_ENCR_KEY],
+  key-u.tkip.iv32, phase1key);
+}
 
+void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
+  u8 *rc4key)
+{
/* Calculate per-packet key */
if (key-u.tkip.iv16 == 0 || !key-u.tkip.tx_initialized) {
/* IV16 wrapped around - perform TKIP phase 1 */
@@ -211,7 +210,19 @@ void ieee80211_tkip_encrypt_data(struct 
 
tkip_mixing_phase2(key-u.tkip.p1k, key-key[ALG_TKIP_TEMP_ENCR_KEY],
   key-u.tkip.iv16, rc4key);
+}
+
+/* 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. */
+void ieee80211_tkip_encrypt_data(struct crypto_tfm *tfm, struct ieee80211_key 
*key,
+u8 *pos, size_t payload_len, u8 *ta)
+{
+   u8 rc4key[16];
 
+   ieee80211_tkip_gen_rc4key(key, ta, rc4key);
pos = ieee80211_tkip_add_iv(pos, key, rc4key[0], rc4key[1], rc4key[2]);
ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
 }
diff --git a/net/d80211/tkip.h b/net/d80211/tkip.h
index e36b85c..9b22717 100644
--- a/net/d80211/tkip.h
+++ b/net/d80211/tkip.h
@@ -15,6 +15,10 @@ #include ieee80211_key.h
 
 u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
   u8 iv0, u8 iv1, u8 iv2);
+void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
+ u16 *phase1key);
+void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
+  u8 *rc4key);
 void ieee80211_tkip_encrypt_data(struct crypto_tfm *tfm, struct ieee80211_key 
*key

[patch] d80211: fix key access race

2006-11-02 Thread Hong Liu
It seems we don't have any protection when accessing the key.
The RX/TX path may acquire a key which can be freed by the
ioctl cmd.

I put a key_lock spinlock to protect all the accesses to the key
(whether the sta_info-key or ieee80211_sub_if_data-keys[]). 
Don't find a good way to handle it :(

Thanks,
Hong

Signed-off-by: Hong Liu [EMAIL PROTECTED]

diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 751bc76..1a1f6fb 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -99,12 +99,38 @@ struct ieee80211_key *ieee80211_key_allo
return key;
 }
 
-void ieee80211_key_free(struct ieee80211_key *key)
+void ieee80211_key_put(struct ieee80211_key *key)
 {
if (key)
kobject_put(key-kobj);
 }
 
+void ieee80211_key_get(struct ieee80211_key *key)
+{
+   if (key)
+   kobject_get(key-kobj);
+}
+
+void ieee80211_key_free(struct ieee80211_local *local,
+   struct ieee80211_key **key,
+   struct ieee80211_sub_if_data *sdata)
+{
+   int remove_def = 0;
+
+   if (*key  sdata  sdata-default_key == *key) {
+   ieee80211_key_sysfs_remove_default(sdata);
+   remove_def = 1;
+   }
+   ieee80211_key_sysfs_remove(*key);
+
+   spin_lock_bh(local-key_lock);
+   if (remove_def)
+   sdata-default_key = NULL;
+   *key = NULL;
+   ieee80211_key_put(*key);
+   spin_unlock_bh(local-key_lock);
+}
+
 void ieee80211_key_release(struct kobject *kobj)
 {
struct ieee80211_key *key;
@@ -402,6 +428,7 @@ ieee80211_tx_h_select_key(struct ieee802
else
tx-u.tx.control-key_idx = HW_KEY_IDX_INVALID;
 
+   spin_lock_bh(tx-local-key_lock);
if (unlikely(tx-u.tx.control-flags  IEEE80211_TXCTL_DO_NOT_ENCRYPT))
tx-key = NULL;
else if (tx-sta  tx-sta-key)
@@ -410,11 +437,16 @@ ieee80211_tx_h_select_key(struct ieee802
tx-key = tx-sdata-default_key;
else if (tx-sdata-drop_unencrypted 
 !(tx-sdata-eapol  ieee80211_is_eapol(tx-skb))) {
+   spin_unlock_bh(tx-local-key_lock);
I802_DEBUG_INC(tx-local-tx_handlers_drop_unencrypted);
return TXRX_DROP;
} else
tx-key = NULL;
 
+   if (tx-key)
+   ieee80211_key_get(tx-key);
+   spin_unlock_bh(tx-local-key_lock);
+
if (tx-key) {
tx-key-tx_rx_count++;
if (unlikely(tx-local-key_tx_rx_threshold 
@@ -1216,6 +1248,9 @@ static int ieee80211_tx(struct net_devic
 
skb = tx.skb; /* handlers are allowed to change skb */
 
+   if (tx.key)
+   ieee80211_key_put(tx.key);
+
if (sta)
sta_info_put(sta);
 
@@ -3092,6 +3127,7 @@ ieee80211_rx_h_check(struct ieee80211_tx
else
always_sta_key = 1;
 
+   spin_lock(rx-local-key_lock);
if (rx-sta  rx-sta-key  always_sta_key) {
rx-key = rx-sta-key;
 } else {
@@ -3109,6 +3145,7 @@ ieee80211_rx_h_check(struct ieee80211_tx
rx-key = rx-sdata-keys[keyidx];
 
if (!rx-key) {
+   spin_unlock(rx-local-key_lock);
if (!rx-u.rx.ra_match)
return TXRX_DROP;
printk(KERN_DEBUG %s: RX WEP frame with 
@@ -3126,6 +3163,10 @@ ieee80211_rx_h_check(struct ieee80211_tx
}
 }
 
+   if (rx-key)
+   ieee80211_key_get(rx-key);
+   spin_unlock(rx-local-key_lock);
+
if (rx-fc  IEEE80211_FCTL_PROTECTED  rx-key  rx-u.rx.ra_match) {
rx-key-tx_rx_count++;
if (unlikely(rx-local-key_tx_rx_threshold 
@@ -3705,6 +3746,8 @@ void __ieee80211_rx(struct net_device *d
}
 
   end:
+   if (rx.key)
+   ieee80211_key_put(rx.key);
if (sta)
sta_info_put(sta);
 }
@@ -4411,6 +4454,7 @@ struct net_device *ieee80211_alloc_hw(si
 init_timer(local-scan.timer); /* clear it out */
 
 spin_lock_init(local-generic_lock);
+   spin_lock_init(local-key_lock);
init_timer(local-stat_timer);
local-stat_timer.function = ieee80211_stat_refresh;
local-stat_timer.data = (unsigned long) local;
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 89666ec..8e2a4a3 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -361,6 +361,7 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
} ieee80211_msg_enum;
 
 spinlock_t generic_lock;
+   spinlock_t key_lock;
/* Station data structures */
struct kset sta_kset;
spinlock_t sta_lock; /* mutex for STA data structures */
@@ -568,7 +569,11 @@ ieee80211_key_data2conf(struct ieee80211
struct ieee80211_key *data);
 struct ieee80211_key *ieee80211_key_alloc

Re: [patch 1/2]d80211: hardware TKIP support for ipw3945

2006-10-25 Thread Hong Liu
On Tue, 2006-10-24 at 17:10, Johannes Berg wrote:
 On Tue, 2006-10-24 at 16:38 +0800, Hong Liu wrote:
 
  The first time when we set the TKIP key, we can set the phase1 key if
  the driver requires.
 
 Right.
 
  The problem is when IV16 wraps, who will generate the new phase1 key?
 
 Ok, I was confused for a moment, but yes, when the 16-bit part of the IV
 wraps then the upper part changes and hence you need to regenerate the
 phase1 key.
 
  If the stack need to do this, then we will need to call set_key in the
  packet TX path which I think may not be appropriate.
 
 Well, I checked again and found that bcm34xx requires the IV (48) to be
 maintained by software, iow with each packet you tell the hardware what
 the IV16 should be. Hence you know when it has wrapped and thus (before
 submitting the DMA for the packet) you can regenerate the phase1 key in
 software and upload it to the hardware key memory.
 
 This is getting quite complicated. How about having the stack maintain
 the IV *only*, and adding helper functions for
  * generating the phase 1 key
  * generating the phase 2 key based on the phase 1 key
 that the drivers can use as required?
 
 ipw3945 would call both key generation functions as required, and
 bcm43xx would just call the phase 1 function when a key is uploaded and
 when the iv16 wraps, not using the phase 2 function at all.
 
 johannes
 
 

I'd prefer to let the stack tell the driver when there is new phase1 key
generated.
Rebase the patch on David Kimdon's bitfield removing patches.


Signed-off-by: Hong Liu [EMAIL PROTECTED]

diff --git a/include/net/d80211.h b/include/net/d80211.h
index 812f2d1..2570072 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -159,6 +159,7 @@ #define IEEE80211_TXCTL_CLEAR_DST_MASK  (
 #define IEEE80211_TXCTL_REQUEUE(17)
 #define IEEE80211_TXCTL_FIRST_FRAGMENT (18) /* this is a first fragment of
* the frame */
+#define IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY (19)
u16 flags; /* tx control flags defined
* above */
u16 rts_cts_duration;   /* duration field for RTS/CTS frame */
@@ -169,6 +170,8 @@ #define IEEE80211_TXCTL_FIRST_FRAGMENT  (
 * hw-set_key() */
u8 icv_len; /* length of the ICV/MIC field in octets */
u8 iv_len;  /* length of the IV field in octets */
+   u8 tkip_keylen;
+   u8 tkip_key[16];/* generated RC4/phase1 key for hw TKIP */
u8 queue;   /* hardware queue to use for this frame;
 * 0 = highest, hw-queues-1 = lowest */
u8 sw_retry_attempt;/* number of times hw has tried to
@@ -487,6 +490,15 @@ #define IEEE80211_HW_MONITOR_DURING_OPER
 * i.e. more than one skb per frame */
 #define IEEE80211_HW_FRAGLIST (111)
 
+   /* calculate Michael MIC for an MSDU when doing hwcrypto */
+#define IEEE80211_HW_TKIP_INCLUDE_MMIC (112)
+   /* Do TKIP phase1 key mixing in stack to support cards only do
+* phase2 key mixing when doing hwcrypto */
+#define IEEE80211_HW_TKIP_REQ_PHASE1_KEY (113)
+   /* Do TKIP phase1 and phase2 key mixing in stack and send the generated
+* per-packet RC4 key with each TX frame when doing hwcrypto */
+#define IEEE80211_HW_TKIP_REQ_PHASE2_KEY (114)
+
u32 flags;  /* hardware flags defined above */
 
 /* This is the time in us to change channels
diff --git a/net/d80211/tkip.c b/net/d80211/tkip.c
index 7e3665a..fd02449 100644
--- a/net/d80211/tkip.c
+++ b/net/d80211/tkip.c
@@ -190,17 +190,16 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, stru
return pos;
 }
 
-
-/* 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. */
-void ieee80211_tkip_encrypt_data(struct crypto_tfm *tfm, struct ieee80211_key 
*key,
-u8 *pos, size_t payload_len, u8 *ta)
+void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
+ u16 *phase1key)
 {
-   u8 rc4key[16];
+   tkip_mixing_phase1(ta, key-key[ALG_TKIP_TEMP_ENCR_KEY],
+  key-u.tkip.iv32, phase1key);
+}
 
+void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
+  u8 *rc4key)
+{
/* Calculate per-packet key */
if (key-u.tkip.iv16 == 0 || !key-u.tkip.tx_initialized) {
/* IV16 wrapped around - perform TKIP phase 1 */
@@ -211,7 +210,19 @@ void ieee80211_tkip_encrypt_data(struct 
 
tkip_mixing_phase2(key-u.tkip.p1k, key-key[ALG_TKIP_TEMP_ENCR_KEY

about 802.11i IBSS support

2006-10-25 Thread Hong Liu
Hi,
I am reading the 802.11i IBSS spec and
trying to find if it is OK to add patches to d80211 to support this feature.

For 802.11i IBSS to work, each STA assumes two roles: supplicant + 
authenticator.
Usually in BSS network, authenticator is in AP.
The problem is the distribution of group keys.
The group key is used for one-to-many communication.
In BSS, the one is the AP, so the AP is responsible for the distribution of the 
group key.
In IBSS, every STA has its own group key, used to broadcast data to other STAs.

When a STA (say S1) joins in an IBSS network with N STAs,
it must negotiate keys with all N STAs.
The process for negotiation with one STA is as follows:
1. S1 init a 4-way handshake with one STA (say S2),
   to derive the pairwise key between them and then S1 sends its group key to 
S2,
   let S2 can decrypt s1's broadcast data.
2. S2 init the second 4-way handshake with S1, the main purpose for this 4-way 
handshake
   is for S2 to send its group key to S1, although this will also derive a 
second pairwise key.
3. Because in an IBSS there are two 4-Way Handshakes between 
   any two STA Supplicants and Authenticators, the pairwise key used between 
any two STAs
   is from the 4-Way Handshake initiated by the STA Authenticator with the 
higher MAC address.
So any STA in an IBSS network with N STAs must keep 2N-1 keys (N-1 for pairwise 
key and N for group key).

We need the following parts to make 802.11i IBSS work:

1. for the d80211 part: I don't think there will be much efforts.
   We may add a group key to each sta_info for decrypting multicast data from 
that STA.
   And in RX path, we need to add code to select the correct group key for 
decryption.
   And also we need to store our own group key used to send multicast data to 
others.

   It should not be difficult because the infrastructures are all there in the 
dscape stack.

2. wpa_supplicant: this is the big part, we need to implement the authenticator
   in it. Not sure how much efforts needed?

Thanks,
Hong
-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: about 802.11i IBSS support

2006-10-25 Thread Hong Liu
On Wed, 2006-10-25 at 23:48, Jouni Malinen wrote:
 On Wed, Oct 25, 2006 at 04:54:41PM +0800, Hong Liu wrote:
 
  I am reading the 802.11i IBSS spec and
  trying to find if it is OK to add patches to d80211 to support this feature.
 
 Large parts of this will be outside d80211, but yes, I think d80211
 should be made ready to support this (mainly in the multiple group keys
 area).
 
  When a STA (say S1) joins in an IBSS network with N STAs,
  it must negotiate keys with all N STAs.
 
 I don't think it is required to negotiate keys with all STAs of the
 network unless it actually needs to communicate with them, i.e., there
 may be cases where it is not needed to send or receive data from some of
 the nodes.

This may add complexity to the implementation.

If the STA wants to send broadcast data, it must distribute its group
key to all other STAs, and then it can send out the packet.

For RX, if it receives data from other STA it needs to find out whether it
has finished key negotiation with that STA. And it can not decrypt the data
until key negotiation is finished.

If we negotiate keys at the beginning, things will be simple.
But the cost is we may negotiating keys with STAs we may not communicate with.

Thanks,
Hong
-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [patch 1/2]d80211: hardware TKIP support for ipw3945

2006-10-24 Thread Hong Liu
On Mon, 2006-10-23 at 20:56, Jiri Benc wrote:
 On Mon, 23 Oct 2006 14:48:00 +0200, Johannes Berg wrote:
  On Mon, 2006-10-23 at 14:40 +0200, Jiri Benc wrote:
   I don't like extending ieee80211_tx_control by 16 more bytes. The
   driver is required to store a copy of each ieee80211_tx_control
   (because it's copied to ieee80211_tx_status). I don't have a better
   idea, though. Anybody?
  
  A pointer that goes somewhere else? I suppose it could even be in the
  skb's cb field.
 
 Yes, that could work. Thanks!
 
  Also, something I just came to think of, bcm43xx does phase2 mixing in
  hw and requires phase1 in software. Do we handle that with or without
  this patch? If not, it'd be nice to fix it up together.
 
 It's not supported now. And it's really a good idea to extend the patch
 to support the bcm43xx case as well.
 
  Jiri

It's really strange bcm43xx only does phase2 mixing in hw. With all the
code that does phase2 mixing, doing phase1 mixing is very cheap.

With Jiri's ieee80211_tx_ctrl_common patch, I think we can put the
rc4key or phase1 key in ieee80211_tx_control with each TX packet.


Thanks,
Hong
-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [patch 1/2]d80211: hardware TKIP support for ipw3945

2006-10-24 Thread Hong Liu
On Tue, 2006-10-24 at 16:35, Johannes Berg wrote:
 On Tue, 2006-10-24 at 16:20 +0800, Hong Liu wrote:
 
  It's really strange bcm43xx only does phase2 mixing in hw. With all the
  code that does phase2 mixing, doing phase1 mixing is very cheap.
 
 Yeah, well, they have the tkip sbox in hw.
 
  With Jiri's ieee80211_tx_ctrl_common patch, I think we can put the
  rc4key or phase1 key in ieee80211_tx_control with each TX packet.
 
 No, the phase1 key is not dependent on the packet so it should not be
 there. It should be set via the regular key setting mechanism, instead
 of the TKIP key the driver would be given the phase1 key if required.
 
 johannes

The first time when we set the TKIP key, we can set the phase1 key if
the driver requires.
The problem is when IV16 wraps, who will generate the new phase1 key?
If the stack need to do this, then we will need to call set_key in the
packet TX path which I think may not be appropriate.

Thanks,
Hong
-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[patch 1/2]d80211: hardware TKIP support for ipw3945

2006-10-20 Thread Hong Liu
ipw3945 TKIP hwcrypto only support RC4 encryption,
so the stack needs to pre compute the michael MIC and the RC4key
for it.

Signed-off-by: Hong Liu [EMAIL PROTECTED]

---

 include/net/d80211.h |7 +++
 net/d80211/tkip.c|   25 +++--
 net/d80211/tkip.h|2 ++
 net/d80211/wpa.c |   10 +-
 4 files changed, 33 insertions(+), 11 deletions(-)

a759f6251a0a5c7a8529c2ebd579acd6f0183cb4
diff --git a/include/net/d80211.h b/include/net/d80211.h
index a80f48b..48e1e01 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -176,6 +176,7 @@ struct ieee80211_tx_control {
*/
int icv_len:8; /* Length of the ICV/MIC field in octets */
int iv_len:8; /* Length of the IV field in octets */
+   u8 rc4key[16]; /* generated RC4 key for hw TKIP */
unsigned int queue:4; /* hardware queue to use for this frame;
  * 0 = highest, hw-queues-1 = lowest */
unsigned int sw_retry_attempt:4; /* no. of times hw has tried to
@@ -476,6 +477,12 @@ struct ieee80211_hw {
/* Force software encryption for TKIP packets if WMM is enabled. */
unsigned int no_tkip_wmm_hwaccel:1;
 
+   /* Do TKIP key mixing in stack, send the generated RC4 key with
+* with each TX frame */
+   unsigned int tkip_include_rc4key:1;
+   /* calculate michael MIC in stack */
+   unsigned int tkip_include_mmic:1;
+
/* set if the payload needs to be padded at even boundaries after the
 * header */
unsigned int extra_hdr_room:1;
diff --git a/net/d80211/tkip.c b/net/d80211/tkip.c
index 7e3665a..c031814 100644
--- a/net/d80211/tkip.c
+++ b/net/d80211/tkip.c
@@ -190,17 +190,9 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, stru
return pos;
 }
 
-
-/* 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. */
-void ieee80211_tkip_encrypt_data(struct crypto_tfm *tfm, struct ieee80211_key 
*key,
-u8 *pos, size_t payload_len, u8 *ta)
+void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key,
+  u8 *rc4key, u8* ta)
 {
-   u8 rc4key[16];
-
/* Calculate per-packet key */
if (key-u.tkip.iv16 == 0 || !key-u.tkip.tx_initialized) {
/* IV16 wrapped around - perform TKIP phase 1 */
@@ -212,6 +204,19 @@ void ieee80211_tkip_encrypt_data(struct 
tkip_mixing_phase2(key-u.tkip.p1k, key-key[ALG_TKIP_TEMP_ENCR_KEY],
   key-u.tkip.iv16, rc4key);
 
+}
+
+/* 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. */
+void ieee80211_tkip_encrypt_data(struct crypto_tfm *tfm, struct ieee80211_key 
*key,
+u8 *pos, size_t payload_len, u8 *ta)
+{
+   u8 rc4key[16];
+
+   ieee80211_tkip_gen_rc4key(key, rc4key, ta);
pos = ieee80211_tkip_add_iv(pos, key, rc4key[0], rc4key[1], rc4key[2]);
ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
 }
diff --git a/net/d80211/tkip.h b/net/d80211/tkip.h
index e36b85c..407556b 100644
--- a/net/d80211/tkip.h
+++ b/net/d80211/tkip.h
@@ -15,6 +15,8 @@ #include ieee80211_key.h
 
 u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
   u8 iv0, u8 iv1, u8 iv2);
+void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key,
+  u8 *rc4key, u8* ta);
 void ieee80211_tkip_encrypt_data(struct crypto_tfm *tfm, struct ieee80211_key 
*key,
 u8 *pos, size_t payload_len, u8 *ta);
 enum {
diff --git a/net/d80211/wpa.c b/net/d80211/wpa.c
index 31abf9b..5e62464 100644
--- a/net/d80211/wpa.c
+++ b/net/d80211/wpa.c
@@ -104,7 +104,8 @@ #ifdef CONFIG_HOSTAPD_WPA_TESTING
 #endif /* CONFIG_HOSTAPD_WPA_TESTING */
 
if (!tx-key-force_sw_encrypt  !tx-local-conf.sw_decrypt 
-   !tx-fragmented  !wpa_test) {
+   !tx-fragmented  !tx-local-hw-tkip_include_mmic 
+   !wpa_test) {
/* hwaccel - with no need for preallocated room for Michael MIC
 */
return TXRX_CONTINUE;
@@ -336,6 +337,13 @@ #endif /* CONFIG_HOSTAPD_WPA_TESTING */
0x7f),
  (u8) key-u.tkip.iv16);
 
+   if (tx-local-hw-tkip_include_rc4key) {
+   hdr = (struct ieee80211_hdr *)skb-data

[patch 2/2] d80211: fix wep_tfm race

2006-10-20 Thread Hong Liu
The TX/RX path all use the local-wep_tfm to encrypt and decrypt
packets. Each {en|de}crypt operation need set a new RC4key,
this may corrupt the previous set key that is still being used.
Thus cause a lot of decrypton error or encryption with the wrong key.
Use two tfm (tx_tfm and rx_tfm) to avoid this race.

Signed-off-by: Hong Liu [EMAIL PROTECTED]

---

 net/d80211/ieee80211_i.h |3 ++-
 net/d80211/wep.c |   18 +-
 net/d80211/wpa.c |6 --
 3 files changed, 19 insertions(+), 8 deletions(-)

634c9615ce3cd06dc7f6aff05e43e61490a53472
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 425fc9b..152b41a 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -402,7 +402,8 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
int long_retry_limit; /* dot11LongRetryLimit */
int short_preamble; /* use short preamble with IEEE 802.11b */
 
-   struct crypto_tfm *wep_tfm;
+   struct crypto_tfm *wep_tx_tfm;
+   struct crypto_tfm *wep_rx_tfm;
u32 wep_iv;
int key_tx_rx_threshold; /* number of times any key can be used in TX
  * or RX before generating a rekey
diff --git a/net/d80211/wep.c b/net/d80211/wep.c
index 22c2e53..06e0230 100644
--- a/net/d80211/wep.c
+++ b/net/d80211/wep.c
@@ -26,16 +26,23 @@ int ieee80211_wep_init(struct ieee80211_
/* start WEP IV from a random value */
get_random_bytes(local-wep_iv, WEP_IV_LEN);
 
-   local-wep_tfm = crypto_alloc_tfm(arc4, 0);
-   if (!local-wep_tfm)
+   local-wep_tx_tfm = crypto_alloc_tfm(arc4, 0);
+   if (!local-wep_tx_tfm)
return -ENOMEM;
 
+   local-wep_rx_tfm = crypto_alloc_tfm(arc4, 0);
+   if (!local-wep_rx_tfm) {
+   crypto_free_tfm(local-wep_tx_tfm);
+   return -ENOMEM;
+   }
+
return 0;
 }
 
 void ieee80211_wep_free(struct ieee80211_local *local)
 {
-   crypto_free_tfm(local-wep_tfm);
+   crypto_free_tfm(local-wep_tx_tfm);
+   crypto_free_tfm(local-wep_rx_tfm);
 }
 
 static inline int ieee80211_wep_weak_iv(u32 iv, int keylen)
@@ -172,7 +179,8 @@ int ieee80211_wep_encrypt(struct ieee802
/* Add room for ICV */
skb_put(skb, WEP_ICV_LEN);
 
-   ieee80211_wep_encrypt_data(local-wep_tfm, rc4key, klen, iv + 
WEP_IV_LEN, len);
+   ieee80211_wep_encrypt_data(local-wep_tx_tfm, rc4key, klen,
+  iv + WEP_IV_LEN, len);
 
kfree(rc4key);
 
@@ -252,7 +260,7 @@ int ieee80211_wep_decrypt(struct ieee802
/* Copy rest of the WEP key (the secret part) */
memcpy(rc4key + 3, key-key, key-keylen);
 
-   if (ieee80211_wep_decrypt_data(local-wep_tfm, rc4key, klen,
+   if (ieee80211_wep_decrypt_data(local-wep_rx_tfm, rc4key, klen,
   skb-data + hdrlen + WEP_IV_LEN,
   len)) {
printk(KERN_DEBUG WEP decrypt failed (ICV)\n);
diff --git a/net/d80211/wpa.c b/net/d80211/wpa.c
index 5e62464..ef707ad 100644
--- a/net/d80211/wpa.c
+++ b/net/d80211/wpa.c
@@ -352,7 +352,8 @@ #endif /* CONFIG_HOSTAPD_WPA_TESTING */
skb_put(skb, TKIP_ICV_LEN);
 
hdr = (struct ieee80211_hdr *) skb-data;
-   ieee80211_tkip_encrypt_data(tx-local-wep_tfm, key, pos, len, 
hdr-addr2);
+   ieee80211_tkip_encrypt_data(tx-local-wep_tx_tfm,
+   key, pos, len, hdr-addr2);
return 0;
 }
 
@@ -495,7 +496,8 @@ #endif /* CONFIG_HOSTAPD_WPA_TESTING */
hwaccel = 1;
}
 
-   res = ieee80211_tkip_decrypt_data(rx-local-wep_tfm, key, skb-data + 
hdrlen,
+   res = ieee80211_tkip_decrypt_data(rx-local-wep_rx_tfm,
+ key, skb-data + hdrlen,
  skb-len - hdrlen, rx-sta-addr,
  hwaccel, rx-u.rx.queue);
if (res != TKIP_DECRYPT_OK || wpa_test) {
-- 
1.3.3

-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[patch 2/2] d80211: fix wep_tfm race

2006-10-20 Thread Hong Liu
The TX/RX path all use the local-wep_tfm to encrypt and decrypt
packets. Each {en|de}crypt operation need set a new RC4key,
this may corrupt the previous set key that is still being used.
Thus cause a lot of decrypton error or encryption with the wrong key.
Use two tfm (tx_tfm and rx_tfm) to avoid this race.

Signed-off-by: Hong Liu [EMAIL PROTECTED]

---

 net/d80211/ieee80211_i.h |3 ++-
 net/d80211/wep.c |   18 +-
 net/d80211/wpa.c |6 --
 3 files changed, 19 insertions(+), 8 deletions(-)

634c9615ce3cd06dc7f6aff05e43e61490a53472
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 425fc9b..152b41a 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -402,7 +402,8 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
int long_retry_limit; /* dot11LongRetryLimit */
int short_preamble; /* use short preamble with IEEE 802.11b */
 
-   struct crypto_tfm *wep_tfm;
+   struct crypto_tfm *wep_tx_tfm;
+   struct crypto_tfm *wep_rx_tfm;
u32 wep_iv;
int key_tx_rx_threshold; /* number of times any key can be used in TX
  * or RX before generating a rekey
diff --git a/net/d80211/wep.c b/net/d80211/wep.c
index 22c2e53..06e0230 100644
--- a/net/d80211/wep.c
+++ b/net/d80211/wep.c
@@ -26,16 +26,23 @@ int ieee80211_wep_init(struct ieee80211_
/* start WEP IV from a random value */
get_random_bytes(local-wep_iv, WEP_IV_LEN);
 
-   local-wep_tfm = crypto_alloc_tfm(arc4, 0);
-   if (!local-wep_tfm)
+   local-wep_tx_tfm = crypto_alloc_tfm(arc4, 0);
+   if (!local-wep_tx_tfm)
return -ENOMEM;
 
+   local-wep_rx_tfm = crypto_alloc_tfm(arc4, 0);
+   if (!local-wep_rx_tfm) {
+   crypto_free_tfm(local-wep_tx_tfm);
+   return -ENOMEM;
+   }
+
return 0;
 }
 
 void ieee80211_wep_free(struct ieee80211_local *local)
 {
-   crypto_free_tfm(local-wep_tfm);
+   crypto_free_tfm(local-wep_tx_tfm);
+   crypto_free_tfm(local-wep_rx_tfm);
 }
 
 static inline int ieee80211_wep_weak_iv(u32 iv, int keylen)
@@ -172,7 +179,8 @@ int ieee80211_wep_encrypt(struct ieee802
/* Add room for ICV */
skb_put(skb, WEP_ICV_LEN);
 
-   ieee80211_wep_encrypt_data(local-wep_tfm, rc4key, klen, iv + 
WEP_IV_LEN, len);
+   ieee80211_wep_encrypt_data(local-wep_tx_tfm, rc4key, klen,
+  iv + WEP_IV_LEN, len);
 
kfree(rc4key);
 
@@ -252,7 +260,7 @@ int ieee80211_wep_decrypt(struct ieee802
/* Copy rest of the WEP key (the secret part) */
memcpy(rc4key + 3, key-key, key-keylen);
 
-   if (ieee80211_wep_decrypt_data(local-wep_tfm, rc4key, klen,
+   if (ieee80211_wep_decrypt_data(local-wep_rx_tfm, rc4key, klen,
   skb-data + hdrlen + WEP_IV_LEN,
   len)) {
printk(KERN_DEBUG WEP decrypt failed (ICV)\n);
diff --git a/net/d80211/wpa.c b/net/d80211/wpa.c
index 5e62464..ef707ad 100644
--- a/net/d80211/wpa.c
+++ b/net/d80211/wpa.c
@@ -352,7 +352,8 @@ #endif /* CONFIG_HOSTAPD_WPA_TESTING */
skb_put(skb, TKIP_ICV_LEN);
 
hdr = (struct ieee80211_hdr *) skb-data;
-   ieee80211_tkip_encrypt_data(tx-local-wep_tfm, key, pos, len, 
hdr-addr2);
+   ieee80211_tkip_encrypt_data(tx-local-wep_tx_tfm,
+   key, pos, len, hdr-addr2);
return 0;
 }
 
@@ -495,7 +496,8 @@ #endif /* CONFIG_HOSTAPD_WPA_TESTING */
hwaccel = 1;
}
 
-   res = ieee80211_tkip_decrypt_data(rx-local-wep_tfm, key, skb-data + 
hdrlen,
+   res = ieee80211_tkip_decrypt_data(rx-local-wep_rx_tfm,
+ key, skb-data + hdrlen,
  skb-len - hdrlen, rx-sta-addr,
  hwaccel, rx-u.rx.queue);
if (res != TKIP_DECRYPT_OK || wpa_test) {
-- 
1.3.3

-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH]d80211: fix iwconfig key [x] behavior

2006-09-22 Thread Hong Liu
On Thu, 2006-09-21 at 23:51, Jiri Benc wrote:
 Hi,
 
 sorry for the delay.
 
 On Fri, 01 Sep 2006 11:37:57 +0800, Hong Liu wrote:
  @@ -2925,7 +2932,8 @@ static int ieee80211_ioctl_giwencode(str
  return 0;
  }
   
  -   erq-length = 0;
  +   erq-length = min((int)erq-length, sdata-keys[idx]-keylen);
  +   memcpy(key, sdata-keys[idx]-key, erq-length);
  erq-flags |= IW_ENCODE_ENABLED;
   
  return 0;
 
 This is still not correct, erq-length should be set to the actual key
 length to allow WE to return -E2BIG in case of too small buffer.
 
   memcpy(key, sdata-keys[idx]-key,
  min((int)erq-length, sdata-keys[idx]-keylen));
   erq-length = sdata-keys[idx]-keylen;
 
  Jiri

Resend.

Thanks,
Hong


Signed-off-by: Hong Liu [EMAIL PROTECTED]

diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 89a58e3..bde0c43 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -2867,9 +2867,10 @@ static int ieee80211_ioctl_siwencode(str
if (!sdata-default_key)
idx = 0;
else for (i = 0; i  NUM_DEFAULT_KEYS; i++) {
-   if (sdata-default_key == sdata-keys[i])
+   if (sdata-default_key == sdata-keys[i]) {
idx = i;
-   break;
+   break;
+   }
}
if (idx  0)
return -EINVAL;
@@ -2880,16 +2881,21 @@ static int ieee80211_ioctl_siwencode(str
alg = ALG_NONE;
else if (erq-length == 0) {
/* No key data - just set the default TX key index */
-   sdata-default_key = sdata-keys[idx];
+   if (sdata-default_key != sdata-keys[idx]) {
+   if (sdata-default_key)
+   ieee80211_key_sysfs_remove_default(sdata);
+   sdata-default_key = sdata-keys[idx];
+   if (sdata-default_key)
+   ieee80211_key_sysfs_add_default(sdata);
+   }
+   return 0;
}
 
return ieee80211_set_encryption(
dev, bcaddr,
-   idx, erq-length == 0 ? ALG_NONE : ALG_WEP,
+   idx, alg,
!sdata-default_key,
NULL, keybuf, erq-length);
-
-   return 0;
 }
 
 
@@ -2908,9 +2914,10 @@ static int ieee80211_ioctl_giwencode(str
if (!sdata-default_key)
idx = 0;
else for (i = 0; i  NUM_DEFAULT_KEYS; i++) {
-   if (sdata-default_key == sdata-keys[i])
+   if (sdata-default_key == sdata-keys[i]) {
idx = i;
-   break;
+   break;
+   }
}
if (idx  0)
return -EINVAL;
@@ -2925,7 +2932,9 @@ static int ieee80211_ioctl_giwencode(str
return 0;
}
 
-   erq-length = 0;
+   memcpy(key, sdata-keys[idx]-key,
+  min((int)erq-length, sdata-keys[idx]-keylen));
+   erq-length = sdata-keys[idx]-keylen;
erq-flags |= IW_ENCODE_ENABLED;
 
return 0;
@@ -3054,9 +3063,10 @@ static int ieee80211_ioctl_siwencodeext(
if (!sdata-default_key)
idx = 0;
else for (i = 0; i  NUM_DEFAULT_KEYS; i++) {
-   if (sdata-default_key == sdata-keys[i])
+   if (sdata-default_key == sdata-keys[i]) {
idx = i;
-   break;
+   break;
+   }
}
if (idx  0)
return -EINVAL;
-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 2/2]d80211: add hardware scan callback

2006-09-01 Thread Hong Liu
On Fri, 2006-09-01 at 14:41, Johannes Berg wrote:
 On Fri, 2006-09-01 at 11:37 +0800, Hong Liu wrote:
  
  + local-sta_scanning = 1;
  + if (local-hw-hw_scan)
  + return local-hw-hw_scan(dev, ssid, ssid_len);
  +
 
 My question still stands, is it proper to assign sta_scanning to 1 even
 if the function returns an error?
 
 johannes
 
 
Thanks for point this out!
Change to only set sta_scanning to 1 if hw_scan successes.


Signed-off-by: Hong Liu [EMAIL PROTECTED]

diff --git a/include/net/d80211.h b/include/net/d80211.h
index 42fdbf7..1caa8a9 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -600,6 +600,10 @@ struct ieee80211_hw {
 int (*passive_scan)(struct net_device *dev, int state,
 struct ieee80211_scan_conf *conf);
 
+   /* Ask the hardware to service the scan request, no need to start
+* the scan state machine in stack. */
+   int (*hw_scan)(struct net_device *dev, u8 *ssid, size_t len);
+
 /* return low-level statistics */
int (*get_stats)(struct net_device *dev,
 struct ieee80211_low_level_stats *stats);
@@ -906,6 +910,8 @@ void ieee80211_tx_led(int state, struct 
  */
 void ieee80211_rx_led(int state, struct net_device *dev);
 
+/* called by driver to notify scan status completed */
+void ieee80211_scan_completed(struct net_device *dev);
 
 /* IEEE 802.11 defines */
 
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 557ba17..1f60a22 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -2410,6 +2410,29 @@ static int ieee80211_active_scan(struct 
 }
 
 
+void ieee80211_scan_completed(struct net_device *dev)
+{
+   struct ieee80211_local *local = dev-ieee80211_ptr;
+   struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+   union iwreq_data wrqu;
+
+   printk(KERN_DEBUG %s: scan completed\n, dev-name);
+   local-sta_scanning = 0;
+   local-last_scan_completed = jiffies;
+
+   memset(wrqu, 0, sizeof(wrqu));
+   wireless_send_event(dev, SIOCGIWSCAN, wrqu, NULL);
+
+   if (sdata-type == IEEE80211_IF_TYPE_IBSS) {
+   struct ieee80211_if_sta *ifsta = sdata-u.sta;
+   if (!ifsta-bssid_set ||
+   (!ifsta-state == IEEE80211_IBSS_JOINED 
+   !ieee80211_sta_active_ibss(dev)))
+   ieee80211_sta_find_ibss(dev, ifsta);
+   }
+}
+EXPORT_SYMBOL(ieee80211_scan_completed);
+
 static void ieee80211_sta_scan_work(void *ptr)
 {
struct net_device *dev = ptr;
@@ -2418,7 +2441,6 @@ static void ieee80211_sta_scan_work(void
struct ieee80211_hw_modes *mode;
struct ieee80211_channel *chan;
int skip;
-   union iwreq_data wrqu;
unsigned long next_delay = 0;
 
if (!local-sta_scanning)
@@ -2435,20 +2457,8 @@ static void ieee80211_sta_scan_work(void
   operational channel after scan\n,
   dev-name);
}
-   printk(KERN_DEBUG %s: scan completed\n, dev-name);
-   local-sta_scanning = 0;
-   local-last_scan_completed = jiffies;
-   memset(wrqu, 0, sizeof(wrqu));
-   wireless_send_event(dev, SIOCGIWSCAN, wrqu, NULL);
-   if (sdata-type == IEEE80211_IF_TYPE_IBSS) {
-   struct ieee80211_sub_if_data *sdata =
-   IEEE80211_DEV_TO_SUB_IF(dev);
-   struct ieee80211_if_sta *ifsta = sdata-u.sta;
-   if (!ifsta-bssid_set ||
-   (ifsta-state == IEEE80211_IBSS_JOINED 
-!ieee80211_sta_active_ibss(dev)))
-   ieee80211_sta_find_ibss(dev, ifsta);
-   }
+
+   ieee80211_scan_completed(dev);
return;
}
skip = !(local-enabled_modes  (1  mode-mode));
@@ -2549,6 +2559,13 @@ int ieee80211_sta_req_scan(struct net_de
 
printk(KERN_DEBUG %s: starting scan\n, dev-name);
 
+   if (local-hw-hw_scan) {
+   int rc = local-hw-hw_scan(dev, ssid, ssid_len);
+   if (!rc)
+   local-sta_scanning = 1;
+   return rc;
+   }
+
ieee80211_sta_save_oper_chan(dev);
 
local-sta_scanning = 1;
-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 2/2]d80211: add hardware scan callback

2006-08-31 Thread Hong Liu
On Thu, 2006-08-31 at 01:10, Jiri Benc wrote:
 On Fri, 25 Aug 2006 16:32:13 +0800, Hong Liu wrote:
  Add hardware scan callback to support cards like ipw3945 which
  implements the scan command in firmware.
 
 How ipw3945 performs scan? From the patch, it looks like it switches
 channels (and sends probe requests) in the firmware and delivers all
 received beacons and probe responses through the normal rx path to be
 handled in a software MAC layer. This is really weird behaviour and
 doesn't make sense to me. Why isn't channel switching left to the
 software MAC as well?
 
  +/* set station scan completed */
  +void ieee80211_set_scan_completed(struct net_device *dev);
 
 Why set? ieee80211_scan_completed sounds better.
 
 Thanks,
 
  Jiri
 
 --
 Jiri Benc
 SUSE Labs
 


Signed-off-by: Hong Liu [EMAIL PROTECTED]

diff --git a/include/net/d80211.h b/include/net/d80211.h
index 42fdbf7..1caa8a9 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -600,6 +600,10 @@ struct ieee80211_hw {
 int (*passive_scan)(struct net_device *dev, int state,
 struct ieee80211_scan_conf *conf);
 
+   /* Ask the hardware to service the scan request, no need to start
+* the scan state machine in stack. */
+   int (*hw_scan)(struct net_device *dev, u8 *ssid, size_t len);
+
 /* return low-level statistics */
int (*get_stats)(struct net_device *dev,
 struct ieee80211_low_level_stats *stats);
@@ -906,6 +910,8 @@ void ieee80211_tx_led(int state, struct 
  */
 void ieee80211_rx_led(int state, struct net_device *dev);
 
+/* called by driver to notify scan status completed */
+void ieee80211_scan_completed(struct net_device *dev);
 
 /* IEEE 802.11 defines */
 
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 557ba17..8541a52 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -2410,6 +2410,29 @@ static int ieee80211_active_scan(struct 
 }
 
 
+void ieee80211_scan_completed(struct net_device *dev)
+{
+   struct ieee80211_local *local = dev-ieee80211_ptr;
+   struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+   union iwreq_data wrqu;
+
+   printk(KERN_DEBUG %s: scan completed\n, dev-name);
+   local-sta_scanning = 0;
+   local-last_scan_completed = jiffies;
+
+   memset(wrqu, 0, sizeof(wrqu));
+   wireless_send_event(dev, SIOCGIWSCAN, wrqu, NULL);
+
+   if (sdata-type == IEEE80211_IF_TYPE_IBSS) {
+   struct ieee80211_if_sta *ifsta = sdata-u.sta;
+   if (!ifsta-bssid_set ||
+   (!ifsta-state == IEEE80211_IBSS_JOINED 
+   !ieee80211_sta_active_ibss(dev)))
+   ieee80211_sta_find_ibss(dev, ifsta);
+   }
+}
+EXPORT_SYMBOL(ieee80211_scan_completed);
+
 static void ieee80211_sta_scan_work(void *ptr)
 {
struct net_device *dev = ptr;
@@ -2418,7 +2441,6 @@ static void ieee80211_sta_scan_work(void
struct ieee80211_hw_modes *mode;
struct ieee80211_channel *chan;
int skip;
-   union iwreq_data wrqu;
unsigned long next_delay = 0;
 
if (!local-sta_scanning)
@@ -2435,20 +2457,8 @@ static void ieee80211_sta_scan_work(void
   operational channel after scan\n,
   dev-name);
}
-   printk(KERN_DEBUG %s: scan completed\n, dev-name);
-   local-sta_scanning = 0;
-   local-last_scan_completed = jiffies;
-   memset(wrqu, 0, sizeof(wrqu));
-   wireless_send_event(dev, SIOCGIWSCAN, wrqu, NULL);
-   if (sdata-type == IEEE80211_IF_TYPE_IBSS) {
-   struct ieee80211_sub_if_data *sdata =
-   IEEE80211_DEV_TO_SUB_IF(dev);
-   struct ieee80211_if_sta *ifsta = sdata-u.sta;
-   if (!ifsta-bssid_set ||
-   (ifsta-state == IEEE80211_IBSS_JOINED 
-!ieee80211_sta_active_ibss(dev)))
-   ieee80211_sta_find_ibss(dev, ifsta);
-   }
+
+   ieee80211_scan_completed(dev);
return;
}
skip = !(local-enabled_modes  (1  mode-mode));
@@ -2549,9 +2559,12 @@ int ieee80211_sta_req_scan(struct net_de
 
printk(KERN_DEBUG %s: starting scan\n, dev-name);
 
+   local-sta_scanning = 1;
+   if (local-hw-hw_scan)
+   return local-hw-hw_scan(dev, ssid, ssid_len);
+
ieee80211_sta_save_oper_chan(dev);
 
-   local-sta_scanning = 1;
/* TODO: stop TX queue? */
 
if (ssid) {
-
To unsubscribe from this list: send the line unsubscribe

Re: [PATCH 1/2]d80211: fix wpa_supplicant reassoc problem

2006-08-31 Thread Hong Liu
On Thu, 2006-08-31 at 00:57, Jiri Benc wrote:
 On Fri, 25 Aug 2006 16:32:08 +0800, Hong Liu wrote:
  After key negotiation completed using wpa_supplicant, wpa_supplicant
  can't reassoc with the AP if we reboot the AP. It always fails at the
  4-way handshake.
  The problem is the key info is not cleared correctly. Thus when
  wpa_supplicant send the EAPOL-KEY packet, the d80211 stack finds the old
  key and uses it to encrypt the packet.
 
  The patch removes the sta_info when we disassociate with AP.
 
 Please:
 - add proper Signed-off-by line
 - do not send patches as an attachment
 - Cc: John Linville [EMAIL PROTECTED] as well as me on d80211
   patches
 
  diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
  index 8caf352..2144b34 100644
  --- a/net/d80211/ieee80211_sta.c
  +++ b/net/d80211/ieee80211_sta.c
  @@ -739,6 +739,14 @@ static void ieee80211_associated(struct
wireless_send_event(dev, SIOCGIWAP, wrqu, NULL);
mod_timer(ifsta-timer,
  jiffies + IEEE80211_MONITORING_INTERVAL + 30 * HZ);
  +
  + sta = sta_info_get(local, ifsta-bssid);
  + if (sta) {
  + sta_info_free(sta, 0);
  + sta_info_put(sta);
  + }
  +
  + ifsta-probereq_poll = 0;
 
 Wouldn't it be better to move this into the 'else' branch of previous
 'if' statement (i.e. just before sta_info_put call in the
 ieee80211_associated function)?
 

Rework the patch according to Jiri's comments.

Signed-off-by: Hong Liu [EMAIL PROTECTED]

diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index a933d92..557ba17 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -710,6 +710,8 @@ static void ieee80211_associated(struct 
   range\n,
   dev-name, MAC_ARG(ifsta-bssid));
disassoc = 1;
+   sta_info_free(sta, 0);
+   ifsta-probereq_poll = 0;
} else {
ieee80211_send_probe_req(dev, ifsta-bssid,
 local-scan_ssid,
diff --git a/net/d80211/sta_info.c b/net/d80211/sta_info.c
index 622b234..5edbd0c 100644
--- a/net/d80211/sta_info.c
+++ b/net/d80211/sta_info.c
@@ -197,6 +197,12 @@ #ifdef CONFIG_D80211_VERBOSE_DEBUG
   local-mdev-name, MAC_ARG(sta-addr));
 #endif /* CONFIG_D80211_VERBOSE_DEBUG */
 
+   if (sta-key) {
+   ieee80211_key_sysfs_remove(sta-key);
+   ieee80211_key_free(sta-key);
+   sta-key = NULL;
+   }
+
rate_control_remove_sta_attrs(local, sta-rate_ctrl_priv, sta-kobj);
ieee80211_sta_sysfs_remove(sta);
 
@@ -244,8 +250,6 @@ void sta_info_free(struct sta_info *sta,
kfree(key);
}
}
-   ieee80211_key_free(sta-key);
-   sta-key = NULL;
} else if (sta-key_idx_compression != HW_KEY_IDX_INVALID) {
struct ieee80211_key_conf conf;
memset(conf, 0, sizeof(conf));
-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH]d80211: fix iwconfig key [x] behavior

2006-08-28 Thread Hong Liu
iwconfig key [x] behavior is not correctly handled in the stack, also
modify the giwencode method to show the key info.

Thanks,
Hong
[PATCH]d80211: fix iwconfig key [x] behavior

Signed-off-by: Hong Liu [EMAIL PROTECTED]

diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index dd52555..d3dc59c 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -2811,9 +2811,10 @@ static int ieee80211_ioctl_siwencode(str
 		if (sdata-default_key == NULL)
 			idx = 0;
 		else for (i = 0; i  NUM_DEFAULT_KEYS; i++) {
-			if (sdata-default_key == sdata-keys[i])
+			if (sdata-default_key == sdata-keys[i]) {
 idx = i;
-			break;
+break;
+			}
 		}
 		if (idx  0)
 			return -EINVAL;
@@ -2824,16 +2825,22 @@ static int ieee80211_ioctl_siwencode(str
 		alg = ALG_NONE;
 	else if (erq-length == 0) {
 		/* No key data - just set the default TX key index */
-		sdata-default_key = sdata-keys[idx];
+		if (sdata-default_key != sdata-keys[idx]) {
+			if (sdata-default_key)
+ieee80211_key_sysfs_remove_default(sdata);
+			sdata-default_key = sdata-keys[idx];
+			if (sdata-default_key)
+ieee80211_key_sysfs_add_default(sdata);
+		}
+		return 0;
 	}
 
 	return ieee80211_set_encryption(
 		dev, bcaddr,
-		idx, erq-length == 0 ? ALG_NONE : ALG_WEP,
+		idx, alg,
 		sdata-default_key == NULL,
 		NULL, keybuf, erq-length);
 
-	return 0;
 }
 
 
@@ -2852,9 +2859,10 @@ static int ieee80211_ioctl_giwencode(str
 		if (sdata-default_key == NULL)
 			idx = 0;
 		else for (i = 0; i  NUM_DEFAULT_KEYS; i++) {
-			if (sdata-default_key == sdata-keys[i])
+			if (sdata-default_key == sdata-keys[i]) {
 idx = i;
-			break;
+break;
+			}
 		}
 		if (idx  0)
 			return -EINVAL;
@@ -2869,7 +2877,8 @@ static int ieee80211_ioctl_giwencode(str
 		return 0;
 	}
 
-	erq-length = 0;
+	erq-length = sdata-keys[idx]-keylen;
+	memcpy(key, sdata-keys[idx]-key, erq-length);
 	erq-flags |= IW_ENCODE_ENABLED;
 
 	return 0;


[PATCH 1/2]d80211: fix wpa_supplicant reassoc problem

2006-08-25 Thread Hong Liu
After key negotiation completed using wpa_supplicant, wpa_supplicant
can't reassoc with the AP if we reboot the AP. It always fails at the
4-way handshake.
The problem is the key info is not cleared correctly. Thus when
wpa_supplicant send the EAPOL-KEY packet, the d80211 stack finds the old
key and uses it to encrypt the packet.

The patch removes the sta_info when we disassociate with AP.

Thanks,
Hong
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 8caf352..2144b34 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -739,6 +739,14 @@ static void ieee80211_associated(struct 
 		wireless_send_event(dev, SIOCGIWAP, wrqu, NULL);
 		mod_timer(ifsta-timer,
 			  jiffies + IEEE80211_MONITORING_INTERVAL + 30 * HZ);
+
+		sta = sta_info_get(local, ifsta-bssid);
+		if (sta) {
+			sta_info_free(sta, 0);
+			sta_info_put(sta);
+		}
+
+		ifsta-probereq_poll = 0;
 	} else {
 		mod_timer(ifsta-timer,
 			  jiffies + IEEE80211_MONITORING_INTERVAL);
diff --git a/net/d80211/sta_info.c b/net/d80211/sta_info.c
index 7f5febe..8902816 100644
--- a/net/d80211/sta_info.c
+++ b/net/d80211/sta_info.c
@@ -197,6 +197,12 @@ #ifdef CONFIG_D80211_VERBOSE_DEBUG
 	   local-mdev-name, MAC_ARG(sta-addr));
 #endif /* CONFIG_D80211_VERBOSE_DEBUG */
 
+	if (sta-key) {
+		ieee80211_key_sysfs_remove(sta-key);
+		ieee80211_key_free(sta-key);
+		sta-key = NULL;
+	}
+
 	rate_control_remove_sta_attrs(local, sta-rate_ctrl_priv, sta-kobj);
 	ieee80211_sta_sysfs_remove(sta);
 
@@ -244,8 +250,6 @@ void sta_info_free(struct sta_info *sta,
 kfree(key);
 			}
 		}
-		ieee80211_key_free(sta-key);
-		sta-key = NULL;
 	} else if (sta-key_idx_compression != HW_KEY_IDX_INVALID) {
 		struct ieee80211_key_conf conf;
 		memset(conf, 0, sizeof(conf));


[PATCH 2/2]d80211: add hardware scan callback

2006-08-25 Thread Hong Liu
Add hardware scan callback to support cards like ipw3945 which
implements the scan command in firmware.

Thanks,
Hong
diff --git a/include/net/d80211.h b/include/net/d80211.h
index ba5cb4c..b369d12 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -595,6 +595,10 @@ struct ieee80211_hw {
 int (*passive_scan)(struct net_device *dev, int state,
 struct ieee80211_scan_conf *conf);
 
+	/* Ask the hardware to service the scan request, no need to start
+	 * the scan state machine in stack. */
+	int (*hw_scan)(struct net_device *dev, u8 *ssid, size_t len);
+
 /* return low-level statistics */
 	int (*get_stats)(struct net_device *dev,
 			 struct ieee80211_low_level_stats *stats);
@@ -893,6 +897,8 @@ void ieee80211_tx_led(int state, struct 
  */
 void ieee80211_rx_led(int state, struct net_device *dev);
 
+/* set station scan completed */
+void ieee80211_set_scan_completed(struct net_device *dev);
 
 /* IEEE 802.11 defines */
 
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 60eca90..dc920c1 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4831,6 +4831,7 @@ EXPORT_SYMBOL(sta_info_get);
 EXPORT_SYMBOL(sta_info_put);
 EXPORT_SYMBOL(ieee80211_radar_status);
 EXPORT_SYMBOL(ieee80211_get_mc_list_item);
+EXPORT_SYMBOL(ieee80211_set_scan_completed);
 
 module_init(ieee80211_init);
 module_exit(ieee80211_exit);
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 2144b34..4bb2234 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -2426,6 +2426,28 @@ static int ieee80211_active_scan(struct 
 }
 
 
+void ieee80211_set_scan_completed(struct net_device *dev)
+{
+	struct ieee80211_local *local = dev-ieee80211_ptr;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	union iwreq_data wrqu;
+
+	printk(KERN_DEBUG %s: scan completed\n, dev-name);
+	local-sta_scanning = 0;
+	local-last_scan_completed = jiffies;
+
+	memset(wrqu, 0, sizeof(wrqu));
+	wireless_send_event(dev, SIOCGIWSCAN, wrqu, NULL);
+
+	if (sdata-type == IEEE80211_IF_TYPE_IBSS) {
+		struct ieee80211_if_sta *ifsta = sdata-u.sta;
+		if (!ifsta-bssid_set ||
+		(!ifsta-state == IEEE80211_IBSS_JOINED 
+		!ieee80211_sta_active_ibss(dev)))
+			ieee80211_sta_find_ibss(dev, ifsta);
+	}
+}
+
 static void ieee80211_sta_scan_work(void *ptr)
 {
 	struct net_device *dev = ptr;
@@ -2434,7 +2456,6 @@ static void ieee80211_sta_scan_work(void
 	struct ieee80211_hw_modes *mode;
 	struct ieee80211_channel *chan;
 	int skip;
-	union iwreq_data wrqu;
 	unsigned long next_delay = 0;
 
 	if (!local-sta_scanning)
@@ -2451,20 +2472,8 @@ static void ieee80211_sta_scan_work(void
    operational channel after scan\n,
    dev-name);
 			}
-			printk(KERN_DEBUG %s: scan completed\n, dev-name);
-			local-sta_scanning = 0;
-			local-last_scan_completed = jiffies;
-			memset(wrqu, 0, sizeof(wrqu));
-			wireless_send_event(dev, SIOCGIWSCAN, wrqu, NULL);
-			if (sdata-type == IEEE80211_IF_TYPE_IBSS) {
-struct ieee80211_sub_if_data *sdata =
-	IEEE80211_DEV_TO_SUB_IF(dev);
-struct ieee80211_if_sta *ifsta = sdata-u.sta;
-if (!ifsta-bssid_set ||
-(ifsta-state == IEEE80211_IBSS_JOINED 
- !ieee80211_sta_active_ibss(dev)))
-	ieee80211_sta_find_ibss(dev, ifsta);
-			}
+
+			ieee80211_set_scan_completed(dev);
 			return;
 		}
 		skip = !(local-enabled_modes  (1  mode-mode));
@@ -2565,9 +2574,12 @@ int ieee80211_sta_req_scan(struct net_de
 
 	printk(KERN_DEBUG %s: starting scan\n, dev-name);
 
+	local-sta_scanning = 1;
+	if (local-hw-hw_scan)
+		return local-hw-hw_scan(dev, ssid, ssid_len);
+
 	ieee80211_sta_save_oper_chan(dev);
 
-	local-sta_scanning = 1;
 	/* TODO: stop TX queue? */
 
 	if (ssid) {


Re: [patch] ieee80211: fix not allocating IV+ICV space when usingencryption in ieee80211_tx_frame

2006-06-20 Thread Hong Liu
On Tue, 2006-06-20 at 10:26, Hong Liu wrote:
 We should preallocate IV+ICV space when encrypting the frame.
 Currently no problem shows up just because dev_alloc_skb aligns the
 data len to SMP_CACHE_BYTES which can be used for ICV.
 
 Thanks,
 Hong
 

Please apply this new patch.
The previous patch has a problem when security is not set.

diff -urp a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
--- a/net/ieee80211/ieee80211_tx.c	2006-06-20 09:36:13.0 +0800
+++ b/net/ieee80211/ieee80211_tx.c	2006-06-21 11:22:56.0 +0800
@@ -562,10 +562,13 @@ int ieee80211_tx_frame(struct ieee80211_
 	struct net_device_stats *stats = ieee-stats;
 	struct sk_buff *skb_frag;
 	int priority = -1;
+	int fraglen = total_len;
+	int headroom = ieee-tx_headroom;
+	struct ieee80211_crypt_data *crypt = ieee-crypt[ieee-tx_keyidx];
 
 	spin_lock_irqsave(ieee-lock, flags);
 
-	if (encrypt_mpdu  !ieee-sec.encrypt)
+	if (encrypt_mpdu  (!ieee-sec.encrypt || !crypt))
 		encrypt_mpdu = 0;
 
 	/* If there is no driver handler to take the TXB, dont' bother
@@ -581,20 +584,24 @@ int ieee80211_tx_frame(struct ieee80211_
 		goto success;
 	}
 
-	if (encrypt_mpdu)
+	if (encrypt_mpdu) {
 		frame-frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+		fraglen += crypt-ops-extra_mpdu_prefix_len +
+			   crypt-ops-extra_mpdu_postfix_len;
+		headroom += crypt-ops-extra_mpdu_prefix_len;
+	}
 
 	/* When we allocate the TXB we allocate enough space for the reserve
 	 * and full fragment bytes (bytes_per_frag doesn't include prefix,
 	 * postfix, header, FCS, etc.) */
-	txb = ieee80211_alloc_txb(1, total_len, ieee-tx_headroom, GFP_ATOMIC);
+	txb = ieee80211_alloc_txb(1, fraglen, headroom, GFP_ATOMIC);
 	if (unlikely(!txb)) {
 		printk(KERN_WARNING %s: Could not allocate TXB\n,
 		   ieee-dev-name);
 		goto failed;
 	}
 	txb-encrypted = 0;
-	txb-payload_size = total_len;
+	txb-payload_size = fraglen;
 
 	skb_frag = txb-fragments[0];
 


[patch] ieee80211: fix not allocating IV+ICV space when using encryption in ieee80211_tx_frame

2006-06-19 Thread Hong Liu
We should preallocate IV+ICV space when encrypting the frame.
Currently no problem shows up just because dev_alloc_skb aligns the
data len to SMP_CACHE_BYTES which can be used for ICV.

Thanks,
Hong
diff -urp a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
--- a/net/ieee80211/ieee80211_tx.c	2006-06-20 09:36:13.0 +0800
+++ b/net/ieee80211/ieee80211_tx.c	2006-06-20 09:32:39.0 +0800
@@ -562,10 +562,12 @@ int ieee80211_tx_frame(struct ieee80211_
 	struct net_device_stats *stats = ieee-stats;
 	struct sk_buff *skb_frag;
 	int priority = -1;
+	int fraglen = total_len;
+	struct ieee80211_crypt_data *crypt = ieee-crypt[ieee-tx_keyidx];
 
 	spin_lock_irqsave(ieee-lock, flags);
 
-	if (encrypt_mpdu  !ieee-sec.encrypt)
+	if (encrypt_mpdu  (!ieee-sec.encrypt || !crypt))
 		encrypt_mpdu = 0;
 
 	/* If there is no driver handler to take the TXB, dont' bother
@@ -581,20 +583,25 @@ int ieee80211_tx_frame(struct ieee80211_
 		goto success;
 	}
 
-	if (encrypt_mpdu)
+	if (encrypt_mpdu) {
 		frame-frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+		/* mpdu_prefix_len will be add to the headroom */
+		fraglen += crypt-ops-extra_mpdu_postfix_len;
+	}
 
 	/* When we allocate the TXB we allocate enough space for the reserve
 	 * and full fragment bytes (bytes_per_frag doesn't include prefix,
 	 * postfix, header, FCS, etc.) */
-	txb = ieee80211_alloc_txb(1, total_len, ieee-tx_headroom, GFP_ATOMIC);
+	txb = ieee80211_alloc_txb(1, fraglen, ieee-tx_headroom +
+  crypt-ops-extra_mpdu_prefix_len,
+  GFP_ATOMIC);
 	if (unlikely(!txb)) {
 		printk(KERN_WARNING %s: Could not allocate TXB\n,
 		   ieee-dev-name);
 		goto failed;
 	}
 	txb-encrypted = 0;
-	txb-payload_size = total_len;
+	txb-payload_size = fraglen;
 
 	skb_frag = txb-fragments[0];