diff options
Diffstat (limited to 'net/ieee80211/ieee80211_tx.c')
-rw-r--r-- | net/ieee80211/ieee80211_tx.c | 88 |
1 files changed, 70 insertions, 18 deletions
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 8b4332f53394..6a5de1b84459 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c | |||
@@ -220,13 +220,43 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, | |||
220 | return txb; | 220 | return txb; |
221 | } | 221 | } |
222 | 222 | ||
223 | static int ieee80211_classify(struct sk_buff *skb) | ||
224 | { | ||
225 | struct ethhdr *eth; | ||
226 | struct iphdr *ip; | ||
227 | |||
228 | eth = (struct ethhdr *)skb->data; | ||
229 | if (eth->h_proto != __constant_htons(ETH_P_IP)) | ||
230 | return 0; | ||
231 | |||
232 | ip = skb->nh.iph; | ||
233 | switch (ip->tos & 0xfc) { | ||
234 | case 0x20: | ||
235 | return 2; | ||
236 | case 0x40: | ||
237 | return 1; | ||
238 | case 0x60: | ||
239 | return 3; | ||
240 | case 0x80: | ||
241 | return 4; | ||
242 | case 0xa0: | ||
243 | return 5; | ||
244 | case 0xc0: | ||
245 | return 6; | ||
246 | case 0xe0: | ||
247 | return 7; | ||
248 | default: | ||
249 | return 0; | ||
250 | } | ||
251 | } | ||
252 | |||
223 | /* Incoming skb is converted to a txb which consists of | 253 | /* Incoming skb is converted to a txb which consists of |
224 | * a block of 802.11 fragment packets (stored as skbs) */ | 254 | * a block of 802.11 fragment packets (stored as skbs) */ |
225 | int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | 255 | int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) |
226 | { | 256 | { |
227 | struct ieee80211_device *ieee = netdev_priv(dev); | 257 | struct ieee80211_device *ieee = netdev_priv(dev); |
228 | struct ieee80211_txb *txb = NULL; | 258 | struct ieee80211_txb *txb = NULL; |
229 | struct ieee80211_hdr_3addr *frag_hdr; | 259 | struct ieee80211_hdr_3addrqos *frag_hdr; |
230 | int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size, | 260 | int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size, |
231 | rts_required; | 261 | rts_required; |
232 | unsigned long flags; | 262 | unsigned long flags; |
@@ -234,9 +264,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
234 | int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv; | 264 | int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv; |
235 | int bytes, fc, hdr_len; | 265 | int bytes, fc, hdr_len; |
236 | struct sk_buff *skb_frag; | 266 | struct sk_buff *skb_frag; |
237 | struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ | 267 | struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */ |
238 | .duration_id = 0, | 268 | .duration_id = 0, |
239 | .seq_ctl = 0 | 269 | .seq_ctl = 0, |
270 | .qos_ctl = 0 | ||
240 | }; | 271 | }; |
241 | u8 dest[ETH_ALEN], src[ETH_ALEN]; | 272 | u8 dest[ETH_ALEN], src[ETH_ALEN]; |
242 | struct ieee80211_crypt_data *crypt; | 273 | struct ieee80211_crypt_data *crypt; |
@@ -282,12 +313,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
282 | memcpy(dest, skb->data, ETH_ALEN); | 313 | memcpy(dest, skb->data, ETH_ALEN); |
283 | memcpy(src, skb->data + ETH_ALEN, ETH_ALEN); | 314 | memcpy(src, skb->data + ETH_ALEN, ETH_ALEN); |
284 | 315 | ||
285 | /* Advance the SKB to the start of the payload */ | ||
286 | skb_pull(skb, sizeof(struct ethhdr)); | ||
287 | |||
288 | /* Determine total amount of storage required for TXB packets */ | ||
289 | bytes = skb->len + SNAP_SIZE + sizeof(u16); | ||
290 | |||
291 | if (host_encrypt || host_build_iv) | 316 | if (host_encrypt || host_build_iv) |
292 | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | | 317 | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | |
293 | IEEE80211_FCTL_PROTECTED; | 318 | IEEE80211_FCTL_PROTECTED; |
@@ -306,9 +331,23 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
306 | memcpy(header.addr2, src, ETH_ALEN); | 331 | memcpy(header.addr2, src, ETH_ALEN); |
307 | memcpy(header.addr3, ieee->bssid, ETH_ALEN); | 332 | memcpy(header.addr3, ieee->bssid, ETH_ALEN); |
308 | } | 333 | } |
309 | header.frame_ctl = cpu_to_le16(fc); | ||
310 | hdr_len = IEEE80211_3ADDR_LEN; | 334 | hdr_len = IEEE80211_3ADDR_LEN; |
311 | 335 | ||
336 | if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) { | ||
337 | fc |= IEEE80211_STYPE_QOS_DATA; | ||
338 | hdr_len += 2; | ||
339 | |||
340 | skb->priority = ieee80211_classify(skb); | ||
341 | header.qos_ctl |= skb->priority & IEEE80211_QCTL_TID; | ||
342 | } | ||
343 | header.frame_ctl = cpu_to_le16(fc); | ||
344 | |||
345 | /* Advance the SKB to the start of the payload */ | ||
346 | skb_pull(skb, sizeof(struct ethhdr)); | ||
347 | |||
348 | /* Determine total amount of storage required for TXB packets */ | ||
349 | bytes = skb->len + SNAP_SIZE + sizeof(u16); | ||
350 | |||
312 | /* Encrypt msdu first on the whole data packet. */ | 351 | /* Encrypt msdu first on the whole data packet. */ |
313 | if ((host_encrypt || host_encrypt_msdu) && | 352 | if ((host_encrypt || host_encrypt_msdu) && |
314 | crypt && crypt->ops && crypt->ops->encrypt_msdu) { | 353 | crypt && crypt->ops && crypt->ops->encrypt_msdu) { |
@@ -402,7 +441,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
402 | if (rts_required) { | 441 | if (rts_required) { |
403 | skb_frag = txb->fragments[0]; | 442 | skb_frag = txb->fragments[0]; |
404 | frag_hdr = | 443 | frag_hdr = |
405 | (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); | 444 | (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); |
406 | 445 | ||
407 | /* | 446 | /* |
408 | * Set header frame_ctl to the RTS. | 447 | * Set header frame_ctl to the RTS. |
@@ -433,7 +472,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
433 | crypt->ops->extra_mpdu_prefix_len); | 472 | crypt->ops->extra_mpdu_prefix_len); |
434 | 473 | ||
435 | frag_hdr = | 474 | frag_hdr = |
436 | (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); | 475 | (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); |
437 | memcpy(frag_hdr, &header, hdr_len); | 476 | memcpy(frag_hdr, &header, hdr_len); |
438 | 477 | ||
439 | /* If this is not the last fragment, then add the MOREFRAGS | 478 | /* If this is not the last fragment, then add the MOREFRAGS |
@@ -516,7 +555,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
516 | /* Incoming 802.11 strucure is converted to a TXB | 555 | /* Incoming 802.11 strucure is converted to a TXB |
517 | * a block of 802.11 fragment packets (stored as skbs) */ | 556 | * a block of 802.11 fragment packets (stored as skbs) */ |
518 | int ieee80211_tx_frame(struct ieee80211_device *ieee, | 557 | int ieee80211_tx_frame(struct ieee80211_device *ieee, |
519 | struct ieee80211_hdr *frame, int len) | 558 | struct ieee80211_hdr *frame, int hdr_len, int total_len, |
559 | int encrypt_mpdu) | ||
520 | { | 560 | { |
521 | struct ieee80211_txb *txb = NULL; | 561 | struct ieee80211_txb *txb = NULL; |
522 | unsigned long flags; | 562 | unsigned long flags; |
@@ -526,6 +566,9 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee, | |||
526 | 566 | ||
527 | spin_lock_irqsave(&ieee->lock, flags); | 567 | spin_lock_irqsave(&ieee->lock, flags); |
528 | 568 | ||
569 | if (encrypt_mpdu && !ieee->sec.encrypt) | ||
570 | encrypt_mpdu = 0; | ||
571 | |||
529 | /* If there is no driver handler to take the TXB, dont' bother | 572 | /* If there is no driver handler to take the TXB, dont' bother |
530 | * creating it... */ | 573 | * creating it... */ |
531 | if (!ieee->hard_start_xmit) { | 574 | if (!ieee->hard_start_xmit) { |
@@ -533,32 +576,41 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee, | |||
533 | goto success; | 576 | goto success; |
534 | } | 577 | } |
535 | 578 | ||
536 | if (unlikely(len < 24)) { | 579 | if (unlikely(total_len < 24)) { |
537 | printk(KERN_WARNING "%s: skb too small (%d).\n", | 580 | printk(KERN_WARNING "%s: skb too small (%d).\n", |
538 | ieee->dev->name, len); | 581 | ieee->dev->name, total_len); |
539 | goto success; | 582 | goto success; |
540 | } | 583 | } |
541 | 584 | ||
585 | if (encrypt_mpdu) | ||
586 | frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
587 | |||
542 | /* When we allocate the TXB we allocate enough space for the reserve | 588 | /* When we allocate the TXB we allocate enough space for the reserve |
543 | * and full fragment bytes (bytes_per_frag doesn't include prefix, | 589 | * and full fragment bytes (bytes_per_frag doesn't include prefix, |
544 | * postfix, header, FCS, etc.) */ | 590 | * postfix, header, FCS, etc.) */ |
545 | txb = ieee80211_alloc_txb(1, len, ieee->tx_headroom, GFP_ATOMIC); | 591 | txb = ieee80211_alloc_txb(1, total_len, ieee->tx_headroom, GFP_ATOMIC); |
546 | if (unlikely(!txb)) { | 592 | if (unlikely(!txb)) { |
547 | printk(KERN_WARNING "%s: Could not allocate TXB\n", | 593 | printk(KERN_WARNING "%s: Could not allocate TXB\n", |
548 | ieee->dev->name); | 594 | ieee->dev->name); |
549 | goto failed; | 595 | goto failed; |
550 | } | 596 | } |
551 | txb->encrypted = 0; | 597 | txb->encrypted = 0; |
552 | txb->payload_size = len; | 598 | txb->payload_size = total_len; |
553 | 599 | ||
554 | skb_frag = txb->fragments[0]; | 600 | skb_frag = txb->fragments[0]; |
555 | 601 | ||
556 | memcpy(skb_put(skb_frag, len), frame, len); | 602 | memcpy(skb_put(skb_frag, total_len), frame, total_len); |
557 | 603 | ||
558 | if (ieee->config & | 604 | if (ieee->config & |
559 | (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) | 605 | (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) |
560 | skb_put(skb_frag, 4); | 606 | skb_put(skb_frag, 4); |
561 | 607 | ||
608 | /* To avoid overcomplicating things, we do the corner-case frame | ||
609 | * encryption in software. The only real situation where encryption is | ||
610 | * needed here is during software-based shared key authentication. */ | ||
611 | if (encrypt_mpdu) | ||
612 | ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); | ||
613 | |||
562 | success: | 614 | success: |
563 | spin_unlock_irqrestore(&ieee->lock, flags); | 615 | spin_unlock_irqrestore(&ieee->lock, flags); |
564 | 616 | ||