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