diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-06-25 07:36:27 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-27 09:09:21 -0400 |
commit | 03f93c3d4c8aa9ed2e2b0a949ece658053527d71 (patch) | |
tree | 3be3c3991e858f0150a13dcb4097a730cb45d3d3 /net/mac80211/tx.c | |
parent | 59959a6150c8af737898e83f727e824dbed7b0fa (diff) |
mac80211: fix tx fragmentation
This patch fixes TX fragmentation caused by
tx handlers reordering and 'tx info to cb' patches
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 68 |
1 files changed, 37 insertions, 31 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index bf3600a04776..52ab85c4341b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -85,8 +85,8 @@ static inline void ieee80211_dump_frame(const char *ifname, const char *title, | |||
85 | } | 85 | } |
86 | #endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ | 86 | #endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ |
87 | 87 | ||
88 | static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | 88 | static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, |
89 | int next_frag_len) | 89 | int next_frag_len) |
90 | { | 90 | { |
91 | int rate, mrate, erp, dur, i; | 91 | int rate, mrate, erp, dur, i; |
92 | struct ieee80211_rate *txrate; | 92 | struct ieee80211_rate *txrate; |
@@ -138,7 +138,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | |||
138 | 138 | ||
139 | /* data/mgmt */ | 139 | /* data/mgmt */ |
140 | if (0 /* FIX: data/mgmt during CFP */) | 140 | if (0 /* FIX: data/mgmt during CFP */) |
141 | return 32768; | 141 | return cpu_to_le16(32768); |
142 | 142 | ||
143 | if (group_addr) /* Group address as the destination - no ACK */ | 143 | if (group_addr) /* Group address as the destination - no ACK */ |
144 | return 0; | 144 | return 0; |
@@ -208,7 +208,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | |||
208 | tx->sdata->bss_conf.use_short_preamble); | 208 | tx->sdata->bss_conf.use_short_preamble); |
209 | } | 209 | } |
210 | 210 | ||
211 | return dur; | 211 | return cpu_to_le16(dur); |
212 | } | 212 | } |
213 | 213 | ||
214 | static int inline is_ieee80211_device(struct net_device *dev, | 214 | static int inline is_ieee80211_device(struct net_device *dev, |
@@ -541,7 +541,6 @@ static ieee80211_tx_result | |||
541 | ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) | 541 | ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) |
542 | { | 542 | { |
543 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; | 543 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; |
544 | u16 dur; | ||
545 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 544 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
546 | struct ieee80211_supported_band *sband; | 545 | struct ieee80211_supported_band *sband; |
547 | 546 | ||
@@ -599,14 +598,6 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) | |||
599 | info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; | 598 | info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; |
600 | } | 599 | } |
601 | 600 | ||
602 | /* Setup duration field for the first fragment of the frame. Duration | ||
603 | * for remaining fragments will be updated when they are being sent | ||
604 | * to low-level driver in ieee80211_tx(). */ | ||
605 | dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), | ||
606 | (tx->flags & IEEE80211_TX_FRAGMENTED) ? | ||
607 | tx->extra_frag[0]->len : 0); | ||
608 | hdr->duration_id = cpu_to_le16(dur); | ||
609 | |||
610 | if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || | 601 | if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || |
611 | (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { | 602 | (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { |
612 | struct ieee80211_rate *rate; | 603 | struct ieee80211_rate *rate; |
@@ -708,6 +699,8 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
708 | fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); | 699 | fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); |
709 | copylen = left > per_fragm ? per_fragm : left; | 700 | copylen = left > per_fragm ? per_fragm : left; |
710 | memcpy(skb_put(frag, copylen), pos, copylen); | 701 | memcpy(skb_put(frag, copylen), pos, copylen); |
702 | memcpy(frag->cb, first->cb, sizeof(frag->cb)); | ||
703 | skb_copy_queue_mapping(frag, first); | ||
711 | 704 | ||
712 | pos += copylen; | 705 | pos += copylen; |
713 | left -= copylen; | 706 | left -= copylen; |
@@ -752,6 +745,36 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | |||
752 | } | 745 | } |
753 | 746 | ||
754 | static ieee80211_tx_result | 747 | static ieee80211_tx_result |
748 | ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) | ||
749 | { | ||
750 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; | ||
751 | int next_len, i; | ||
752 | int group_addr = is_multicast_ether_addr(hdr->addr1); | ||
753 | |||
754 | if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) { | ||
755 | hdr->duration_id = ieee80211_duration(tx, group_addr, 0); | ||
756 | return TX_CONTINUE; | ||
757 | } | ||
758 | |||
759 | hdr->duration_id = ieee80211_duration(tx, group_addr, | ||
760 | tx->extra_frag[0]->len); | ||
761 | |||
762 | for (i = 0; i < tx->num_extra_frag; i++) { | ||
763 | if (i + 1 < tx->num_extra_frag) { | ||
764 | next_len = tx->extra_frag[i + 1]->len; | ||
765 | } else { | ||
766 | next_len = 0; | ||
767 | tx->rate_idx = tx->last_frag_rate_idx; | ||
768 | } | ||
769 | |||
770 | hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data; | ||
771 | hdr->duration_id = ieee80211_duration(tx, 0, next_len); | ||
772 | } | ||
773 | |||
774 | return TX_CONTINUE; | ||
775 | } | ||
776 | |||
777 | static ieee80211_tx_result | ||
755 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | 778 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) |
756 | { | 779 | { |
757 | int i; | 780 | int i; |
@@ -785,6 +808,7 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] = | |||
785 | ieee80211_tx_h_fragment, | 808 | ieee80211_tx_h_fragment, |
786 | /* handlers after fragment must be aware of tx info fragmentation! */ | 809 | /* handlers after fragment must be aware of tx info fragmentation! */ |
787 | ieee80211_tx_h_encrypt, | 810 | ieee80211_tx_h_encrypt, |
811 | ieee80211_tx_h_calculate_duration, | ||
788 | ieee80211_tx_h_stats, | 812 | ieee80211_tx_h_stats, |
789 | NULL | 813 | NULL |
790 | }; | 814 | }; |
@@ -1151,24 +1175,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | |||
1151 | if (invoke_tx_handlers(&tx)) | 1175 | if (invoke_tx_handlers(&tx)) |
1152 | goto out; | 1176 | goto out; |
1153 | 1177 | ||
1154 | if (tx.extra_frag) { | ||
1155 | for (i = 0; i < tx.num_extra_frag; i++) { | ||
1156 | int next_len, dur; | ||
1157 | struct ieee80211_hdr *hdr = | ||
1158 | (struct ieee80211_hdr *) | ||
1159 | tx.extra_frag[i]->data; | ||
1160 | |||
1161 | if (i + 1 < tx.num_extra_frag) { | ||
1162 | next_len = tx.extra_frag[i + 1]->len; | ||
1163 | } else { | ||
1164 | next_len = 0; | ||
1165 | tx.rate_idx = tx.last_frag_rate_idx; | ||
1166 | } | ||
1167 | dur = ieee80211_duration(&tx, 0, next_len); | ||
1168 | hdr->duration_id = cpu_to_le16(dur); | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | retry: | 1178 | retry: |
1173 | ret = __ieee80211_tx(local, skb, &tx); | 1179 | ret = __ieee80211_tx(local, skb, &tx); |
1174 | if (ret) { | 1180 | if (ret) { |