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