diff options
Diffstat (limited to 'net/ieee80211')
-rw-r--r-- | net/ieee80211/ieee80211_crypt.c | 4 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt_ccmp.c | 4 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt_tkip.c | 5 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt_wep.c | 4 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_module.c | 7 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_tx.c | 148 |
6 files changed, 98 insertions, 74 deletions
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c index 60d3166facce..e26bcc918032 100644 --- a/net/ieee80211/ieee80211_crypt.c +++ b/net/ieee80211/ieee80211_crypt.c | |||
@@ -221,8 +221,8 @@ static struct ieee80211_crypto_ops ieee80211_crypt_null = { | |||
221 | .decrypt_msdu = NULL, | 221 | .decrypt_msdu = NULL, |
222 | .set_key = NULL, | 222 | .set_key = NULL, |
223 | .get_key = NULL, | 223 | .get_key = NULL, |
224 | .extra_prefix_len = 0, | 224 | .extra_mpdu_prefix_len = 0, |
225 | .extra_postfix_len = 0, | 225 | .extra_mpdu_postfix_len = 0, |
226 | .owner = THIS_MODULE, | 226 | .owner = THIS_MODULE, |
227 | }; | 227 | }; |
228 | 228 | ||
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index d3b5cdee69ef..a3dc5712b98b 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c | |||
@@ -436,8 +436,8 @@ static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { | |||
436 | .set_key = ieee80211_ccmp_set_key, | 436 | .set_key = ieee80211_ccmp_set_key, |
437 | .get_key = ieee80211_ccmp_get_key, | 437 | .get_key = ieee80211_ccmp_get_key, |
438 | .print_stats = ieee80211_ccmp_print_stats, | 438 | .print_stats = ieee80211_ccmp_print_stats, |
439 | .extra_prefix_len = CCMP_HDR_LEN, | 439 | .extra_mpdu_prefix_len = CCMP_HDR_LEN, |
440 | .extra_postfix_len = CCMP_MIC_LEN, | 440 | .extra_mpdu_postfix_len = CCMP_MIC_LEN, |
441 | .owner = THIS_MODULE, | 441 | .owner = THIS_MODULE, |
442 | }; | 442 | }; |
443 | 443 | ||
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index f091aacd4297..f973d6cb8248 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c | |||
@@ -690,8 +690,9 @@ static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { | |||
690 | .set_key = ieee80211_tkip_set_key, | 690 | .set_key = ieee80211_tkip_set_key, |
691 | .get_key = ieee80211_tkip_get_key, | 691 | .get_key = ieee80211_tkip_get_key, |
692 | .print_stats = ieee80211_tkip_print_stats, | 692 | .print_stats = ieee80211_tkip_print_stats, |
693 | .extra_prefix_len = 4 + 4, /* IV + ExtIV */ | 693 | .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ |
694 | .extra_postfix_len = 8 + 4, /* MIC + ICV */ | 694 | .extra_mpdu_postfix_len = 4, /* ICV */ |
695 | .extra_msdu_postfix_len = 8, /* MIC */ | ||
695 | .owner = THIS_MODULE, | 696 | .owner = THIS_MODULE, |
696 | }; | 697 | }; |
697 | 698 | ||
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index 63e783fa5173..2aaeac1e02d7 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c | |||
@@ -239,8 +239,8 @@ static struct ieee80211_crypto_ops ieee80211_crypt_wep = { | |||
239 | .set_key = prism2_wep_set_key, | 239 | .set_key = prism2_wep_set_key, |
240 | .get_key = prism2_wep_get_key, | 240 | .get_key = prism2_wep_get_key, |
241 | .print_stats = prism2_wep_print_stats, | 241 | .print_stats = prism2_wep_print_stats, |
242 | .extra_prefix_len = 4, /* IV */ | 242 | .extra_mpdu_prefix_len = 4, /* IV */ |
243 | .extra_postfix_len = 4, /* ICV */ | 243 | .extra_mpdu_postfix_len = 4, /* ICV */ |
244 | .owner = THIS_MODULE, | 244 | .owner = THIS_MODULE, |
245 | }; | 245 | }; |
246 | 246 | ||
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 67d6bdd2e3f2..dddc61647390 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c | |||
@@ -133,6 +133,12 @@ struct net_device *alloc_ieee80211(int sizeof_priv) | |||
133 | /* Default to enabling full open WEP with host based encrypt/decrypt */ | 133 | /* Default to enabling full open WEP with host based encrypt/decrypt */ |
134 | ieee->host_encrypt = 1; | 134 | ieee->host_encrypt = 1; |
135 | ieee->host_decrypt = 1; | 135 | ieee->host_decrypt = 1; |
136 | /* Host fragementation in Open mode. Default is enabled. | ||
137 | * Note: host fragmentation is always enabled if host encryption | ||
138 | * is enabled. For cards can do hardware encryption, they must do | ||
139 | * hardware fragmentation as well. So we don't need a variable | ||
140 | * like host_enc_frag. */ | ||
141 | ieee->host_open_frag = 1; | ||
136 | ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ | 142 | ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ |
137 | 143 | ||
138 | INIT_LIST_HEAD(&ieee->crypt_deinit_list); | 144 | INIT_LIST_HEAD(&ieee->crypt_deinit_list); |
@@ -147,7 +153,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv) | |||
147 | ieee->tkip_countermeasures = 0; | 153 | ieee->tkip_countermeasures = 0; |
148 | ieee->drop_unencrypted = 0; | 154 | ieee->drop_unencrypted = 0; |
149 | ieee->privacy_invoked = 0; | 155 | ieee->privacy_invoked = 0; |
150 | ieee->ieee802_1x = 1; | ||
151 | 156 | ||
152 | return dev; | 157 | return dev; |
153 | 158 | ||
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index f505aa127e21..23a1f88de7cb 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c | |||
@@ -128,7 +128,7 @@ payload of each frame is reduced to 492 bytes. | |||
128 | static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; | 128 | static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; |
129 | static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; | 129 | static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; |
130 | 130 | ||
131 | static inline int ieee80211_put_snap(u8 * data, u16 h_proto) | 131 | static inline int ieee80211_copy_snap(u8 * data, u16 h_proto) |
132 | { | 132 | { |
133 | struct ieee80211_snap_hdr *snap; | 133 | struct ieee80211_snap_hdr *snap; |
134 | u8 *oui; | 134 | u8 *oui; |
@@ -159,15 +159,9 @@ static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, | |||
159 | 159 | ||
160 | /* To encrypt, frame format is: | 160 | /* To encrypt, frame format is: |
161 | * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ | 161 | * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ |
162 | |||
163 | // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption. | ||
164 | /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so | ||
165 | * call both MSDU and MPDU encryption functions from here. */ | ||
166 | atomic_inc(&crypt->refcnt); | 162 | atomic_inc(&crypt->refcnt); |
167 | res = 0; | 163 | res = 0; |
168 | if (crypt->ops->encrypt_msdu) | 164 | if (crypt->ops->encrypt_mpdu) |
169 | res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); | ||
170 | if (res == 0 && crypt->ops->encrypt_mpdu) | ||
171 | res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); | 165 | res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); |
172 | 166 | ||
173 | atomic_dec(&crypt->refcnt); | 167 | atomic_dec(&crypt->refcnt); |
@@ -222,7 +216,7 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, | |||
222 | return txb; | 216 | return txb; |
223 | } | 217 | } |
224 | 218 | ||
225 | /* Incoming skb is converted to a txb which consist of | 219 | /* Incoming skb is converted to a txb which consists of |
226 | * a block of 802.11 fragment packets (stored as skbs) */ | 220 | * a block of 802.11 fragment packets (stored as skbs) */ |
227 | int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | 221 | int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) |
228 | { | 222 | { |
@@ -233,7 +227,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
233 | rts_required; | 227 | rts_required; |
234 | unsigned long flags; | 228 | unsigned long flags; |
235 | struct net_device_stats *stats = &ieee->stats; | 229 | struct net_device_stats *stats = &ieee->stats; |
236 | int ether_type, encrypt, host_encrypt; | 230 | int ether_type, encrypt, host_encrypt, host_encrypt_msdu; |
237 | int bytes, fc, hdr_len; | 231 | int bytes, fc, hdr_len; |
238 | struct sk_buff *skb_frag; | 232 | struct sk_buff *skb_frag; |
239 | struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ | 233 | struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ |
@@ -241,8 +235,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
241 | .seq_ctl = 0 | 235 | .seq_ctl = 0 |
242 | }; | 236 | }; |
243 | u8 dest[ETH_ALEN], src[ETH_ALEN]; | 237 | u8 dest[ETH_ALEN], src[ETH_ALEN]; |
244 | |||
245 | struct ieee80211_crypt_data *crypt; | 238 | struct ieee80211_crypt_data *crypt; |
239 | int snapped = 0; | ||
246 | 240 | ||
247 | spin_lock_irqsave(&ieee->lock, flags); | 241 | spin_lock_irqsave(&ieee->lock, flags); |
248 | 242 | ||
@@ -266,6 +260,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
266 | encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && | 260 | encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && |
267 | ieee->sec.encrypt; | 261 | ieee->sec.encrypt; |
268 | host_encrypt = ieee->host_encrypt && encrypt; | 262 | host_encrypt = ieee->host_encrypt && encrypt; |
263 | host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt; | ||
269 | 264 | ||
270 | if (!encrypt && ieee->ieee802_1x && | 265 | if (!encrypt && ieee->ieee802_1x && |
271 | ieee->drop_unencrypted && ether_type != ETH_P_PAE) { | 266 | ieee->drop_unencrypted && ether_type != ETH_P_PAE) { |
@@ -291,14 +286,12 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
291 | 286 | ||
292 | if (ieee->iw_mode == IW_MODE_INFRA) { | 287 | if (ieee->iw_mode == IW_MODE_INFRA) { |
293 | fc |= IEEE80211_FCTL_TODS; | 288 | fc |= IEEE80211_FCTL_TODS; |
294 | /* To DS: Addr1 = BSSID, Addr2 = SA, | 289 | /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ |
295 | Addr3 = DA */ | ||
296 | memcpy(header.addr1, ieee->bssid, ETH_ALEN); | 290 | memcpy(header.addr1, ieee->bssid, ETH_ALEN); |
297 | memcpy(header.addr2, src, ETH_ALEN); | 291 | memcpy(header.addr2, src, ETH_ALEN); |
298 | memcpy(header.addr3, dest, ETH_ALEN); | 292 | memcpy(header.addr3, dest, ETH_ALEN); |
299 | } else if (ieee->iw_mode == IW_MODE_ADHOC) { | 293 | } else if (ieee->iw_mode == IW_MODE_ADHOC) { |
300 | /* not From/To DS: Addr1 = DA, Addr2 = SA, | 294 | /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ |
301 | Addr3 = BSSID */ | ||
302 | memcpy(header.addr1, dest, ETH_ALEN); | 295 | memcpy(header.addr1, dest, ETH_ALEN); |
303 | memcpy(header.addr2, src, ETH_ALEN); | 296 | memcpy(header.addr2, src, ETH_ALEN); |
304 | memcpy(header.addr3, ieee->bssid, ETH_ALEN); | 297 | memcpy(header.addr3, ieee->bssid, ETH_ALEN); |
@@ -306,42 +299,75 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
306 | header.frame_ctl = cpu_to_le16(fc); | 299 | header.frame_ctl = cpu_to_le16(fc); |
307 | hdr_len = IEEE80211_3ADDR_LEN; | 300 | hdr_len = IEEE80211_3ADDR_LEN; |
308 | 301 | ||
309 | /* Determine fragmentation size based on destination (multicast | 302 | /* Encrypt msdu first on the whole data packet. */ |
310 | * and broadcast are not fragmented) */ | 303 | if ((host_encrypt || host_encrypt_msdu) && |
311 | if (is_multicast_ether_addr(dest) || is_broadcast_ether_addr(dest)) | 304 | crypt && crypt->ops && crypt->ops->encrypt_msdu) { |
312 | frag_size = MAX_FRAG_THRESHOLD; | 305 | int res = 0; |
313 | else | 306 | int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len + |
314 | frag_size = ieee->fts; | 307 | crypt->ops->extra_msdu_postfix_len; |
308 | struct sk_buff *skb_new = dev_alloc_skb(len); | ||
309 | if (unlikely(!skb_new)) | ||
310 | goto failed; | ||
311 | skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len); | ||
312 | memcpy(skb_put(skb_new, hdr_len), &header, hdr_len); | ||
313 | snapped = 1; | ||
314 | ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)), | ||
315 | ether_type); | ||
316 | memcpy(skb_put(skb_new, skb->len), skb->data, skb->len); | ||
317 | res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv); | ||
318 | if (res < 0) { | ||
319 | IEEE80211_ERROR("msdu encryption failed\n"); | ||
320 | dev_kfree_skb_any(skb_new); | ||
321 | goto failed; | ||
322 | } | ||
323 | dev_kfree_skb_any(skb); | ||
324 | skb = skb_new; | ||
325 | bytes += crypt->ops->extra_msdu_prefix_len + | ||
326 | crypt->ops->extra_msdu_postfix_len; | ||
327 | skb_pull(skb, hdr_len); | ||
328 | } | ||
315 | 329 | ||
316 | /* Determine amount of payload per fragment. Regardless of if | 330 | if (host_encrypt || ieee->host_open_frag) { |
317 | * this stack is providing the full 802.11 header, one will | 331 | /* Determine fragmentation size based on destination (multicast |
318 | * eventually be affixed to this fragment -- so we must account for | 332 | * and broadcast are not fragmented) */ |
319 | * it when determining the amount of payload space. */ | 333 | if (is_multicast_ether_addr(dest)) |
320 | bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN; | 334 | frag_size = MAX_FRAG_THRESHOLD; |
321 | if (ieee->config & | 335 | else |
322 | (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) | 336 | frag_size = ieee->fts; |
323 | bytes_per_frag -= IEEE80211_FCS_LEN; | 337 | |
338 | /* Determine amount of payload per fragment. Regardless of if | ||
339 | * this stack is providing the full 802.11 header, one will | ||
340 | * eventually be affixed to this fragment -- so we must account | ||
341 | * for it when determining the amount of payload space. */ | ||
342 | bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN; | ||
343 | if (ieee->config & | ||
344 | (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) | ||
345 | bytes_per_frag -= IEEE80211_FCS_LEN; | ||
324 | 346 | ||
325 | /* Each fragment may need to have room for encryptiong pre/postfix */ | 347 | /* Each fragment may need to have room for encryptiong |
326 | if (host_encrypt) | 348 | * pre/postfix */ |
327 | bytes_per_frag -= crypt->ops->extra_prefix_len + | 349 | if (host_encrypt) |
328 | crypt->ops->extra_postfix_len; | 350 | bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len + |
329 | 351 | crypt->ops->extra_mpdu_postfix_len; | |
330 | /* Number of fragments is the total bytes_per_frag / | 352 | |
331 | * payload_per_fragment */ | 353 | /* Number of fragments is the total |
332 | nr_frags = bytes / bytes_per_frag; | 354 | * bytes_per_frag / payload_per_fragment */ |
333 | bytes_last_frag = bytes % bytes_per_frag; | 355 | nr_frags = bytes / bytes_per_frag; |
334 | if (bytes_last_frag) | 356 | bytes_last_frag = bytes % bytes_per_frag; |
335 | nr_frags++; | 357 | if (bytes_last_frag) |
336 | else | 358 | nr_frags++; |
337 | bytes_last_frag = bytes_per_frag; | 359 | else |
360 | bytes_last_frag = bytes_per_frag; | ||
361 | } else { | ||
362 | nr_frags = 1; | ||
363 | bytes_per_frag = bytes_last_frag = bytes; | ||
364 | frag_size = bytes + IEEE80211_3ADDR_LEN; | ||
365 | } | ||
338 | 366 | ||
339 | rts_required = (frag_size > ieee->rts | 367 | rts_required = (frag_size > ieee->rts |
340 | && ieee->config & CFG_IEEE80211_RTS); | 368 | && ieee->config & CFG_IEEE80211_RTS); |
341 | if (rts_required) | 369 | if (rts_required) |
342 | nr_frags++; | 370 | nr_frags++; |
343 | else | ||
344 | bytes_last_frag = bytes_per_frag; | ||
345 | 371 | ||
346 | /* When we allocate the TXB we allocate enough space for the reserve | 372 | /* When we allocate the TXB we allocate enough space for the reserve |
347 | * and full fragment bytes (bytes_per_frag doesn't include prefix, | 373 | * and full fragment bytes (bytes_per_frag doesn't include prefix, |
@@ -353,7 +379,11 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
353 | goto failed; | 379 | goto failed; |
354 | } | 380 | } |
355 | txb->encrypted = encrypt; | 381 | txb->encrypted = encrypt; |
356 | txb->payload_size = bytes; | 382 | if (host_encrypt) |
383 | txb->payload_size = frag_size * (nr_frags - 1) + | ||
384 | bytes_last_frag; | ||
385 | else | ||
386 | txb->payload_size = bytes; | ||
357 | 387 | ||
358 | if (rts_required) { | 388 | if (rts_required) { |
359 | skb_frag = txb->fragments[0]; | 389 | skb_frag = txb->fragments[0]; |
@@ -385,7 +415,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
385 | skb_frag = txb->fragments[i]; | 415 | skb_frag = txb->fragments[i]; |
386 | 416 | ||
387 | if (host_encrypt) | 417 | if (host_encrypt) |
388 | skb_reserve(skb_frag, crypt->ops->extra_prefix_len); | 418 | skb_reserve(skb_frag, |
419 | crypt->ops->extra_mpdu_prefix_len); | ||
389 | 420 | ||
390 | frag_hdr = | 421 | frag_hdr = |
391 | (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); | 422 | (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); |
@@ -402,11 +433,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
402 | bytes = bytes_last_frag; | 433 | bytes = bytes_last_frag; |
403 | } | 434 | } |
404 | 435 | ||
405 | /* Put a SNAP header on the first fragment */ | 436 | if (i == 0 && !snapped) { |
406 | if (i == 0) { | 437 | ieee80211_copy_snap(skb_put |
407 | ieee80211_put_snap(skb_put | 438 | (skb_frag, SNAP_SIZE + sizeof(u16)), |
408 | (skb_frag, SNAP_SIZE + sizeof(u16)), | 439 | ether_type); |
409 | ether_type); | ||
410 | bytes -= SNAP_SIZE + sizeof(u16); | 440 | bytes -= SNAP_SIZE + sizeof(u16); |
411 | } | 441 | } |
412 | 442 | ||
@@ -420,19 +450,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
420 | if (host_encrypt) | 450 | if (host_encrypt) |
421 | ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); | 451 | ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); |
422 | 452 | ||
423 | /* ipw2200/2915 Hardware encryption doesn't support TKIP MIC */ | ||
424 | if (!ieee->host_encrypt && encrypt && | ||
425 | (ieee->sec.level == SEC_LEVEL_2) && | ||
426 | crypt && crypt->ops && crypt->ops->encrypt_msdu) { | ||
427 | int res = 0; | ||
428 | res = crypt->ops->encrypt_msdu(skb_frag, hdr_len, | ||
429 | crypt->priv); | ||
430 | if (res < 0) { | ||
431 | IEEE80211_ERROR("TKIP MIC encryption failed\n"); | ||
432 | goto failed; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | if (ieee->config & | 453 | if (ieee->config & |
437 | (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) | 454 | (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) |
438 | skb_put(skb_frag, 4); | 455 | skb_put(skb_frag, 4); |
@@ -444,7 +461,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
444 | dev_kfree_skb_any(skb); | 461 | dev_kfree_skb_any(skb); |
445 | 462 | ||
446 | if (txb) { | 463 | if (txb) { |
447 | if ((*ieee->hard_start_xmit) (txb, dev) == 0) { | 464 | int ret = (*ieee->hard_start_xmit) (txb, dev); |
465 | if (ret == 0) { | ||
448 | stats->tx_packets++; | 466 | stats->tx_packets++; |
449 | stats->tx_bytes += txb->payload_size; | 467 | stats->tx_bytes += txb->payload_size; |
450 | return 0; | 468 | return 0; |