diff options
-rw-r--r-- | net/mac80211/tx.c | 234 |
1 files changed, 118 insertions, 116 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 99c3860bc0e2..666158f02a89 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -506,106 +506,6 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
506 | } | 506 | } |
507 | 507 | ||
508 | static ieee80211_tx_result | 508 | static ieee80211_tx_result |
509 | ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | ||
510 | { | ||
511 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; | ||
512 | size_t hdrlen, per_fragm, num_fragm, payload_len, left; | ||
513 | struct sk_buff **frags, *first, *frag; | ||
514 | int i; | ||
515 | u16 seq; | ||
516 | u8 *pos; | ||
517 | int frag_threshold = tx->local->fragmentation_threshold; | ||
518 | |||
519 | if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) | ||
520 | return TX_CONTINUE; | ||
521 | |||
522 | first = tx->skb; | ||
523 | |||
524 | hdrlen = ieee80211_get_hdrlen(tx->fc); | ||
525 | payload_len = first->len - hdrlen; | ||
526 | per_fragm = frag_threshold - hdrlen - FCS_LEN; | ||
527 | num_fragm = DIV_ROUND_UP(payload_len, per_fragm); | ||
528 | |||
529 | frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); | ||
530 | if (!frags) | ||
531 | goto fail; | ||
532 | |||
533 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); | ||
534 | seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; | ||
535 | pos = first->data + hdrlen + per_fragm; | ||
536 | left = payload_len - per_fragm; | ||
537 | for (i = 0; i < num_fragm - 1; i++) { | ||
538 | struct ieee80211_hdr *fhdr; | ||
539 | size_t copylen; | ||
540 | |||
541 | if (left <= 0) | ||
542 | goto fail; | ||
543 | |||
544 | /* reserve enough extra head and tail room for possible | ||
545 | * encryption */ | ||
546 | frag = frags[i] = | ||
547 | dev_alloc_skb(tx->local->tx_headroom + | ||
548 | frag_threshold + | ||
549 | IEEE80211_ENCRYPT_HEADROOM + | ||
550 | IEEE80211_ENCRYPT_TAILROOM); | ||
551 | if (!frag) | ||
552 | goto fail; | ||
553 | /* Make sure that all fragments use the same priority so | ||
554 | * that they end up using the same TX queue */ | ||
555 | frag->priority = first->priority; | ||
556 | skb_reserve(frag, tx->local->tx_headroom + | ||
557 | IEEE80211_ENCRYPT_HEADROOM); | ||
558 | fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); | ||
559 | memcpy(fhdr, first->data, hdrlen); | ||
560 | if (i == num_fragm - 2) | ||
561 | fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); | ||
562 | fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); | ||
563 | copylen = left > per_fragm ? per_fragm : left; | ||
564 | memcpy(skb_put(frag, copylen), pos, copylen); | ||
565 | |||
566 | pos += copylen; | ||
567 | left -= copylen; | ||
568 | } | ||
569 | skb_trim(first, hdrlen + per_fragm); | ||
570 | |||
571 | tx->num_extra_frag = num_fragm - 1; | ||
572 | tx->extra_frag = frags; | ||
573 | |||
574 | return TX_CONTINUE; | ||
575 | |||
576 | fail: | ||
577 | printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); | ||
578 | if (frags) { | ||
579 | for (i = 0; i < num_fragm - 1; i++) | ||
580 | if (frags[i]) | ||
581 | dev_kfree_skb(frags[i]); | ||
582 | kfree(frags); | ||
583 | } | ||
584 | I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); | ||
585 | return TX_DROP; | ||
586 | } | ||
587 | |||
588 | static ieee80211_tx_result | ||
589 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | ||
590 | { | ||
591 | if (!tx->key) | ||
592 | return TX_CONTINUE; | ||
593 | |||
594 | switch (tx->key->conf.alg) { | ||
595 | case ALG_WEP: | ||
596 | return ieee80211_crypto_wep_encrypt(tx); | ||
597 | case ALG_TKIP: | ||
598 | return ieee80211_crypto_tkip_encrypt(tx); | ||
599 | case ALG_CCMP: | ||
600 | return ieee80211_crypto_ccmp_encrypt(tx); | ||
601 | } | ||
602 | |||
603 | /* not reached */ | ||
604 | WARN_ON(1); | ||
605 | return TX_DROP; | ||
606 | } | ||
607 | |||
608 | static ieee80211_tx_result | ||
609 | ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | 509 | ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) |
610 | { | 510 | { |
611 | struct rate_selection rsel; | 511 | struct rate_selection rsel; |
@@ -747,26 +647,114 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) | |||
747 | control->rts_cts_rate_idx = 0; | 647 | control->rts_cts_rate_idx = 0; |
748 | } | 648 | } |
749 | 649 | ||
750 | if (tx->sta) { | 650 | if (tx->sta) |
751 | control->aid = tx->sta->aid; | 651 | control->aid = tx->sta->aid; |
752 | tx->sta->tx_packets++; | 652 | |
753 | tx->sta->tx_fragments++; | 653 | return TX_CONTINUE; |
754 | tx->sta->tx_bytes += tx->skb->len; | 654 | } |
755 | if (tx->extra_frag) { | 655 | |
756 | int i; | 656 | static ieee80211_tx_result |
757 | tx->sta->tx_fragments += tx->num_extra_frag; | 657 | ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) |
758 | for (i = 0; i < tx->num_extra_frag; i++) { | 658 | { |
759 | tx->sta->tx_bytes += | 659 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; |
760 | tx->extra_frag[i]->len; | 660 | size_t hdrlen, per_fragm, num_fragm, payload_len, left; |
761 | } | 661 | struct sk_buff **frags, *first, *frag; |
762 | } | 662 | int i; |
663 | u16 seq; | ||
664 | u8 *pos; | ||
665 | int frag_threshold = tx->local->fragmentation_threshold; | ||
666 | |||
667 | if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) | ||
668 | return TX_CONTINUE; | ||
669 | |||
670 | first = tx->skb; | ||
671 | |||
672 | hdrlen = ieee80211_get_hdrlen(tx->fc); | ||
673 | payload_len = first->len - hdrlen; | ||
674 | per_fragm = frag_threshold - hdrlen - FCS_LEN; | ||
675 | num_fragm = DIV_ROUND_UP(payload_len, per_fragm); | ||
676 | |||
677 | frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); | ||
678 | if (!frags) | ||
679 | goto fail; | ||
680 | |||
681 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); | ||
682 | seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; | ||
683 | pos = first->data + hdrlen + per_fragm; | ||
684 | left = payload_len - per_fragm; | ||
685 | for (i = 0; i < num_fragm - 1; i++) { | ||
686 | struct ieee80211_hdr *fhdr; | ||
687 | size_t copylen; | ||
688 | |||
689 | if (left <= 0) | ||
690 | goto fail; | ||
691 | |||
692 | /* reserve enough extra head and tail room for possible | ||
693 | * encryption */ | ||
694 | frag = frags[i] = | ||
695 | dev_alloc_skb(tx->local->tx_headroom + | ||
696 | frag_threshold + | ||
697 | IEEE80211_ENCRYPT_HEADROOM + | ||
698 | IEEE80211_ENCRYPT_TAILROOM); | ||
699 | if (!frag) | ||
700 | goto fail; | ||
701 | /* Make sure that all fragments use the same priority so | ||
702 | * that they end up using the same TX queue */ | ||
703 | frag->priority = first->priority; | ||
704 | skb_reserve(frag, tx->local->tx_headroom + | ||
705 | IEEE80211_ENCRYPT_HEADROOM); | ||
706 | fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); | ||
707 | memcpy(fhdr, first->data, hdrlen); | ||
708 | if (i == num_fragm - 2) | ||
709 | fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); | ||
710 | fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); | ||
711 | copylen = left > per_fragm ? per_fragm : left; | ||
712 | memcpy(skb_put(frag, copylen), pos, copylen); | ||
713 | |||
714 | pos += copylen; | ||
715 | left -= copylen; | ||
763 | } | 716 | } |
717 | skb_trim(first, hdrlen + per_fragm); | ||
718 | |||
719 | tx->num_extra_frag = num_fragm - 1; | ||
720 | tx->extra_frag = frags; | ||
764 | 721 | ||
765 | return TX_CONTINUE; | 722 | return TX_CONTINUE; |
723 | |||
724 | fail: | ||
725 | printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); | ||
726 | if (frags) { | ||
727 | for (i = 0; i < num_fragm - 1; i++) | ||
728 | if (frags[i]) | ||
729 | dev_kfree_skb(frags[i]); | ||
730 | kfree(frags); | ||
731 | } | ||
732 | I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); | ||
733 | return TX_DROP; | ||
766 | } | 734 | } |
767 | 735 | ||
768 | static ieee80211_tx_result | 736 | static ieee80211_tx_result |
769 | ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx) | 737 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) |
738 | { | ||
739 | if (!tx->key) | ||
740 | return TX_CONTINUE; | ||
741 | |||
742 | switch (tx->key->conf.alg) { | ||
743 | case ALG_WEP: | ||
744 | return ieee80211_crypto_wep_encrypt(tx); | ||
745 | case ALG_TKIP: | ||
746 | return ieee80211_crypto_tkip_encrypt(tx); | ||
747 | case ALG_CCMP: | ||
748 | return ieee80211_crypto_ccmp_encrypt(tx); | ||
749 | } | ||
750 | |||
751 | /* not reached */ | ||
752 | WARN_ON(1); | ||
753 | return TX_DROP; | ||
754 | } | ||
755 | |||
756 | static ieee80211_tx_result | ||
757 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | ||
770 | { | 758 | { |
771 | struct ieee80211_local *local = tx->local; | 759 | struct ieee80211_local *local = tx->local; |
772 | struct sk_buff *skb = tx->skb; | 760 | struct sk_buff *skb = tx->skb; |
@@ -822,6 +810,20 @@ ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx) | |||
822 | tx->sta->channel_use_raw += load; | 810 | tx->sta->channel_use_raw += load; |
823 | tx->sdata->channel_use_raw += load; | 811 | tx->sdata->channel_use_raw += load; |
824 | 812 | ||
813 | if (tx->sta) { | ||
814 | tx->sta->tx_packets++; | ||
815 | tx->sta->tx_fragments++; | ||
816 | tx->sta->tx_bytes += tx->skb->len; | ||
817 | if (tx->extra_frag) { | ||
818 | int i; | ||
819 | tx->sta->tx_fragments += tx->num_extra_frag; | ||
820 | for (i = 0; i < tx->num_extra_frag; i++) { | ||
821 | tx->sta->tx_bytes += | ||
822 | tx->extra_frag[i]->len; | ||
823 | } | ||
824 | } | ||
825 | } | ||
826 | |||
825 | return TX_CONTINUE; | 827 | return TX_CONTINUE; |
826 | } | 828 | } |
827 | 829 | ||
@@ -834,11 +836,11 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] = | |||
834 | ieee80211_tx_h_ps_buf, | 836 | ieee80211_tx_h_ps_buf, |
835 | ieee80211_tx_h_select_key, | 837 | ieee80211_tx_h_select_key, |
836 | ieee80211_tx_h_michael_mic_add, | 838 | ieee80211_tx_h_michael_mic_add, |
837 | ieee80211_tx_h_fragment, | ||
838 | ieee80211_tx_h_encrypt, | ||
839 | ieee80211_tx_h_rate_ctrl, | 839 | ieee80211_tx_h_rate_ctrl, |
840 | ieee80211_tx_h_misc, | 840 | ieee80211_tx_h_misc, |
841 | ieee80211_tx_h_load_stats, | 841 | ieee80211_tx_h_fragment, |
842 | ieee80211_tx_h_encrypt, | ||
843 | ieee80211_tx_h_stats, | ||
842 | NULL | 844 | NULL |
843 | }; | 845 | }; |
844 | 846 | ||