]>
Commit | Line | Data |
---|---|---|
92b96797 FB |
1 | /* |
2 | * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along | |
16 | * with this program; if not, write to the Free Software Foundation, Inc., | |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 | * | |
19 | * File: rxtx.c | |
20 | * | |
21 | * Purpose: handle WMAC/802.3/802.11 rx & tx functions | |
22 | * | |
23 | * Author: Lyndon Chen | |
24 | * | |
25 | * Date: May 20, 2003 | |
26 | * | |
27 | * Functions: | |
9ec7f2d8 | 28 | * vnt_generate_tx_parameter - Generate tx dma required parameter. |
435ae3be | 29 | * vnt_get_duration_le - get tx data required duration |
f2aabee6 | 30 | * vnt_get_rtscts_duration_le- get rtx/cts required duration |
aadf7d13 | 31 | * vnt_get_rtscts_rsvtime_le- get rts/cts reserved time |
3815a27b | 32 | * vnt_get_rsvtime- get frame reserved time |
4f31668f | 33 | * vnt_fill_cts_head- fulfill CTS ctl header |
92b96797 FB |
34 | * |
35 | * Revision History: | |
36 | * | |
37 | */ | |
38 | ||
92b96797 | 39 | #include "device.h" |
92b96797 | 40 | #include "rxtx.h" |
92b96797 | 41 | #include "card.h" |
92b96797 | 42 | #include "mac.h" |
92b96797 | 43 | #include "rf.h" |
92b96797 | 44 | #include "usbpipe.h" |
9d26d60f | 45 | |
4a499de2 | 46 | static int msglevel = MSG_LEVEL_INFO; |
92b96797 | 47 | |
1a4d4509 MP |
48 | static const u16 vnt_time_stampoff[2][MAX_RATE] = { |
49 | {384, 288, 226, 209, 54, 43, 37, 31, 28, 25, 24, 23},/* Long Preamble */ | |
50 | {384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23},/* Short Preamble */ | |
51 | }; | |
92b96797 | 52 | |
e3f31874 MP |
53 | static const u16 vnt_fb_opt0[2][5] = { |
54 | {RATE_12M, RATE_18M, RATE_24M, RATE_36M, RATE_48M}, /* fallback_rate0 */ | |
55 | {RATE_12M, RATE_12M, RATE_18M, RATE_24M, RATE_36M}, /* fallback_rate1 */ | |
56 | }; | |
57 | ||
2331ba42 MP |
58 | static const u16 vnt_fb_opt1[2][5] = { |
59 | {RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, /* fallback_rate0 */ | |
60 | {RATE_6M , RATE_6M, RATE_12M, RATE_12M, RATE_18M}, /* fallback_rate1 */ | |
61 | }; | |
92b96797 | 62 | |
92b96797 FB |
63 | #define RTSDUR_BB 0 |
64 | #define RTSDUR_BA 1 | |
65 | #define RTSDUR_AA 2 | |
66 | #define CTSDUR_BA 3 | |
67 | #define RTSDUR_BA_F0 4 | |
68 | #define RTSDUR_AA_F0 5 | |
69 | #define RTSDUR_BA_F1 6 | |
70 | #define RTSDUR_AA_F1 7 | |
71 | #define CTSDUR_BA_F0 8 | |
72 | #define CTSDUR_BA_F1 9 | |
73 | #define DATADUR_B 10 | |
74 | #define DATADUR_A 11 | |
75 | #define DATADUR_A_F0 12 | |
76 | #define DATADUR_A_F1 13 | |
77 | ||
aceaf018 | 78 | static struct vnt_usb_send_context |
a032b16c | 79 | *vnt_get_free_context(struct vnt_private *priv) |
92b96797 | 80 | { |
b89f3b94 | 81 | struct vnt_usb_send_context *context = NULL; |
d56131de | 82 | int ii; |
92b96797 | 83 | |
b89f3b94 MP |
84 | DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GetFreeContext()\n"); |
85 | ||
86 | for (ii = 0; ii < priv->cbTD; ii++) { | |
87 | if (!priv->apTD[ii]) | |
88 | return NULL; | |
89 | ||
90 | context = priv->apTD[ii]; | |
30a05b39 MP |
91 | if (context->in_use == false) { |
92 | context->in_use = true; | |
93 | memset(context->data, 0, | |
b89f3b94 | 94 | MAX_TOTAL_SIZE_WITH_ALL_HEADERS); |
1622c8fc MP |
95 | |
96 | context->hdr = NULL; | |
97 | ||
b89f3b94 MP |
98 | return context; |
99 | } | |
100 | } | |
101 | ||
102 | if (ii == priv->cbTD) | |
103 | DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"No Free Tx Context\n"); | |
aceaf018 | 104 | |
5c851383 | 105 | return NULL; |
92b96797 FB |
106 | } |
107 | ||
dab085b1 | 108 | static __le16 vnt_time_stamp_off(struct vnt_private *priv, u16 rate) |
f115e76a | 109 | { |
1a4d4509 | 110 | return cpu_to_le16(vnt_time_stampoff[priv->byPreambleType % 2] |
f115e76a MP |
111 | [rate % MAX_RATE]); |
112 | } | |
113 | ||
3815a27b | 114 | static u32 vnt_get_rsvtime(struct vnt_private *priv, u8 pkt_type, |
3fd5620f | 115 | u32 frame_length, u16 rate, int need_ack) |
92b96797 | 116 | { |
3fd5620f | 117 | u32 data_time, ack_time; |
92b96797 | 118 | |
d38ee5b2 | 119 | data_time = vnt_get_frame_time(priv->byPreambleType, pkt_type, |
3fd5620f | 120 | frame_length, rate); |
92b96797 | 121 | |
3fd5620f | 122 | if (pkt_type == PK_TYPE_11B) |
d38ee5b2 MP |
123 | ack_time = vnt_get_frame_time(priv->byPreambleType, pkt_type, |
124 | 14, (u16)priv->byTopCCKBasicRate); | |
3fd5620f | 125 | else |
d38ee5b2 MP |
126 | ack_time = vnt_get_frame_time(priv->byPreambleType, pkt_type, |
127 | 14, (u16)priv->byTopOFDMBasicRate); | |
3fd5620f MP |
128 | |
129 | if (need_ack) | |
130 | return data_time + priv->uSIFS + ack_time; | |
131 | ||
132 | return data_time; | |
92b96797 FB |
133 | } |
134 | ||
2075f654 | 135 | static __le16 vnt_rxtx_rsvtime_le16(struct vnt_private *priv, u8 pkt_type, |
9c3806d5 MP |
136 | u32 frame_length, u16 rate, int need_ack) |
137 | { | |
3815a27b | 138 | return cpu_to_le16((u16)vnt_get_rsvtime(priv, pkt_type, |
9c3806d5 MP |
139 | frame_length, rate, need_ack)); |
140 | } | |
141 | ||
aadf7d13 | 142 | static __le16 vnt_get_rtscts_rsvtime_le(struct vnt_private *priv, |
3b6cee7b | 143 | u8 rsv_type, u8 pkt_type, u32 frame_length, u16 current_rate) |
92b96797 | 144 | { |
342e2e20 | 145 | u32 rrv_time, rts_time, cts_time, ack_time, data_time; |
92b96797 | 146 | |
342e2e20 | 147 | rrv_time = rts_time = cts_time = ack_time = data_time = 0; |
92b96797 | 148 | |
d38ee5b2 | 149 | data_time = vnt_get_frame_time(priv->byPreambleType, pkt_type, |
3b6cee7b | 150 | frame_length, current_rate); |
342e2e20 MP |
151 | |
152 | if (rsv_type == 0) { | |
d38ee5b2 | 153 | rts_time = vnt_get_frame_time(priv->byPreambleType, |
342e2e20 | 154 | pkt_type, 20, priv->byTopCCKBasicRate); |
d38ee5b2 | 155 | cts_time = ack_time = vnt_get_frame_time(priv->byPreambleType, |
342e2e20 MP |
156 | pkt_type, 14, priv->byTopCCKBasicRate); |
157 | } else if (rsv_type == 1) { | |
d38ee5b2 | 158 | rts_time = vnt_get_frame_time(priv->byPreambleType, |
342e2e20 | 159 | pkt_type, 20, priv->byTopCCKBasicRate); |
d38ee5b2 | 160 | cts_time = vnt_get_frame_time(priv->byPreambleType, pkt_type, |
342e2e20 | 161 | 14, priv->byTopCCKBasicRate); |
d38ee5b2 | 162 | ack_time = vnt_get_frame_time(priv->byPreambleType, pkt_type, |
342e2e20 MP |
163 | 14, priv->byTopOFDMBasicRate); |
164 | } else if (rsv_type == 2) { | |
d38ee5b2 | 165 | rts_time = vnt_get_frame_time(priv->byPreambleType, pkt_type, |
342e2e20 | 166 | 20, priv->byTopOFDMBasicRate); |
d38ee5b2 | 167 | cts_time = ack_time = vnt_get_frame_time(priv->byPreambleType, |
342e2e20 MP |
168 | pkt_type, 14, priv->byTopOFDMBasicRate); |
169 | } else if (rsv_type == 3) { | |
d38ee5b2 | 170 | cts_time = vnt_get_frame_time(priv->byPreambleType, pkt_type, |
342e2e20 | 171 | 14, priv->byTopCCKBasicRate); |
d38ee5b2 | 172 | ack_time = vnt_get_frame_time(priv->byPreambleType, pkt_type, |
342e2e20 MP |
173 | 14, priv->byTopOFDMBasicRate); |
174 | ||
175 | rrv_time = cts_time + ack_time + data_time + 2 * priv->uSIFS; | |
176 | ||
20338015 | 177 | return cpu_to_le16((u16)rrv_time); |
342e2e20 MP |
178 | } |
179 | ||
180 | rrv_time = rts_time + cts_time + ack_time + data_time + 3 * priv->uSIFS; | |
92b96797 | 181 | |
342e2e20 | 182 | return cpu_to_le16((u16)rrv_time); |
92b96797 FB |
183 | } |
184 | ||
435ae3be | 185 | static __le16 vnt_get_duration_le(struct vnt_private *piv, |
a4c2a8a4 | 186 | u8 pkt_type, int need_ack) |
92b96797 | 187 | { |
a4c2a8a4 | 188 | u32 ack_time = 0; |
92b96797 | 189 | |
a4c2a8a4 MP |
190 | if (need_ack) { |
191 | if (pkt_type == PK_TYPE_11B) | |
192 | ack_time = vnt_get_frame_time(piv->byPreambleType, | |
193 | pkt_type, 14, piv->byTopCCKBasicRate); | |
b02ccd59 | 194 | else |
a4c2a8a4 MP |
195 | ack_time = vnt_get_frame_time(piv->byPreambleType, |
196 | pkt_type, 14, piv->byTopOFDMBasicRate); | |
197 | ||
198 | return cpu_to_le16((u16)(piv->uSIFS + ack_time)); | |
b02ccd59 | 199 | } |
92b96797 | 200 | |
92b96797 FB |
201 | return 0; |
202 | } | |
203 | ||
f2aabee6 | 204 | static __le16 vnt_get_rtscts_duration_le(struct vnt_private *priv, u8 dur_type, |
7beae9a2 | 205 | u32 frame_length, u8 pkt_type, u16 rate, int need_ack) |
92b96797 | 206 | { |
7beae9a2 | 207 | u32 cts_time = 0, dur_time = 0; |
92b96797 | 208 | |
7beae9a2 | 209 | switch (dur_type) { |
ecd80240 MP |
210 | case RTSDUR_BB: |
211 | case RTSDUR_BA: | |
212 | case RTSDUR_BA_F0: | |
213 | case RTSDUR_BA_F1: | |
7beae9a2 MP |
214 | cts_time = vnt_get_frame_time(priv->byPreambleType, |
215 | pkt_type, 14, priv->byTopCCKBasicRate); | |
216 | dur_time = cts_time + 2 * priv->uSIFS + | |
3815a27b | 217 | vnt_get_rsvtime(priv, pkt_type, |
7beae9a2 | 218 | frame_length, rate, need_ack); |
ecd80240 | 219 | break; |
92b96797 | 220 | |
ecd80240 MP |
221 | case RTSDUR_AA: |
222 | case RTSDUR_AA_F0: | |
223 | case RTSDUR_AA_F1: | |
7beae9a2 MP |
224 | cts_time = vnt_get_frame_time(priv->byPreambleType, |
225 | pkt_type, 14, priv->byTopOFDMBasicRate); | |
226 | dur_time = cts_time + 2 * priv->uSIFS + | |
3815a27b | 227 | vnt_get_rsvtime(priv, pkt_type, |
7beae9a2 | 228 | frame_length, rate, need_ack); |
ecd80240 | 229 | break; |
92b96797 | 230 | |
ecd80240 MP |
231 | case CTSDUR_BA: |
232 | case CTSDUR_BA_F0: | |
233 | case CTSDUR_BA_F1: | |
3815a27b | 234 | dur_time = priv->uSIFS + vnt_get_rsvtime(priv, |
7beae9a2 | 235 | pkt_type, frame_length, rate, need_ack); |
ecd80240 | 236 | break; |
92b96797 | 237 | |
ecd80240 MP |
238 | default: |
239 | break; | |
240 | } | |
92b96797 | 241 | |
7beae9a2 | 242 | return cpu_to_le16((u16)dur_time); |
92b96797 FB |
243 | } |
244 | ||
1622c8fc MP |
245 | static u16 vnt_mac_hdr_pos(struct vnt_usb_send_context *tx_context, |
246 | struct ieee80211_hdr *hdr) | |
247 | { | |
248 | u8 *head = tx_context->data + offsetof(struct vnt_tx_buffer, fifo_head); | |
249 | u8 *hdr_pos = (u8 *)hdr; | |
250 | ||
251 | tx_context->hdr = hdr; | |
252 | if (!tx_context->hdr) | |
253 | return 0; | |
254 | ||
255 | return (u16)(hdr_pos - head); | |
256 | } | |
257 | ||
c2c32da3 MP |
258 | static u16 vnt_rxtx_datahead_g(struct vnt_usb_send_context *tx_context, |
259 | u8 pkt_type, u16 rate, struct vnt_tx_datahead_g *buf, | |
260 | u32 frame_len, int need_ack) | |
78363fd1 | 261 | { |
c2c32da3 MP |
262 | |
263 | struct vnt_private *priv = tx_context->priv; | |
893cc709 MP |
264 | struct ieee80211_hdr *hdr = |
265 | (struct ieee80211_hdr *)tx_context->skb->data; | |
c2c32da3 | 266 | |
78363fd1 | 267 | /* Get SignalField,ServiceField,Length */ |
205056f3 MP |
268 | vnt_get_phy_field(priv, frame_len, rate, pkt_type, &buf->a); |
269 | vnt_get_phy_field(priv, frame_len, priv->byTopCCKBasicRate, | |
78363fd1 MP |
270 | PK_TYPE_11B, &buf->b); |
271 | ||
272 | /* Get Duration and TimeStamp */ | |
893cc709 MP |
273 | if (ieee80211_is_pspoll(hdr->frame_control)) { |
274 | __le16 dur = cpu_to_le16(priv->current_aid | BIT(14) | BIT(15)); | |
275 | ||
276 | buf->duration_a = dur; | |
277 | buf->duration_b = dur; | |
278 | } else { | |
435ae3be MP |
279 | buf->duration_a = vnt_get_duration_le(priv, pkt_type, need_ack); |
280 | buf->duration_b = vnt_get_duration_le(priv, | |
893cc709 MP |
281 | PK_TYPE_11B, need_ack); |
282 | } | |
78363fd1 | 283 | |
10bb39a0 MP |
284 | buf->time_stamp_off_a = vnt_time_stamp_off(priv, rate); |
285 | buf->time_stamp_off_b = vnt_time_stamp_off(priv, | |
78363fd1 MP |
286 | priv->byTopCCKBasicRate); |
287 | ||
1622c8fc MP |
288 | tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr); |
289 | ||
c4cf6dfb | 290 | return le16_to_cpu(buf->duration_a); |
78363fd1 MP |
291 | } |
292 | ||
c2c32da3 MP |
293 | static u16 vnt_rxtx_datahead_g_fb(struct vnt_usb_send_context *tx_context, |
294 | u8 pkt_type, u16 rate, struct vnt_tx_datahead_g_fb *buf, | |
5b852f53 MP |
295 | u32 frame_len, int need_ack) |
296 | { | |
c2c32da3 MP |
297 | struct vnt_private *priv = tx_context->priv; |
298 | ||
5b852f53 | 299 | /* Get SignalField,ServiceField,Length */ |
205056f3 | 300 | vnt_get_phy_field(priv, frame_len, rate, pkt_type, &buf->a); |
5b852f53 | 301 | |
205056f3 | 302 | vnt_get_phy_field(priv, frame_len, priv->byTopCCKBasicRate, |
5b852f53 MP |
303 | PK_TYPE_11B, &buf->b); |
304 | ||
305 | /* Get Duration and TimeStamp */ | |
435ae3be MP |
306 | buf->duration_a = vnt_get_duration_le(priv, pkt_type, need_ack); |
307 | buf->duration_b = vnt_get_duration_le(priv, PK_TYPE_11B, need_ack); | |
5b852f53 | 308 | |
435ae3be MP |
309 | buf->duration_a_f0 = vnt_get_duration_le(priv, pkt_type, need_ack); |
310 | buf->duration_a_f1 = vnt_get_duration_le(priv, pkt_type, need_ack); | |
5b852f53 | 311 | |
10bb39a0 MP |
312 | buf->time_stamp_off_a = vnt_time_stamp_off(priv, rate); |
313 | buf->time_stamp_off_b = vnt_time_stamp_off(priv, | |
5b852f53 MP |
314 | priv->byTopCCKBasicRate); |
315 | ||
1622c8fc MP |
316 | tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr); |
317 | ||
c4cf6dfb | 318 | return le16_to_cpu(buf->duration_a); |
5b852f53 MP |
319 | } |
320 | ||
c2c32da3 MP |
321 | static u16 vnt_rxtx_datahead_a_fb(struct vnt_usb_send_context *tx_context, |
322 | u8 pkt_type, u16 rate, struct vnt_tx_datahead_a_fb *buf, | |
bd3f51f1 MP |
323 | u32 frame_len, int need_ack) |
324 | { | |
c2c32da3 MP |
325 | struct vnt_private *priv = tx_context->priv; |
326 | ||
bd3f51f1 | 327 | /* Get SignalField,ServiceField,Length */ |
205056f3 | 328 | vnt_get_phy_field(priv, frame_len, rate, pkt_type, &buf->a); |
bd3f51f1 | 329 | /* Get Duration and TimeStampOff */ |
435ae3be | 330 | buf->duration = vnt_get_duration_le(priv, pkt_type, need_ack); |
bd3f51f1 | 331 | |
435ae3be MP |
332 | buf->duration_f0 = vnt_get_duration_le(priv, pkt_type, need_ack); |
333 | buf->duration_f1 = vnt_get_duration_le(priv, pkt_type, need_ack); | |
bd3f51f1 | 334 | |
10bb39a0 | 335 | buf->time_stamp_off = vnt_time_stamp_off(priv, rate); |
bd3f51f1 | 336 | |
1622c8fc MP |
337 | tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr); |
338 | ||
c4cf6dfb | 339 | return le16_to_cpu(buf->duration); |
bd3f51f1 MP |
340 | } |
341 | ||
c2c32da3 MP |
342 | static u16 vnt_rxtx_datahead_ab(struct vnt_usb_send_context *tx_context, |
343 | u8 pkt_type, u16 rate, struct vnt_tx_datahead_ab *buf, | |
5634a5ab MP |
344 | u32 frame_len, int need_ack) |
345 | { | |
c2c32da3 | 346 | struct vnt_private *priv = tx_context->priv; |
893cc709 MP |
347 | struct ieee80211_hdr *hdr = |
348 | (struct ieee80211_hdr *)tx_context->skb->data; | |
c2c32da3 | 349 | |
5634a5ab | 350 | /* Get SignalField,ServiceField,Length */ |
205056f3 | 351 | vnt_get_phy_field(priv, frame_len, rate, pkt_type, &buf->ab); |
893cc709 | 352 | |
5634a5ab | 353 | /* Get Duration and TimeStampOff */ |
893cc709 MP |
354 | if (ieee80211_is_pspoll(hdr->frame_control)) { |
355 | __le16 dur = cpu_to_le16(priv->current_aid | BIT(14) | BIT(15)); | |
356 | ||
357 | buf->duration = dur; | |
358 | } else { | |
435ae3be | 359 | buf->duration = vnt_get_duration_le(priv, pkt_type, need_ack); |
893cc709 | 360 | } |
5634a5ab | 361 | |
10bb39a0 | 362 | buf->time_stamp_off = vnt_time_stamp_off(priv, rate); |
5634a5ab | 363 | |
1622c8fc MP |
364 | tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr); |
365 | ||
c4cf6dfb | 366 | return le16_to_cpu(buf->duration); |
5634a5ab MP |
367 | } |
368 | ||
d38b13aa MP |
369 | static int vnt_fill_ieee80211_rts(struct vnt_usb_send_context *tx_context, |
370 | struct ieee80211_rts *rts, __le16 duration) | |
5e67ee49 | 371 | { |
d38b13aa MP |
372 | struct ieee80211_hdr *hdr = |
373 | (struct ieee80211_hdr *)tx_context->skb->data; | |
374 | ||
5e67ee49 | 375 | rts->duration = duration; |
f4554d3b MP |
376 | rts->frame_control = |
377 | cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); | |
5e67ee49 | 378 | |
d38b13aa MP |
379 | memcpy(rts->ra, hdr->addr1, ETH_ALEN); |
380 | memcpy(rts->ta, hdr->addr2, ETH_ALEN); | |
5e67ee49 MP |
381 | |
382 | return 0; | |
383 | } | |
384 | ||
c2c32da3 | 385 | static u16 vnt_rxtx_rts_g_head(struct vnt_usb_send_context *tx_context, |
72bf8059 | 386 | struct vnt_rts_g *buf, u8 pkt_type, u32 frame_len, int need_ack, |
26e7362c | 387 | u16 current_rate) |
5e67ee49 | 388 | { |
c2c32da3 | 389 | struct vnt_private *priv = tx_context->priv; |
5e67ee49 MP |
390 | u16 rts_frame_len = 20; |
391 | ||
205056f3 | 392 | vnt_get_phy_field(priv, rts_frame_len, priv->byTopCCKBasicRate, |
5e67ee49 | 393 | PK_TYPE_11B, &buf->b); |
205056f3 | 394 | vnt_get_phy_field(priv, rts_frame_len, |
5e67ee49 MP |
395 | priv->byTopOFDMBasicRate, pkt_type, &buf->a); |
396 | ||
f2aabee6 MP |
397 | buf->duration_bb = vnt_get_rtscts_duration_le(priv, RTSDUR_BB, |
398 | frame_len, PK_TYPE_11B, priv->byTopCCKBasicRate, need_ack); | |
399 | buf->duration_aa = vnt_get_rtscts_duration_le(priv, RTSDUR_AA, | |
400 | frame_len, pkt_type, current_rate, need_ack); | |
401 | buf->duration_ba = vnt_get_rtscts_duration_le(priv, RTSDUR_BA, | |
402 | frame_len, pkt_type, current_rate, need_ack); | |
5e67ee49 | 403 | |
d38b13aa | 404 | vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration_aa); |
5e67ee49 | 405 | |
c2c32da3 | 406 | return vnt_rxtx_datahead_g(tx_context, pkt_type, current_rate, |
78363fd1 | 407 | &buf->data_head, frame_len, need_ack); |
5e67ee49 MP |
408 | } |
409 | ||
c2c32da3 | 410 | static u16 vnt_rxtx_rts_g_fb_head(struct vnt_usb_send_context *tx_context, |
72bf8059 | 411 | struct vnt_rts_g_fb *buf, u8 pkt_type, u32 frame_len, int need_ack, |
26e7362c | 412 | u16 current_rate) |
ec91713a | 413 | { |
c2c32da3 | 414 | struct vnt_private *priv = tx_context->priv; |
ec91713a MP |
415 | u16 rts_frame_len = 20; |
416 | ||
205056f3 | 417 | vnt_get_phy_field(priv, rts_frame_len, priv->byTopCCKBasicRate, |
ec91713a | 418 | PK_TYPE_11B, &buf->b); |
205056f3 | 419 | vnt_get_phy_field(priv, rts_frame_len, |
ec91713a MP |
420 | priv->byTopOFDMBasicRate, pkt_type, &buf->a); |
421 | ||
422 | ||
f2aabee6 MP |
423 | buf->duration_bb = vnt_get_rtscts_duration_le(priv, RTSDUR_BB, |
424 | frame_len, PK_TYPE_11B, priv->byTopCCKBasicRate, need_ack); | |
425 | buf->duration_aa = vnt_get_rtscts_duration_le(priv, RTSDUR_AA, | |
426 | frame_len, pkt_type, current_rate, need_ack); | |
427 | buf->duration_ba = vnt_get_rtscts_duration_le(priv, RTSDUR_BA, | |
428 | frame_len, pkt_type, current_rate, need_ack); | |
ec91713a MP |
429 | |
430 | ||
f2aabee6 | 431 | buf->rts_duration_ba_f0 = vnt_get_rtscts_duration_le(priv, RTSDUR_BA_F0, |
26e7362c | 432 | frame_len, pkt_type, priv->tx_rate_fb0, need_ack); |
f2aabee6 | 433 | buf->rts_duration_aa_f0 = vnt_get_rtscts_duration_le(priv, RTSDUR_AA_F0, |
26e7362c | 434 | frame_len, pkt_type, priv->tx_rate_fb0, need_ack); |
f2aabee6 | 435 | buf->rts_duration_ba_f1 = vnt_get_rtscts_duration_le(priv, RTSDUR_BA_F1, |
26e7362c | 436 | frame_len, pkt_type, priv->tx_rate_fb1, need_ack); |
f2aabee6 | 437 | buf->rts_duration_aa_f1 = vnt_get_rtscts_duration_le(priv, RTSDUR_AA_F1, |
26e7362c | 438 | frame_len, pkt_type, priv->tx_rate_fb1, need_ack); |
ec91713a | 439 | |
d38b13aa | 440 | vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration_aa); |
ec91713a | 441 | |
c2c32da3 | 442 | return vnt_rxtx_datahead_g_fb(tx_context, pkt_type, current_rate, |
5b852f53 | 443 | &buf->data_head, frame_len, need_ack); |
ec91713a MP |
444 | } |
445 | ||
c2c32da3 | 446 | static u16 vnt_rxtx_rts_ab_head(struct vnt_usb_send_context *tx_context, |
72bf8059 | 447 | struct vnt_rts_ab *buf, u8 pkt_type, u32 frame_len, int need_ack, |
26e7362c | 448 | u16 current_rate) |
1712633d | 449 | { |
c2c32da3 | 450 | struct vnt_private *priv = tx_context->priv; |
1712633d MP |
451 | u16 rts_frame_len = 20; |
452 | ||
205056f3 | 453 | vnt_get_phy_field(priv, rts_frame_len, |
1712633d MP |
454 | priv->byTopOFDMBasicRate, pkt_type, &buf->ab); |
455 | ||
f2aabee6 | 456 | buf->duration = vnt_get_rtscts_duration_le(priv, RTSDUR_AA, frame_len, |
26e7362c | 457 | pkt_type, current_rate, need_ack); |
1712633d | 458 | |
d38b13aa | 459 | vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration); |
1712633d | 460 | |
c2c32da3 | 461 | return vnt_rxtx_datahead_ab(tx_context, pkt_type, current_rate, |
5634a5ab | 462 | &buf->data_head, frame_len, need_ack); |
1712633d MP |
463 | } |
464 | ||
c2c32da3 | 465 | static u16 vnt_rxtx_rts_a_fb_head(struct vnt_usb_send_context *tx_context, |
72bf8059 | 466 | struct vnt_rts_a_fb *buf, u8 pkt_type, u32 frame_len, int need_ack, |
26e7362c | 467 | u16 current_rate) |
9d2578c1 | 468 | { |
c2c32da3 | 469 | struct vnt_private *priv = tx_context->priv; |
9d2578c1 MP |
470 | u16 rts_frame_len = 20; |
471 | ||
205056f3 | 472 | vnt_get_phy_field(priv, rts_frame_len, |
9d2578c1 MP |
473 | priv->byTopOFDMBasicRate, pkt_type, &buf->a); |
474 | ||
f2aabee6 | 475 | buf->duration = vnt_get_rtscts_duration_le(priv, RTSDUR_AA, frame_len, |
26e7362c | 476 | pkt_type, current_rate, need_ack); |
9d2578c1 | 477 | |
f2aabee6 | 478 | buf->rts_duration_f0 = vnt_get_rtscts_duration_le(priv, RTSDUR_AA_F0, |
26e7362c | 479 | frame_len, pkt_type, priv->tx_rate_fb0, need_ack); |
9d2578c1 | 480 | |
f2aabee6 | 481 | buf->rts_duration_f1 = vnt_get_rtscts_duration_le(priv, RTSDUR_AA_F1, |
26e7362c | 482 | frame_len, pkt_type, priv->tx_rate_fb1, need_ack); |
9d2578c1 | 483 | |
d38b13aa | 484 | vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration); |
9d2578c1 | 485 | |
c2c32da3 | 486 | return vnt_rxtx_datahead_a_fb(tx_context, pkt_type, current_rate, |
bd3f51f1 | 487 | &buf->data_head, frame_len, need_ack); |
9d2578c1 MP |
488 | } |
489 | ||
4f31668f | 490 | static u16 vnt_fill_cts_head(struct vnt_usb_send_context *tx_context, |
ee16de8c MP |
491 | u8 pkt_type, union vnt_tx_data_head *head, u32 frame_len, |
492 | int need_ack, u16 current_rate) | |
92b96797 | 493 | { |
ee16de8c MP |
494 | struct vnt_private *priv = tx_context->priv; |
495 | u32 cts_frame_len = 14; | |
92b96797 | 496 | |
27df3ebf | 497 | if (!head) |
0a0f4b69 | 498 | return 0; |
92b96797 | 499 | |
ce7b0db8 | 500 | if (tx_context->fb_option) { |
c921cc8c | 501 | /* Auto Fall back */ |
ee16de8c | 502 | struct vnt_cts_fb *buf = &head->cts_g_fb; |
aed387c7 | 503 | /* Get SignalField,ServiceField,Length */ |
ee16de8c MP |
504 | vnt_get_phy_field(priv, cts_frame_len, |
505 | priv->byTopCCKBasicRate, PK_TYPE_11B, &buf->b); | |
f2aabee6 | 506 | buf->duration_ba = vnt_get_rtscts_duration_le(priv, CTSDUR_BA, |
ee16de8c MP |
507 | frame_len, pkt_type, |
508 | current_rate, need_ack); | |
e34f9dbe | 509 | /* Get CTSDuration_ba_f0 */ |
f2aabee6 | 510 | buf->cts_duration_ba_f0 = vnt_get_rtscts_duration_le(priv, |
ee16de8c MP |
511 | CTSDUR_BA_F0, frame_len, pkt_type, |
512 | priv->tx_rate_fb0, need_ack); | |
e34f9dbe | 513 | /* Get CTSDuration_ba_f1 */ |
f2aabee6 | 514 | buf->cts_duration_ba_f1 = vnt_get_rtscts_duration_le(priv, |
ee16de8c MP |
515 | CTSDUR_BA_F1, frame_len, pkt_type, |
516 | priv->tx_rate_fb1, need_ack); | |
14840cdd | 517 | /* Get CTS Frame body */ |
ee16de8c MP |
518 | buf->data.duration = buf->duration_ba; |
519 | buf->data.frame_control = | |
d9560ae5 MP |
520 | cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS); |
521 | ||
ee16de8c | 522 | memcpy(buf->data.ra, priv->abyCurrentNetAddr, ETH_ALEN); |
5b852f53 | 523 | |
ee16de8c MP |
524 | return vnt_rxtx_datahead_g_fb(tx_context, pkt_type, |
525 | current_rate, &buf->data_head, frame_len, | |
526 | need_ack); | |
c921cc8c | 527 | } else { |
ee16de8c | 528 | struct vnt_cts *buf = &head->cts_g; |
aed387c7 | 529 | /* Get SignalField,ServiceField,Length */ |
ee16de8c MP |
530 | vnt_get_phy_field(priv, cts_frame_len, |
531 | priv->byTopCCKBasicRate, PK_TYPE_11B, &buf->b); | |
e34f9dbe | 532 | /* Get CTSDuration_ba */ |
f2aabee6 | 533 | buf->duration_ba = vnt_get_rtscts_duration_le(priv, |
ee16de8c MP |
534 | CTSDUR_BA, frame_len, pkt_type, |
535 | current_rate, need_ack); | |
14840cdd | 536 | /*Get CTS Frame body*/ |
ee16de8c MP |
537 | buf->data.duration = buf->duration_ba; |
538 | buf->data.frame_control = | |
d9560ae5 MP |
539 | cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS); |
540 | ||
ee16de8c | 541 | memcpy(buf->data.ra, priv->abyCurrentNetAddr, ETH_ALEN); |
78363fd1 | 542 | |
ee16de8c MP |
543 | return vnt_rxtx_datahead_g(tx_context, pkt_type, current_rate, |
544 | &buf->data_head, frame_len, need_ack); | |
92b96797 | 545 | } |
0a0f4b69 MP |
546 | |
547 | return 0; | |
92b96797 FB |
548 | } |
549 | ||
24cdd90f MP |
550 | static u16 vnt_rxtx_rts(struct vnt_usb_send_context *tx_context, |
551 | union vnt_tx_head *tx_head, u8 pkt_type, u32 frame_size, | |
4f06c0dc | 552 | int need_ack, u16 current_rate, bool need_mic) |
24cdd90f MP |
553 | { |
554 | struct vnt_private *priv = tx_context->priv; | |
555 | struct vnt_rrv_time_rts *buf = &tx_head->tx_rts.rts; | |
4f06c0dc | 556 | union vnt_tx_data_head *head = &tx_head->tx_rts.tx.head; |
24cdd90f | 557 | |
aadf7d13 | 558 | buf->rts_rrv_time_aa = vnt_get_rtscts_rsvtime_le(priv, 2, |
24cdd90f | 559 | pkt_type, frame_size, current_rate); |
aadf7d13 | 560 | buf->rts_rrv_time_ba = vnt_get_rtscts_rsvtime_le(priv, 1, |
24cdd90f | 561 | pkt_type, frame_size, current_rate); |
aadf7d13 | 562 | buf->rts_rrv_time_bb = vnt_get_rtscts_rsvtime_le(priv, 0, |
24cdd90f MP |
563 | pkt_type, frame_size, current_rate); |
564 | ||
565 | buf->rrv_time_a = vnt_rxtx_rsvtime_le16(priv, pkt_type, frame_size, | |
566 | current_rate, need_ack); | |
567 | buf->rrv_time_b = vnt_rxtx_rsvtime_le16(priv, PK_TYPE_11B, frame_size, | |
568 | priv->byTopCCKBasicRate, need_ack); | |
569 | ||
4f06c0dc MP |
570 | if (need_mic) |
571 | head = &tx_head->tx_rts.tx.mic.head; | |
572 | ||
573 | if (tx_context->fb_option) | |
574 | return vnt_rxtx_rts_g_fb_head(tx_context, &head->rts_g_fb, | |
575 | pkt_type, frame_size, need_ack, current_rate); | |
576 | ||
577 | return vnt_rxtx_rts_g_head(tx_context, &head->rts_g, | |
578 | pkt_type, frame_size, need_ack, current_rate); | |
24cdd90f MP |
579 | } |
580 | ||
bf9c0118 MP |
581 | static u16 vnt_rxtx_cts(struct vnt_usb_send_context *tx_context, |
582 | union vnt_tx_head *tx_head, u8 pkt_type, u32 frame_size, | |
b00cb684 | 583 | int need_ack, u16 current_rate, bool need_mic) |
bf9c0118 MP |
584 | { |
585 | struct vnt_private *priv = tx_context->priv; | |
586 | struct vnt_rrv_time_cts *buf = &tx_head->tx_cts.cts; | |
b00cb684 MP |
587 | union vnt_tx_data_head *head = &tx_head->tx_cts.tx.head; |
588 | ||
bf9c0118 MP |
589 | |
590 | buf->rrv_time_a = vnt_rxtx_rsvtime_le16(priv, pkt_type, | |
591 | frame_size, current_rate, need_ack); | |
592 | buf->rrv_time_b = vnt_rxtx_rsvtime_le16(priv, PK_TYPE_11B, | |
593 | frame_size, priv->byTopCCKBasicRate, need_ack); | |
594 | ||
aadf7d13 | 595 | buf->cts_rrv_time_ba = vnt_get_rtscts_rsvtime_le(priv, 3, |
bf9c0118 MP |
596 | pkt_type, frame_size, current_rate); |
597 | ||
b00cb684 MP |
598 | if (need_mic) |
599 | head = &tx_head->tx_cts.tx.mic.head; | |
600 | ||
601 | /* Fill CTS */ | |
4f31668f | 602 | return vnt_fill_cts_head(tx_context, pkt_type, head, frame_size, |
b00cb684 | 603 | need_ack, current_rate); |
bf9c0118 MP |
604 | } |
605 | ||
3b03fea2 MP |
606 | static u16 vnt_rxtx_ab(struct vnt_usb_send_context *tx_context, |
607 | union vnt_tx_head *tx_head, u8 pkt_type, u32 frame_size, | |
681acf68 | 608 | int need_ack, u16 current_rate, bool need_rts, bool need_mic) |
3b03fea2 MP |
609 | { |
610 | struct vnt_private *priv = tx_context->priv; | |
611 | struct vnt_rrv_time_ab *buf = &tx_head->tx_ab.ab; | |
681acf68 | 612 | union vnt_tx_data_head *head = &tx_head->tx_ab.tx.head; |
3b03fea2 MP |
613 | |
614 | buf->rrv_time = vnt_rxtx_rsvtime_le16(priv, pkt_type, | |
615 | frame_size, current_rate, need_ack); | |
616 | ||
681acf68 MP |
617 | if (need_mic) |
618 | head = &tx_head->tx_ab.tx.mic.head; | |
619 | ||
3b03fea2 MP |
620 | if (need_rts) { |
621 | if (pkt_type == PK_TYPE_11B) | |
aadf7d13 | 622 | buf->rts_rrv_time = vnt_get_rtscts_rsvtime_le(priv, 0, |
3b03fea2 MP |
623 | pkt_type, frame_size, current_rate); |
624 | else /* PK_TYPE_11A */ | |
aadf7d13 | 625 | buf->rts_rrv_time = vnt_get_rtscts_rsvtime_le(priv, 2, |
3b03fea2 | 626 | pkt_type, frame_size, current_rate); |
681acf68 MP |
627 | |
628 | if (tx_context->fb_option && pkt_type == PK_TYPE_11A) | |
629 | return vnt_rxtx_rts_a_fb_head(tx_context, | |
630 | &head->rts_a_fb, pkt_type, frame_size, | |
631 | need_ack, current_rate); | |
632 | ||
633 | return vnt_rxtx_rts_ab_head(tx_context, &head->rts_ab, | |
634 | pkt_type, frame_size, need_ack, current_rate); | |
3b03fea2 MP |
635 | } |
636 | ||
681acf68 MP |
637 | if (pkt_type == PK_TYPE_11A) |
638 | return vnt_rxtx_datahead_a_fb(tx_context, pkt_type, | |
639 | current_rate, &head->data_head_a_fb, | |
640 | frame_size, need_ack); | |
641 | ||
642 | return vnt_rxtx_datahead_ab(tx_context, pkt_type, current_rate, | |
643 | &head->data_head_ab, frame_size, need_ack); | |
3b03fea2 MP |
644 | } |
645 | ||
9ec7f2d8 | 646 | static u16 vnt_generate_tx_parameter(struct vnt_usb_send_context *tx_context, |
165ac77a MP |
647 | u8 pkt_type, u16 current_rate, struct vnt_tx_buffer *tx_buffer, |
648 | struct vnt_mic_hdr **mic_hdr, u32 need_mic, u32 frame_size, | |
649 | int need_ack, bool need_rts) | |
92b96797 | 650 | { |
92b96797 | 651 | |
165ac77a | 652 | if (pkt_type == PK_TYPE_11GB || pkt_type == PK_TYPE_11GA) { |
92928f13 | 653 | if (need_rts) { |
4f06c0dc | 654 | if (need_mic) |
92928f13 MP |
655 | *mic_hdr = &tx_buffer-> |
656 | tx_head.tx_rts.tx.mic.hdr; | |
f0e0d505 | 657 | |
4f06c0dc | 658 | return vnt_rxtx_rts(tx_context, &tx_buffer->tx_head, |
165ac77a MP |
659 | pkt_type, frame_size, need_ack, |
660 | current_rate, need_mic); | |
92928f13 | 661 | } |
da9ef9f4 | 662 | |
681acf68 | 663 | if (need_mic) |
da9ef9f4 | 664 | *mic_hdr = &tx_buffer->tx_head.tx_cts.tx.mic.hdr; |
c12dca09 | 665 | |
165ac77a MP |
666 | return vnt_rxtx_cts(tx_context, &tx_buffer->tx_head, pkt_type, |
667 | frame_size, need_ack, current_rate, need_mic); | |
92928f13 | 668 | } |
0a0f4b69 | 669 | |
da9ef9f4 MP |
670 | if (need_mic) |
671 | *mic_hdr = &tx_buffer->tx_head.tx_ab.tx.mic.hdr; | |
672 | ||
165ac77a MP |
673 | return vnt_rxtx_ab(tx_context, &tx_buffer->tx_head, pkt_type, |
674 | frame_size, need_ack, current_rate, need_rts, need_mic); | |
92b96797 | 675 | } |
d38b13aa MP |
676 | |
677 | static void vnt_fill_txkey(struct vnt_usb_send_context *tx_context, | |
678 | u8 *key_buffer, struct ieee80211_key_conf *tx_key, struct sk_buff *skb, | |
679 | u16 payload_len, struct vnt_mic_hdr *mic_hdr) | |
680 | { | |
681 | struct ieee80211_hdr *hdr = tx_context->hdr; | |
682 | struct ieee80211_key_seq seq; | |
683 | u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb)); | |
684 | ||
685 | /* strip header and icv len from payload */ | |
686 | payload_len -= ieee80211_get_hdrlen_from_skb(skb); | |
687 | payload_len -= tx_key->icv_len; | |
688 | ||
689 | switch (tx_key->cipher) { | |
690 | case WLAN_CIPHER_SUITE_WEP40: | |
691 | case WLAN_CIPHER_SUITE_WEP104: | |
692 | memcpy(key_buffer, iv, 3); | |
693 | memcpy(key_buffer + 3, tx_key->key, tx_key->keylen); | |
694 | ||
695 | if (tx_key->keylen == WLAN_KEY_LEN_WEP40) { | |
696 | memcpy(key_buffer + 8, iv, 3); | |
697 | memcpy(key_buffer + 11, | |
698 | tx_key->key, WLAN_KEY_LEN_WEP40); | |
699 | } | |
700 | ||
701 | break; | |
702 | case WLAN_CIPHER_SUITE_TKIP: | |
703 | ieee80211_get_tkip_p2k(tx_key, skb, key_buffer); | |
704 | ||
705 | break; | |
706 | case WLAN_CIPHER_SUITE_CCMP: | |
707 | ||
708 | if (!mic_hdr) | |
709 | return; | |
710 | ||
711 | mic_hdr->id = 0x59; | |
712 | mic_hdr->payload_len = cpu_to_be16(payload_len); | |
713 | memcpy(mic_hdr->mic_addr2, hdr->addr2, ETH_ALEN); | |
714 | ||
715 | ieee80211_get_key_tx_seq(tx_key, &seq); | |
716 | ||
79f976dc | 717 | memcpy(mic_hdr->ccmp_pn, seq.ccmp.pn, IEEE80211_CCMP_PN_LEN); |
d38b13aa MP |
718 | |
719 | if (ieee80211_has_a4(hdr->frame_control)) | |
720 | mic_hdr->hlen = cpu_to_be16(28); | |
721 | else | |
722 | mic_hdr->hlen = cpu_to_be16(22); | |
723 | ||
724 | memcpy(mic_hdr->addr1, hdr->addr1, ETH_ALEN); | |
725 | memcpy(mic_hdr->addr2, hdr->addr2, ETH_ALEN); | |
726 | memcpy(mic_hdr->addr3, hdr->addr3, ETH_ALEN); | |
727 | ||
728 | mic_hdr->frame_control = cpu_to_le16( | |
729 | le16_to_cpu(hdr->frame_control) & 0xc78f); | |
730 | mic_hdr->seq_ctrl = cpu_to_le16( | |
731 | le16_to_cpu(hdr->seq_ctrl) & 0xf); | |
732 | ||
733 | if (ieee80211_has_a4(hdr->frame_control)) | |
734 | memcpy(mic_hdr->addr4, hdr->addr4, ETH_ALEN); | |
735 | ||
736 | ||
737 | memcpy(key_buffer, tx_key->key, WLAN_KEY_LEN_CCMP); | |
738 | ||
739 | break; | |
740 | default: | |
741 | break; | |
742 | } | |
743 | ||
744 | } | |
745 | ||
746 | int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) | |
747 | { | |
748 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | |
749 | struct ieee80211_tx_rate *tx_rate = &info->control.rates[0]; | |
750 | struct ieee80211_rate *rate; | |
751 | struct ieee80211_key_conf *tx_key; | |
752 | struct ieee80211_hdr *hdr; | |
753 | struct vnt_mic_hdr *mic_hdr = NULL; | |
754 | struct vnt_tx_buffer *tx_buffer; | |
755 | struct vnt_tx_fifo_head *tx_buffer_head; | |
756 | struct vnt_usb_send_context *tx_context; | |
757 | unsigned long flags; | |
758 | u32 frame_size = 0; | |
759 | u16 tx_bytes, tx_header_size, tx_body_size, current_rate, duration_id; | |
760 | u8 pkt_type, fb_option = AUTO_FB_NONE; | |
761 | bool need_rts = false, need_ack = false, is_pspoll = false; | |
762 | bool need_mic = false; | |
763 | ||
764 | hdr = (struct ieee80211_hdr *)(skb->data); | |
765 | ||
766 | rate = ieee80211_get_tx_rate(priv->hw, info); | |
767 | ||
768 | current_rate = rate->hw_value; | |
5091d963 MP |
769 | if (priv->wCurrentRate != current_rate && |
770 | !(priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { | |
d38b13aa MP |
771 | priv->wCurrentRate = current_rate; |
772 | bScheduleCommand(priv, WLAN_CMD_SETPOWER, NULL); | |
773 | } | |
774 | ||
775 | if (current_rate > RATE_11M) | |
776 | pkt_type = priv->byPacketType; | |
777 | else | |
778 | pkt_type = PK_TYPE_11B; | |
779 | ||
780 | spin_lock_irqsave(&priv->lock, flags); | |
781 | ||
a032b16c | 782 | tx_context = vnt_get_free_context(priv); |
d38b13aa MP |
783 | if (!tx_context) { |
784 | dev_dbg(&priv->usb->dev, "%s No free context\n", __func__); | |
785 | spin_unlock_irqrestore(&priv->lock, flags); | |
786 | return -ENOMEM; | |
787 | } | |
788 | ||
789 | tx_context->skb = skb; | |
790 | ||
791 | spin_unlock_irqrestore(&priv->lock, flags); | |
792 | ||
793 | tx_buffer = (struct vnt_tx_buffer *)tx_context->data; | |
794 | tx_buffer_head = &tx_buffer->fifo_head; | |
795 | tx_body_size = skb->len; | |
796 | ||
797 | frame_size = tx_body_size + 4; | |
798 | ||
d38b13aa MP |
799 | /*Set fifo controls */ |
800 | if (pkt_type == PK_TYPE_11A) | |
801 | tx_buffer_head->wFIFOCtl = 0; | |
802 | else if (pkt_type == PK_TYPE_11B) | |
803 | tx_buffer_head->wFIFOCtl = FIFOCTL_11B; | |
804 | else if (pkt_type == PK_TYPE_11GB) | |
805 | tx_buffer_head->wFIFOCtl = FIFOCTL_11GB; | |
806 | else if (pkt_type == PK_TYPE_11GA) | |
807 | tx_buffer_head->wFIFOCtl = FIFOCTL_11GA; | |
808 | ||
809 | if (!ieee80211_is_data(hdr->frame_control)) { | |
810 | tx_buffer_head->wFIFOCtl |= (FIFOCTL_GENINT | | |
811 | FIFOCTL_ISDMA0); | |
812 | tx_buffer_head->wFIFOCtl |= FIFOCTL_TMOEN; | |
813 | ||
814 | tx_buffer_head->time_stamp = | |
815 | cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us); | |
816 | } else { | |
817 | tx_buffer_head->time_stamp = | |
818 | cpu_to_le16(DEFAULT_MSDU_LIFETIME_RES_64us); | |
819 | } | |
820 | ||
821 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { | |
822 | tx_buffer_head->wFIFOCtl |= FIFOCTL_NEEDACK; | |
823 | need_ack = true; | |
824 | } | |
825 | ||
826 | if (ieee80211_has_retry(hdr->frame_control)) | |
827 | tx_buffer_head->wFIFOCtl |= FIFOCTL_LRETRY; | |
828 | ||
829 | if (tx_rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) | |
830 | priv->byPreambleType = PREAMBLE_SHORT; | |
831 | else | |
832 | priv->byPreambleType = PREAMBLE_LONG; | |
833 | ||
834 | if (tx_rate->flags & IEEE80211_TX_RC_USE_RTS_CTS) { | |
835 | need_rts = true; | |
836 | tx_buffer_head->wFIFOCtl |= FIFOCTL_RTS; | |
837 | } | |
838 | ||
839 | if (ieee80211_has_a4(hdr->frame_control)) | |
840 | tx_buffer_head->wFIFOCtl |= FIFOCTL_LHEAD; | |
841 | ||
842 | if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER) | |
843 | is_pspoll = true; | |
844 | ||
5deb1cfa MP |
845 | tx_buffer_head->frag_ctl = |
846 | cpu_to_le16(ieee80211_get_hdrlen_from_skb(skb) << 10); | |
d38b13aa MP |
847 | |
848 | if (info->control.hw_key) { | |
849 | tx_key = info->control.hw_key; | |
850 | switch (info->control.hw_key->cipher) { | |
851 | case WLAN_CIPHER_SUITE_WEP40: | |
852 | case WLAN_CIPHER_SUITE_WEP104: | |
5deb1cfa | 853 | tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_LEGACY); |
d38b13aa MP |
854 | break; |
855 | case WLAN_CIPHER_SUITE_TKIP: | |
5deb1cfa | 856 | tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_TKIP); |
d38b13aa MP |
857 | break; |
858 | case WLAN_CIPHER_SUITE_CCMP: | |
5deb1cfa | 859 | tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_AES); |
d38b13aa MP |
860 | need_mic = true; |
861 | default: | |
862 | break; | |
863 | } | |
864 | frame_size += tx_key->icv_len; | |
865 | } | |
866 | ||
cb8ee9de MP |
867 | tx_buffer_head->current_rate = cpu_to_le16(current_rate); |
868 | ||
d38b13aa MP |
869 | /* legacy rates TODO use ieee80211_tx_rate */ |
870 | if (current_rate >= RATE_18M && ieee80211_is_data(hdr->frame_control)) { | |
871 | if (priv->byAutoFBCtrl == AUTO_FB_0) { | |
872 | tx_buffer_head->wFIFOCtl |= FIFOCTL_AUTO_FB_0; | |
873 | ||
874 | priv->tx_rate_fb0 = | |
e3f31874 | 875 | vnt_fb_opt0[FB_RATE0][current_rate - RATE_18M]; |
d38b13aa | 876 | priv->tx_rate_fb1 = |
e3f31874 | 877 | vnt_fb_opt0[FB_RATE1][current_rate - RATE_18M]; |
d38b13aa MP |
878 | |
879 | fb_option = AUTO_FB_0; | |
880 | } else if (priv->byAutoFBCtrl == AUTO_FB_1) { | |
881 | tx_buffer_head->wFIFOCtl |= FIFOCTL_AUTO_FB_1; | |
882 | ||
883 | priv->tx_rate_fb0 = | |
2331ba42 | 884 | vnt_fb_opt1[FB_RATE0][current_rate - RATE_18M]; |
d38b13aa | 885 | priv->tx_rate_fb1 = |
2331ba42 | 886 | vnt_fb_opt1[FB_RATE1][current_rate - RATE_18M]; |
d38b13aa MP |
887 | |
888 | fb_option = AUTO_FB_1; | |
889 | } | |
890 | } | |
891 | ||
71d764ae MP |
892 | tx_context->fb_option = fb_option; |
893 | ||
9ec7f2d8 MP |
894 | duration_id = vnt_generate_tx_parameter(tx_context, pkt_type, |
895 | current_rate, tx_buffer, &mic_hdr, need_mic, frame_size, | |
72bf8059 | 896 | need_ack, need_rts); |
d38b13aa MP |
897 | |
898 | tx_header_size = tx_context->tx_hdr_size; | |
899 | if (!tx_header_size) { | |
900 | tx_context->in_use = false; | |
901 | return -ENOMEM; | |
902 | } | |
903 | ||
5deb1cfa | 904 | tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_NONFRAG); |
d38b13aa MP |
905 | |
906 | tx_bytes = tx_header_size + tx_body_size; | |
907 | ||
908 | memcpy(tx_context->hdr, skb->data, tx_body_size); | |
909 | ||
910 | hdr->duration_id = cpu_to_le16(duration_id); | |
911 | ||
912 | if (info->control.hw_key) { | |
913 | tx_key = info->control.hw_key; | |
914 | if (tx_key->keylen > 0) | |
915 | vnt_fill_txkey(tx_context, tx_buffer_head->tx_key, | |
916 | tx_key, skb, tx_body_size, mic_hdr); | |
917 | } | |
918 | ||
919 | priv->wSeqCounter = (le16_to_cpu(hdr->seq_ctrl) & | |
920 | IEEE80211_SCTL_SEQ) >> 4; | |
921 | ||
922 | tx_buffer->tx_byte_count = cpu_to_le16(tx_bytes); | |
71d764ae | 923 | tx_buffer->byPKTNO = tx_context->pkt_no; |
d38b13aa MP |
924 | tx_buffer->byType = 0x00; |
925 | ||
926 | tx_bytes += 4; | |
927 | ||
928 | tx_context->type = CONTEXT_DATA_PACKET; | |
929 | tx_context->buf_len = tx_bytes; | |
930 | ||
931 | spin_lock_irqsave(&priv->lock, flags); | |
932 | ||
933 | if (PIPEnsSendBulkOut(priv, tx_context) != STATUS_PENDING) { | |
934 | spin_unlock_irqrestore(&priv->lock, flags); | |
935 | return -EIO; | |
936 | } | |
937 | ||
938 | spin_unlock_irqrestore(&priv->lock, flags); | |
939 | ||
940 | return 0; | |
941 | } | |
942 | ||
943 | static int vnt_beacon_xmit(struct vnt_private *priv, | |
944 | struct sk_buff *skb) | |
945 | { | |
946 | struct vnt_beacon_buffer *beacon_buffer; | |
947 | struct vnt_tx_short_buf_head *short_head; | |
948 | struct ieee80211_tx_info *info; | |
949 | struct vnt_usb_send_context *context; | |
950 | struct ieee80211_mgmt *mgmt_hdr; | |
951 | unsigned long flags; | |
952 | u32 frame_size = skb->len + 4; | |
953 | u16 current_rate, count; | |
954 | ||
955 | spin_lock_irqsave(&priv->lock, flags); | |
956 | ||
a032b16c | 957 | context = vnt_get_free_context(priv); |
d38b13aa MP |
958 | if (!context) { |
959 | dev_dbg(&priv->usb->dev, "%s No free context!\n", __func__); | |
960 | spin_unlock_irqrestore(&priv->lock, flags); | |
961 | return -ENOMEM; | |
962 | } | |
963 | ||
964 | context->skb = skb; | |
965 | ||
966 | spin_unlock_irqrestore(&priv->lock, flags); | |
967 | ||
968 | beacon_buffer = (struct vnt_beacon_buffer *)&context->data[0]; | |
969 | short_head = &beacon_buffer->short_head; | |
970 | ||
971 | if (priv->byBBType == BB_TYPE_11A) { | |
972 | current_rate = RATE_6M; | |
973 | ||
974 | /* Get SignalField,ServiceField,Length */ | |
975 | vnt_get_phy_field(priv, frame_size, current_rate, | |
976 | PK_TYPE_11A, &short_head->ab); | |
977 | ||
978 | /* Get Duration and TimeStampOff */ | |
435ae3be | 979 | short_head->duration = vnt_get_duration_le(priv, |
d38b13aa MP |
980 | PK_TYPE_11A, false); |
981 | short_head->time_stamp_off = | |
982 | vnt_time_stamp_off(priv, current_rate); | |
983 | } else { | |
984 | current_rate = RATE_1M; | |
985 | short_head->fifo_ctl |= FIFOCTL_11B; | |
986 | ||
987 | /* Get SignalField,ServiceField,Length */ | |
988 | vnt_get_phy_field(priv, frame_size, current_rate, | |
989 | PK_TYPE_11B, &short_head->ab); | |
990 | ||
991 | /* Get Duration and TimeStampOff */ | |
435ae3be | 992 | short_head->duration = vnt_get_duration_le(priv, |
d38b13aa MP |
993 | PK_TYPE_11B, false); |
994 | short_head->time_stamp_off = | |
995 | vnt_time_stamp_off(priv, current_rate); | |
996 | } | |
997 | ||
998 | /* Generate Beacon Header */ | |
999 | mgmt_hdr = &beacon_buffer->mgmt_hdr; | |
1000 | memcpy(mgmt_hdr, skb->data, skb->len); | |
1001 | ||
1002 | /* time stamp always 0 */ | |
1003 | mgmt_hdr->u.beacon.timestamp = 0; | |
1004 | ||
1005 | info = IEEE80211_SKB_CB(skb); | |
1006 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | |
1007 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)mgmt_hdr; | |
1008 | hdr->duration_id = 0; | |
1009 | hdr->seq_ctrl = cpu_to_le16(priv->wSeqCounter << 4); | |
1010 | } | |
1011 | ||
1012 | priv->wSeqCounter++; | |
1013 | if (priv->wSeqCounter > 0x0fff) | |
1014 | priv->wSeqCounter = 0; | |
1015 | ||
1016 | count = sizeof(struct vnt_tx_short_buf_head) + skb->len; | |
1017 | ||
1018 | beacon_buffer->tx_byte_count = cpu_to_le16(count); | |
71d764ae | 1019 | beacon_buffer->byPKTNO = context->pkt_no; |
d38b13aa MP |
1020 | beacon_buffer->byType = 0x01; |
1021 | ||
1022 | context->type = CONTEXT_BEACON_PACKET; | |
1023 | context->buf_len = count + 4; /* USB header */ | |
1024 | ||
1025 | spin_lock_irqsave(&priv->lock, flags); | |
1026 | ||
1027 | if (PIPEnsSendBulkOut(priv, context) != STATUS_PENDING) | |
1028 | ieee80211_free_txskb(priv->hw, context->skb); | |
1029 | ||
1030 | spin_unlock_irqrestore(&priv->lock, flags); | |
1031 | ||
1032 | return 0; | |
1033 | } | |
1034 | ||
1035 | int vnt_beacon_make(struct vnt_private *priv, struct ieee80211_vif *vif) | |
1036 | { | |
1037 | struct sk_buff *beacon; | |
1038 | ||
1039 | beacon = ieee80211_beacon_get(priv->hw, vif); | |
1040 | if (!beacon) | |
1041 | return -ENOMEM; | |
1042 | ||
1043 | if (vnt_beacon_xmit(priv, beacon)) { | |
1044 | ieee80211_free_txskb(priv->hw, beacon); | |
1045 | return -ENODEV; | |
1046 | } | |
1047 | ||
1048 | return 0; | |
1049 | } | |
1050 | ||
1051 | int vnt_beacon_enable(struct vnt_private *priv, struct ieee80211_vif *vif, | |
1052 | struct ieee80211_bss_conf *conf) | |
1053 | { | |
1054 | int ret; | |
1055 | ||
1056 | vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX); | |
1057 | ||
1058 | vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); | |
1059 | ||
1060 | vnt_mac_set_beacon_interval(priv, conf->beacon_int); | |
1061 | ||
1062 | vnt_clear_current_tsf(priv); | |
1063 | ||
1064 | vnt_mac_reg_bits_on(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); | |
1065 | ||
1066 | vnt_reset_next_tbtt(priv, conf->beacon_int); | |
1067 | ||
1068 | ret = vnt_beacon_make(priv, vif); | |
1069 | ||
1070 | return ret; | |
1071 | } |