aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/tx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-06-25 07:36:27 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-27 09:09:21 -0400
commit03f93c3d4c8aa9ed2e2b0a949ece658053527d71 (patch)
tree3be3c3991e858f0150a13dcb4097a730cb45d3d3 /net/mac80211/tx.c
parent59959a6150c8af737898e83f727e824dbed7b0fa (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.c68
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
88static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, 88static __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
214static int inline is_ieee80211_device(struct net_device *dev, 214static int inline is_ieee80211_device(struct net_device *dev,
@@ -541,7 +541,6 @@ static ieee80211_tx_result
541ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) 541ieee80211_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
754static ieee80211_tx_result 747static ieee80211_tx_result
748ieee80211_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
777static ieee80211_tx_result
755ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) 778ieee80211_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
1172retry: 1178retry:
1173 ret = __ieee80211_tx(local, skb, &tx); 1179 ret = __ieee80211_tx(local, skb, &tx);
1174 if (ret) { 1180 if (ret) {