aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/rtl8712/rtl871x_xmit.c
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2010-08-20 11:15:30 -0400
committerLarry Finger <Larry.Finger@lwfinger.net>2010-08-20 11:15:30 -0400
commit2865d42c78a9121caad52cb02d1fbb7f5cdbc4ef (patch)
tree430b79f753b0e1cec6379b9a4208a716c914ac65 /drivers/staging/rtl8712/rtl871x_xmit.c
parent763008c4357b73c8d18396dfd8d79dc58fa3f99d (diff)
staging: r8712u: Add the new driver to the mainline kernel
This code is for a completely new version of the Realtek 8192 USB devices such as the D-Link DWA-130. The Realtek code, which was originally for Linux, Windows XP and Windows CE, has been stripped of all code not needed for Linux. In addition, only one additional configuration variable, which enables AP mode, remains. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: Florian Schilhabel <florian.c.schilhabel@googlemail.com> Tested-by: Frederic Leroy <fredo@starox.org>
Diffstat (limited to 'drivers/staging/rtl8712/rtl871x_xmit.c')
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c1052
1 files changed, 1052 insertions, 0 deletions
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
new file mode 100644
index 00000000000..b8195e3a72d
--- /dev/null
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -0,0 +1,1052 @@
1/******************************************************************************
2 * rtl871x_xmit.c
3 *
4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
5 * Linux device driver for RTL8192SU
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 *
20 * Modifications for inclusion into the Linux staging tree are
21 * Copyright(c) 2010 Larry Finger. All rights reserved.
22 *
23 * Contact information:
24 * WLAN FAE <wlanfae@realtek.com>
25 * Larry Finger <Larry.Finger@lwfinger.net>
26 *
27 ******************************************************************************/
28
29#define _RTL871X_XMIT_C_
30
31#include "osdep_service.h"
32#include "drv_types.h"
33#include "rtl871x_byteorder.h"
34#include "wifi.h"
35#include "osdep_intf.h"
36#include "usb_ops.h"
37
38
39static const u8 P802_1H_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0xf8};
40static const u8 RFC1042_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0x00};
41static void init_hwxmits(struct hw_xmit *phwxmit, sint entry);
42static void alloc_hwxmits(struct _adapter *padapter);
43static void free_hwxmits(struct _adapter *padapter);
44
45static void _init_txservq(struct tx_servq *ptxservq)
46{
47 _init_listhead(&ptxservq->tx_pending);
48 _init_queue(&ptxservq->sta_pending);
49 ptxservq->qcnt = 0;
50}
51
52void _r8712_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv)
53{
54 memset((unsigned char *)psta_xmitpriv, 0,
55 sizeof(struct sta_xmit_priv));
56 spin_lock_init(&psta_xmitpriv->lock);
57 _init_txservq(&psta_xmitpriv->be_q);
58 _init_txservq(&psta_xmitpriv->bk_q);
59 _init_txservq(&psta_xmitpriv->vi_q);
60 _init_txservq(&psta_xmitpriv->vo_q);
61 _init_listhead(&psta_xmitpriv->legacy_dz);
62 _init_listhead(&psta_xmitpriv->apsd);
63}
64
65sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
66 struct _adapter *padapter)
67{
68 sint i;
69 struct xmit_buf *pxmitbuf;
70 struct xmit_frame *pxframe;
71
72 memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv));
73 spin_lock_init(&pxmitpriv->lock);
74 sema_init(&pxmitpriv->xmit_sema, 0);
75 sema_init(&pxmitpriv->terminate_xmitthread_sema, 0);
76 /*
77 Please insert all the queue initializaiton using _init_queue below
78 */
79 pxmitpriv->adapter = padapter;
80 _init_queue(&pxmitpriv->be_pending);
81 _init_queue(&pxmitpriv->bk_pending);
82 _init_queue(&pxmitpriv->vi_pending);
83 _init_queue(&pxmitpriv->vo_pending);
84 _init_queue(&pxmitpriv->bm_pending);
85 _init_queue(&pxmitpriv->legacy_dz_queue);
86 _init_queue(&pxmitpriv->apsd_queue);
87 _init_queue(&pxmitpriv->free_xmit_queue);
88 /*
89 Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME,
90 and initialize free_xmit_frame below.
91 Please also apply free_txobj to link_up all the xmit_frames...
92 */
93 pxmitpriv->pallocated_frame_buf = _malloc(NR_XMITFRAME *
94 sizeof(struct xmit_frame) + 4);
95 if (pxmitpriv->pallocated_frame_buf == NULL) {
96 pxmitpriv->pxmit_frame_buf = NULL;
97 return _FAIL;
98 }
99 pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 -
100 ((addr_t) (pxmitpriv->pallocated_frame_buf) & 3);
101 pxframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf;
102 for (i = 0; i < NR_XMITFRAME; i++) {
103 _init_listhead(&(pxframe->list));
104 pxframe->padapter = padapter;
105 pxframe->frame_tag = DATA_FRAMETAG;
106 pxframe->pkt = NULL;
107 pxframe->buf_addr = NULL;
108 pxframe->pxmitbuf = NULL;
109 list_insert_tail(&(pxframe->list),
110 &(pxmitpriv->free_xmit_queue.queue));
111 pxframe++;
112 }
113 pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME;
114 /*
115 init xmit hw_txqueue
116 */
117 _r8712_init_hw_txqueue(&pxmitpriv->be_txqueue, BE_QUEUE_INX);
118 _r8712_init_hw_txqueue(&pxmitpriv->bk_txqueue, BK_QUEUE_INX);
119 _r8712_init_hw_txqueue(&pxmitpriv->vi_txqueue, VI_QUEUE_INX);
120 _r8712_init_hw_txqueue(&pxmitpriv->vo_txqueue, VO_QUEUE_INX);
121 _r8712_init_hw_txqueue(&pxmitpriv->bmc_txqueue, BMC_QUEUE_INX);
122 pxmitpriv->frag_len = MAX_FRAG_THRESHOLD;
123 pxmitpriv->txirp_cnt = 1;
124 sema_init(&(pxmitpriv->tx_retevt), 0);
125 /*per AC pending irp*/
126 pxmitpriv->beq_cnt = 0;
127 pxmitpriv->bkq_cnt = 0;
128 pxmitpriv->viq_cnt = 0;
129 pxmitpriv->voq_cnt = 0;
130 /*init xmit_buf*/
131 _init_queue(&pxmitpriv->free_xmitbuf_queue);
132 _init_queue(&pxmitpriv->pending_xmitbuf_queue);
133 pxmitpriv->pallocated_xmitbuf = _malloc(NR_XMITBUFF *
134 sizeof(struct xmit_buf) + 4);
135 if (pxmitpriv->pallocated_xmitbuf == NULL)
136 return _FAIL;
137 pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 -
138 ((addr_t)(pxmitpriv->pallocated_xmitbuf) & 3);
139 pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
140 for (i = 0; i < NR_XMITBUFF; i++) {
141 _init_listhead(&pxmitbuf->list);
142 pxmitbuf->pallocated_buf = _malloc(MAX_XMITBUF_SZ +
143 XMITBUF_ALIGN_SZ);
144 if (pxmitbuf->pallocated_buf == NULL)
145 return _FAIL;
146 pxmitbuf->pbuf = pxmitbuf->pallocated_buf + XMITBUF_ALIGN_SZ -
147 ((addr_t) (pxmitbuf->pallocated_buf) &
148 (XMITBUF_ALIGN_SZ - 1));
149 r8712_xmit_resource_alloc(padapter, pxmitbuf);
150 list_insert_tail(&pxmitbuf->list,
151 &(pxmitpriv->free_xmitbuf_queue.queue));
152 pxmitbuf++;
153 }
154 pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF;
155 alloc_hwxmits(padapter);
156 init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
157 tasklet_init(&pxmitpriv->xmit_tasklet,
158 (void(*)(addr_t))r8712_xmit_bh,
159 (addr_t)padapter);
160 return _SUCCESS;
161}
162
163void _free_xmit_priv(struct xmit_priv *pxmitpriv)
164{
165 int i;
166 struct _adapter *padapter = pxmitpriv->adapter;
167 struct xmit_frame *pxmitframe = (struct xmit_frame *)
168 pxmitpriv->pxmit_frame_buf;
169 struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
170
171 if (pxmitpriv->pxmit_frame_buf == NULL)
172 return;
173 for (i = 0; i < NR_XMITFRAME; i++) {
174 r8712_xmit_complete(padapter, pxmitframe);
175 pxmitframe++;
176 }
177 for (i = 0; i < NR_XMITBUFF; i++) {
178 r8712_xmit_resource_free(padapter, pxmitbuf);
179 kfree(pxmitbuf->pallocated_buf);
180 pxmitbuf++;
181 }
182 kfree(pxmitpriv->pallocated_frame_buf);
183 kfree(pxmitpriv->pallocated_xmitbuf);
184 free_hwxmits(padapter);
185}
186
187sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
188 struct pkt_attrib *pattrib)
189{
190 uint i;
191 struct pkt_file pktfile;
192 struct sta_info *psta = NULL;
193 struct ethhdr etherhdr;
194
195 struct tx_cmd txdesc;
196
197 sint bmcast;
198 struct sta_priv *pstapriv = &padapter->stapriv;
199 struct security_priv *psecuritypriv = &padapter->securitypriv;
200 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
201 struct qos_priv *pqospriv = &pmlmepriv->qospriv;
202
203 _r8712_open_pktfile(pkt, &pktfile);
204
205 i = _r8712_pktfile_read(&pktfile, (unsigned char *)&etherhdr, ETH_HLEN);
206
207 pattrib->ether_type = ntohs(etherhdr.h_proto);
208
209{
210 u8 bool;
211 /*If driver xmit ARP packet, driver can set ps mode to initial
212 * setting. It stands for getting DHCP or fix IP.*/
213 if (pattrib->ether_type == 0x0806) {
214 if (padapter->pwrctrlpriv.pwr_mode !=
215 padapter->registrypriv.power_mgnt) {
216 _cancel_timer(&(pmlmepriv->dhcp_timer), &bool);
217 r8712_set_ps_mode(padapter, padapter->registrypriv.
218 power_mgnt, padapter->registrypriv.smart_ps);
219 }
220 }
221}
222 memcpy(pattrib->dst, &etherhdr.h_dest, ETH_ALEN);
223 memcpy(pattrib->src, &etherhdr.h_source, ETH_ALEN);
224 pattrib->pctrl = 0;
225 if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ||
226 (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
227 memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
228 memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
229 } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
230 memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN);
231 memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
232 } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
233 memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
234 memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN);
235 } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) {
236 /*firstly, filter packet not belongs to mp*/
237 if (pattrib->ether_type != 0x8712)
238 return _FAIL;
239 /* for mp storing the txcmd per packet,
240 * according to the info of txcmd to update pattrib */
241 /*get MP_TXDESC_SIZE bytes txcmd per packet*/
242 i = _r8712_pktfile_read(&pktfile, (u8 *)&txdesc, TXDESC_SIZE);
243 memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
244 memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
245 pattrib->pctrl = 1;
246 }
247 /* r8712_xmitframe_coalesce() overwrite this!*/
248 pattrib->pktlen = pktfile.pkt_len;
249 if (ETH_P_IP == pattrib->ether_type) {
250 /* The following is for DHCP and ARP packet, we use cck1M to
251 * tx these packets and let LPS awake some time
252 * to prevent DHCP protocol fail */
253 u8 tmp[24];
254 _r8712_pktfile_read(&pktfile, &tmp[0], 24);
255 pattrib->dhcp_pkt = 0;
256 if (pktfile.pkt_len > 282) {/*MINIMUM_DHCP_PACKET_SIZE)*/
257 if (ETH_P_IP == pattrib->ether_type) {/* IP header*/
258 if (((tmp[21] == 68) && (tmp[23] == 67)) ||
259 ((tmp[21] == 67) && (tmp[23] == 68))) {
260 /* 68 : UDP BOOTP client
261 * 67 : UDP BOOTP server
262 * Use low rate to send DHCP packet.*/
263 pattrib->dhcp_pkt = 1;
264 }
265 }
266 }
267 }
268 bmcast = IS_MCAST(pattrib->ra);
269 /* get sta_info*/
270 if (bmcast) {
271 psta = r8712_get_bcmc_stainfo(padapter);
272 pattrib->mac_id = 4;
273 } else {
274 if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) {
275 psta = r8712_get_stainfo(pstapriv,
276 get_bssid(pmlmepriv));
277 pattrib->mac_id = 5;
278 } else {
279 psta = r8712_get_stainfo(pstapriv, pattrib->ra);
280 if (psta == NULL) /* drop the pkt */
281 return _FAIL;
282 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
283 pattrib->mac_id = 5;
284 else
285 pattrib->mac_id = psta->mac_id;
286 }
287 }
288
289 if (psta) {
290 pattrib->psta = psta;
291 } else {
292 /* if we cannot get psta => drrp the pkt */
293 return _FAIL;
294 }
295
296 pattrib->ack_policy = 0;
297 /* get ether_hdr_len */
298 pattrib->pkt_hdrlen = ETH_HLEN;
299
300 if (pqospriv->qos_option)
301 r8712_set_qos(&pktfile, pattrib);
302 else {
303 pattrib->hdrlen = WLAN_HDR_A3_LEN;
304 pattrib->subtype = WIFI_DATA_TYPE;
305 pattrib->priority = 0;
306 }
307 if (psta->ieee8021x_blocked == true) {
308 pattrib->encrypt = 0;
309 if ((pattrib->ether_type != 0x888e) &&
310 (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false))
311 return _FAIL;
312 } else
313 GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast);
314 switch (pattrib->encrypt) {
315 case _WEP40_:
316 case _WEP104_:
317 pattrib->iv_len = 4;
318 pattrib->icv_len = 4;
319 break;
320 case _TKIP_:
321 pattrib->iv_len = 8;
322 pattrib->icv_len = 4;
323 if (padapter->securitypriv.busetkipkey == _FAIL)
324 return _FAIL;
325 break;
326 case _AES_:
327 pattrib->iv_len = 8;
328 pattrib->icv_len = 8;
329 break;
330 default:
331 pattrib->iv_len = 0;
332 pattrib->icv_len = 0;
333 break;
334 }
335
336 if (pattrib->encrypt &&
337 ((padapter->securitypriv.sw_encrypt == true) ||
338 (psecuritypriv->hw_decrypted == false)))
339 pattrib->bswenc = true;
340 else
341 pattrib->bswenc = false;
342 /* if in MP_STATE, update pkt_attrib from mp_txcmd, and overwrite
343 * some settings above.*/
344 if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)
345 pattrib->priority = (txdesc.txdw1 >> QSEL_SHT) & 0x1f;
346 return _SUCCESS;
347}
348
349static sint xmitframe_addmic(struct _adapter *padapter,
350 struct xmit_frame *pxmitframe)
351{
352 u32 curfragnum, length, datalen;
353 u8 *pframe, *payload, mic[8];
354 struct mic_data micdata;
355 struct sta_info *stainfo;
356 struct qos_priv *pqospriv = &(padapter->mlmepriv.qospriv);
357 struct pkt_attrib *pattrib = &pxmitframe->attrib;
358 struct security_priv *psecuritypriv = &padapter->securitypriv;
359 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
360 u8 priority[4] = {0x0, 0x0, 0x0, 0x0};
361 sint bmcst = IS_MCAST(pattrib->ra);
362
363 if (pattrib->psta)
364 stainfo = pattrib->psta;
365 else
366 stainfo = r8712_get_stainfo(&padapter->stapriv,
367 &pattrib->ra[0]);
368 if (pattrib->encrypt == _TKIP_) {
369 /*encode mic code*/
370 if (stainfo != NULL) {
371 u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
372 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
373 0x0, 0x0};
374 datalen = pattrib->pktlen - pattrib->hdrlen;
375 pframe = pxmitframe->buf_addr + TXDESC_OFFSET;;
376 if (bmcst) {
377 if (!memcmp(psecuritypriv->XGrptxmickey
378 [psecuritypriv->XGrpKeyid].skey,
379 null_key, 16))
380 return _FAIL;
381 /*start to calculate the mic code*/
382 r8712_secmicsetkey(&micdata,
383 psecuritypriv->
384 XGrptxmickey[psecuritypriv->
385 XGrpKeyid].skey);
386 } else {
387 if (!memcmp(&stainfo->tkiptxmickey.skey[0],
388 null_key, 16))
389 return _FAIL;
390 /* start to calculate the mic code */
391 r8712_secmicsetkey(&micdata,
392 &stainfo->tkiptxmickey.skey[0]);
393 }
394 if (pframe[1] & 1) { /* ToDS==1 */
395 r8712_secmicappend(&micdata,
396 &pframe[16], 6); /*DA*/
397 if (pframe[1]&2) /* From Ds==1 */
398 r8712_secmicappend(&micdata,
399 &pframe[24], 6);
400 else
401 r8712_secmicappend(&micdata,
402 &pframe[10], 6);
403 } else { /* ToDS==0 */
404 r8712_secmicappend(&micdata,
405 &pframe[4], 6); /* DA */
406 if (pframe[1]&2) /* From Ds==1 */
407 r8712_secmicappend(&micdata,
408 &pframe[16], 6);
409 else
410 r8712_secmicappend(&micdata,
411 &pframe[10], 6);
412 }
413 if (pqospriv->qos_option == 1)
414 priority[0] = (u8)pxmitframe->
415 attrib.priority;
416 r8712_secmicappend(&micdata, &priority[0], 4);
417 payload = pframe;
418 for (curfragnum = 0; curfragnum < pattrib->nr_frags;
419 curfragnum++) {
420 payload = (u8 *)RND4((addr_t)(payload));
421 payload = payload+pattrib->
422 hdrlen+pattrib->iv_len;
423 if ((curfragnum + 1) == pattrib->nr_frags) {
424 length = pattrib->last_txcmdsz -
425 pattrib->hdrlen -
426 pattrib->iv_len -
427 ((psecuritypriv->sw_encrypt)
428 ? pattrib->icv_len : 0);
429 r8712_secmicappend(&micdata, payload,
430 length);
431 payload = payload+length;
432 } else{
433 length = pxmitpriv->frag_len -
434 pattrib->hdrlen-pattrib->iv_len -
435 ((psecuritypriv->sw_encrypt) ?
436 pattrib->icv_len : 0);
437 r8712_secmicappend(&micdata, payload,
438 length);
439 payload = payload + length +
440 pattrib->icv_len;
441 }
442 }
443 r8712_secgetmic(&micdata, &(mic[0]));
444 /* add mic code and add the mic code length in
445 * last_txcmdsz */
446 memcpy(payload, &(mic[0]), 8);
447 pattrib->last_txcmdsz += 8;
448 payload = payload-pattrib->last_txcmdsz + 8;
449 }
450 }
451 return _SUCCESS;
452}
453
454static sint xmitframe_swencrypt(struct _adapter *padapter,
455 struct xmit_frame *pxmitframe)
456{
457 struct pkt_attrib *pattrib = &pxmitframe->attrib;
458
459 if (pattrib->bswenc) {
460 switch (pattrib->encrypt) {
461 case _WEP40_:
462 case _WEP104_:
463 r8712_wep_encrypt(padapter, (u8 *)pxmitframe);
464 break;
465 case _TKIP_:
466 r8712_tkip_encrypt(padapter, (u8 *)pxmitframe);
467 break;
468 case _AES_:
469 r8712_aes_encrypt(padapter, (u8 *)pxmitframe);
470 break;
471 default:
472 break;
473 }
474 }
475 return _SUCCESS;
476}
477
478static sint make_wlanhdr(struct _adapter *padapter , u8 *hdr,
479 struct pkt_attrib *pattrib)
480{
481 u16 *qc;
482
483 struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr;
484 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
485 struct qos_priv *pqospriv = &pmlmepriv->qospriv;
486 u16 *fctrl = &pwlanhdr->frame_ctl;
487 memset(hdr, 0, WLANHDR_OFFSET);
488 SetFrameSubType(fctrl, pattrib->subtype);
489 if (pattrib->subtype & WIFI_DATA_TYPE) {
490 if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)) {
491 /* to_ds = 1, fr_ds = 0; */
492 SetToDs(fctrl);
493 memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv),
494 ETH_ALEN);
495 memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
496 memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN);
497 } else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)) {
498 /* to_ds = 0, fr_ds = 1; */
499 SetFrDs(fctrl);
500 memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
501 memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv),
502 ETH_ALEN);
503 memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN);
504 } else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)
505 || (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)
506 == true)) {
507 memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
508 memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
509 memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv),
510 ETH_ALEN);
511 } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) {
512 memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
513 memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
514 memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv),
515 ETH_ALEN);
516 } else
517 return _FAIL;
518
519 if (pattrib->encrypt)
520 SetPrivacy(fctrl);
521 if (pqospriv->qos_option) {
522 qc = (unsigned short *)(hdr + pattrib->hdrlen - 2);
523 if (pattrib->priority)
524 SetPriority(qc, pattrib->priority);
525 SetAckpolicy(qc, pattrib->ack_policy);
526 }
527 /* TODO: fill HT Control Field */
528 /* Update Seq Num will be handled by f/w */
529 {
530 struct sta_info *psta;
531
532 sint bmcst = IS_MCAST(pattrib->ra);
533 if (pattrib->psta)
534 psta = pattrib->psta;
535 else {
536 if (bmcst)
537 psta = r8712_get_bcmc_stainfo(padapter);
538 else
539 psta =
540 r8712_get_stainfo(&padapter->stapriv,
541 pattrib->ra);
542 }
543 if (psta) {
544 psta->sta_xmitpriv.txseq_tid
545 [pattrib->priority]++;
546 psta->sta_xmitpriv.txseq_tid[pattrib->priority]
547 &= 0xFFF;
548 pattrib->seqnum = psta->sta_xmitpriv.
549 txseq_tid[pattrib->priority];
550 SetSeqNum(hdr, pattrib->seqnum);
551 }
552 }
553 }
554 return _SUCCESS;
555}
556
557static sint r8712_put_snap(u8 *data, u16 h_proto)
558{
559 struct ieee80211_snap_hdr *snap;
560 const u8 *oui;
561
562 snap = (struct ieee80211_snap_hdr *)data;
563 snap->dsap = 0xaa;
564 snap->ssap = 0xaa;
565 snap->ctrl = 0x03;
566 if (h_proto == 0x8137 || h_proto == 0x80f3)
567 oui = P802_1H_OUI;
568 else
569 oui = RFC1042_OUI;
570 snap->oui[0] = oui[0];
571 snap->oui[1] = oui[1];
572 snap->oui[2] = oui[2];
573 *(u16 *)(data + SNAP_SIZE) = htons(h_proto);
574 return SNAP_SIZE + sizeof(u16);
575}
576
577/*
578 * This sub-routine will perform all the following:
579 * 1. remove 802.3 header.
580 * 2. create wlan_header, based on the info in pxmitframe
581 * 3. append sta's iv/ext-iv
582 * 4. append LLC
583 * 5. move frag chunk from pframe to pxmitframe->mem
584 * 6. apply sw-encrypt, if necessary.
585 */
586sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt,
587 struct xmit_frame *pxmitframe)
588{
589 struct pkt_file pktfile;
590
591 sint frg_len, mpdu_len, llc_sz;
592 u32 mem_sz;
593 u8 frg_inx;
594 addr_t addr;
595 u8 *pframe, *mem_start, *ptxdesc;
596 struct sta_info *psta;
597 struct security_priv *psecuritypriv = &padapter->securitypriv;
598 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
599 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
600 struct pkt_attrib *pattrib = &pxmitframe->attrib;
601 u8 *pbuf_start;
602 sint bmcst = IS_MCAST(pattrib->ra);
603
604 if (pattrib->psta == NULL)
605 return _FAIL;
606 psta = pattrib->psta;
607 if (pxmitframe->buf_addr == NULL)
608 return _FAIL;
609 pbuf_start = pxmitframe->buf_addr;
610 ptxdesc = pbuf_start;
611 mem_start = pbuf_start + TXDESC_OFFSET;
612 if (make_wlanhdr(padapter, mem_start, pattrib) == _FAIL)
613 return _FAIL;
614 _r8712_open_pktfile(pkt, &pktfile);
615 _r8712_pktfile_read(&pktfile, NULL, pattrib->pkt_hdrlen);
616 if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) {
617 /* truncate TXDESC_SIZE bytes txcmd if at mp mode for 871x */
618 if (pattrib->ether_type == 0x8712) {
619 /* take care - update_txdesc overwrite this */
620 _r8712_pktfile_read(&pktfile, ptxdesc, TXDESC_SIZE);
621 }
622 }
623 pattrib->pktlen = pktfile.pkt_len;
624 frg_inx = 0;
625 frg_len = pxmitpriv->frag_len - 4;
626 while (1) {
627 llc_sz = 0;
628 mpdu_len = frg_len;
629 pframe = mem_start;
630 SetMFrag(mem_start);
631 pframe += pattrib->hdrlen;
632 mpdu_len -= pattrib->hdrlen;
633 /* adding icv, if necessary...*/
634 if (pattrib->iv_len) {
635 if (psta != NULL) {
636 switch (pattrib->encrypt) {
637 case _WEP40_:
638 case _WEP104_:
639 WEP_IV(pattrib->iv, psta->txpn,
640 (u8)psecuritypriv->
641 PrivacyKeyIndex);
642 break;
643 case _TKIP_:
644 if (bmcst)
645 TKIP_IV(pattrib->iv,
646 psta->txpn,
647 (u8)psecuritypriv->
648 XGrpKeyid);
649 else
650 TKIP_IV(pattrib->iv, psta->txpn,
651 0);
652 break;
653 case _AES_:
654 if (bmcst)
655 AES_IV(pattrib->iv, psta->txpn,
656 (u8)psecuritypriv->
657 XGrpKeyid);
658 else
659 AES_IV(pattrib->iv, psta->txpn,
660 0);
661 break;
662 }
663 }
664 memcpy(pframe, pattrib->iv, pattrib->iv_len);
665 pframe += pattrib->iv_len;
666 mpdu_len -= pattrib->iv_len;
667 }
668 if (frg_inx == 0) {
669 llc_sz = r8712_put_snap(pframe, pattrib->ether_type);
670 pframe += llc_sz;
671 mpdu_len -= llc_sz;
672 }
673 if ((pattrib->icv_len > 0) && (pattrib->bswenc))
674 mpdu_len -= pattrib->icv_len;
675 if (bmcst)
676 mem_sz = _r8712_pktfile_read(&pktfile, pframe,
677 pattrib->pktlen);
678 else
679 mem_sz = _r8712_pktfile_read(&pktfile, pframe,
680 mpdu_len);
681 pframe += mem_sz;
682 if ((pattrib->icv_len > 0) && (pattrib->bswenc)) {
683 memcpy(pframe, pattrib->icv, pattrib->icv_len);
684 pframe += pattrib->icv_len;
685 }
686 frg_inx++;
687 if (bmcst || (r8712_endofpktfile(&pktfile) == true)) {
688 pattrib->nr_frags = frg_inx;
689 pattrib->last_txcmdsz = pattrib->hdrlen +
690 pattrib->iv_len +
691 ((pattrib->nr_frags == 1) ?
692 llc_sz : 0) +
693 ((pattrib->bswenc) ?
694 pattrib->icv_len : 0) + mem_sz;
695 ClearMFrag(mem_start);
696 break;
697 }
698 addr = (addr_t)(pframe);
699 mem_start = (unsigned char *)RND4(addr) + TXDESC_OFFSET;
700 memcpy(mem_start, pbuf_start + TXDESC_OFFSET, pattrib->hdrlen);
701 }
702
703 if (xmitframe_addmic(padapter, pxmitframe) == _FAIL)
704 return _FAIL;
705 xmitframe_swencrypt(padapter, pxmitframe);
706 return _SUCCESS;
707}
708
709void r8712_update_protection(struct _adapter *padapter, u8 *ie, uint ie_len)
710{
711 uint protection;
712 u8 *perp;
713 sint erp_len;
714 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
715 struct registry_priv *pregistrypriv = &padapter->registrypriv;
716
717 switch (pxmitpriv->vcs_setting) {
718 case DISABLE_VCS:
719 pxmitpriv->vcs = NONE_VCS;
720 break;
721 case ENABLE_VCS:
722 break;
723 case AUTO_VCS:
724 default:
725 perp = r8712_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len);
726 if (perp == NULL)
727 pxmitpriv->vcs = NONE_VCS;
728 else {
729 protection = (*(perp + 2)) & BIT(1);
730 if (protection) {
731 if (pregistrypriv->vcs_type == RTS_CTS)
732 pxmitpriv->vcs = RTS_CTS;
733 else
734 pxmitpriv->vcs = CTS_TO_SELF;
735 } else
736 pxmitpriv->vcs = NONE_VCS;
737 }
738 break;
739 }
740}
741
742struct xmit_buf *r8712_alloc_xmitbuf(struct xmit_priv *pxmitpriv)
743{
744 unsigned long irqL;
745 struct xmit_buf *pxmitbuf = NULL;
746 struct list_head *plist, *phead;
747 struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
748
749 spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL);
750 if (_queue_empty(pfree_xmitbuf_queue) == true)
751 pxmitbuf = NULL;
752 else {
753 phead = get_list_head(pfree_xmitbuf_queue);
754 plist = get_next(phead);
755 pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
756 list_delete(&(pxmitbuf->list));
757 }
758 if (pxmitbuf != NULL)
759 pxmitpriv->free_xmitbuf_cnt--;
760 spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL);
761 return pxmitbuf;
762}
763
764int r8712_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
765{
766 unsigned long irqL;
767 struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
768
769 if (pxmitbuf == NULL)
770 return _FAIL;
771 spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL);
772 list_delete(&pxmitbuf->list);
773 list_insert_tail(&(pxmitbuf->list), get_list_head(pfree_xmitbuf_queue));
774 pxmitpriv->free_xmitbuf_cnt++;
775 spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL);
776 return _SUCCESS;
777}
778
779/*
780Calling context:
7811. OS_TXENTRY
7822. RXENTRY (rx_thread or RX_ISR/RX_CallBack)
783
784If we turn on USE_RXTHREAD, then, no need for critical section.
785Otherwise, we must use _enter/_exit critical to protect free_xmit_queue...
786
787Must be very very cautious...
788
789*/
790
791struct xmit_frame *r8712_alloc_xmitframe(struct xmit_priv *pxmitpriv)
792{
793 /*
794 Please remember to use all the osdep_service api,
795 and lock/unlock or _enter/_exit critical to protect
796 pfree_xmit_queue
797 */
798 unsigned long irqL;
799 struct xmit_frame *pxframe = NULL;
800 struct list_head *plist, *phead;
801 struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue;
802
803 spin_lock_irqsave(&pfree_xmit_queue->lock, irqL);
804 if (_queue_empty(pfree_xmit_queue) == true)
805 pxframe = NULL;
806 else {
807 phead = get_list_head(pfree_xmit_queue);
808 plist = get_next(phead);
809 pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
810 list_delete(&(pxframe->list));
811 }
812 if (pxframe != NULL) {
813 pxmitpriv->free_xmitframe_cnt--;
814 pxframe->buf_addr = NULL;
815 pxframe->pxmitbuf = NULL;
816 pxframe->attrib.psta = NULL;
817 pxframe->pkt = NULL;
818 }
819 spin_unlock_irqrestore(&pfree_xmit_queue->lock, irqL);
820 return pxframe;
821}
822
823void r8712_free_xmitframe(struct xmit_priv *pxmitpriv,
824 struct xmit_frame *pxmitframe)
825{
826 unsigned long irqL;
827 struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue;
828 struct _adapter *padapter = pxmitpriv->adapter;
829
830 if (pxmitframe == NULL)
831 return;
832 if (pxmitframe->pkt)
833 r8712_xmit_complete(padapter, pxmitframe);
834 spin_lock_irqsave(&pfree_xmit_queue->lock, irqL);
835 list_delete(&pxmitframe->list);
836 list_insert_tail(&pxmitframe->list, get_list_head(pfree_xmit_queue));
837 pxmitpriv->free_xmitframe_cnt++;
838 spin_unlock_irqrestore(&pfree_xmit_queue->lock, irqL);
839 if (netif_queue_stopped(padapter->pnetdev))
840 netif_wake_queue(padapter->pnetdev);
841}
842
843void r8712_free_xmitframe_ex(struct xmit_priv *pxmitpriv,
844 struct xmit_frame *pxmitframe)
845{
846 if (pxmitframe == NULL)
847 return;
848 if (pxmitframe->frame_tag == DATA_FRAMETAG)
849 r8712_free_xmitframe(pxmitpriv, pxmitframe);
850}
851
852void r8712_free_xmitframe_queue(struct xmit_priv *pxmitpriv,
853 struct __queue *pframequeue)
854{
855 unsigned long irqL;
856 struct list_head *plist, *phead;
857 struct xmit_frame *pxmitframe;
858
859 spin_lock_irqsave(&(pframequeue->lock), irqL);
860 phead = get_list_head(pframequeue);
861 plist = get_next(phead);
862 while (end_of_queue_search(phead, plist) == false) {
863 pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
864 plist = get_next(plist);
865 r8712_free_xmitframe(pxmitpriv, pxmitframe);
866 }
867 spin_unlock_irqrestore(&(pframequeue->lock), irqL);
868}
869
870static inline struct tx_servq *get_sta_pending(struct _adapter *padapter,
871 struct __queue **ppstapending,
872 struct sta_info *psta, sint up)
873{
874
875 struct tx_servq *ptxservq;
876 struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
877
878 switch (up) {
879 case 1:
880 case 2:
881 ptxservq = &(psta->sta_xmitpriv.bk_q);
882 *ppstapending = &padapter->xmitpriv.bk_pending;
883 (phwxmits+3)->accnt++;
884 break;
885 case 4:
886 case 5:
887 ptxservq = &(psta->sta_xmitpriv.vi_q);
888 *ppstapending = &padapter->xmitpriv.vi_pending;
889 (phwxmits+1)->accnt++;
890 break;
891 case 6:
892 case 7:
893 ptxservq = &(psta->sta_xmitpriv.vo_q);
894 *ppstapending = &padapter->xmitpriv.vo_pending;
895 (phwxmits+0)->accnt++;
896 break;
897 case 0:
898 case 3:
899 default:
900 ptxservq = &(psta->sta_xmitpriv.be_q);
901 *ppstapending = &padapter->xmitpriv.be_pending;
902 (phwxmits + 2)->accnt++;
903 break;
904 }
905 return ptxservq;
906}
907
908/*
909 * Will enqueue pxmitframe to the proper queue, and indicate it
910 * to xx_pending list.....
911 */
912sint r8712_xmit_classifier(struct _adapter *padapter,
913 struct xmit_frame *pxmitframe)
914{
915 unsigned long irqL0;
916 struct __queue *pstapending;
917 struct sta_info *psta;
918 struct tx_servq *ptxservq;
919 struct pkt_attrib *pattrib = &pxmitframe->attrib;
920 struct sta_priv *pstapriv = &padapter->stapriv;
921 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
922 sint bmcst = IS_MCAST(pattrib->ra);
923
924 if (pattrib->psta)
925 psta = pattrib->psta;
926 else {
927 if (bmcst)
928 psta = r8712_get_bcmc_stainfo(padapter);
929 else {
930 if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)
931 psta = r8712_get_stainfo(pstapriv,
932 get_bssid(pmlmepriv));
933 else
934 psta = r8712_get_stainfo(pstapriv, pattrib->ra);
935 }
936 }
937 if (psta == NULL)
938 return _FAIL;
939 ptxservq = get_sta_pending(padapter, &pstapending,
940 psta, pattrib->priority);
941 spin_lock_irqsave(&pstapending->lock, irqL0);
942 if (is_list_empty(&ptxservq->tx_pending))
943 list_insert_tail(&ptxservq->tx_pending,
944 get_list_head(pstapending));
945 list_insert_tail(&pxmitframe->list,
946 get_list_head(&ptxservq->sta_pending));
947 ptxservq->qcnt++;
948 spin_unlock_irqrestore(&pstapending->lock, irqL0);
949 return _SUCCESS;
950}
951
952static void alloc_hwxmits(struct _adapter *padapter)
953{
954 struct hw_xmit *hwxmits;
955 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
956
957 pxmitpriv->hwxmit_entry = HWXMIT_ENTRY;
958 pxmitpriv->hwxmits = (struct hw_xmit *)_malloc(sizeof(struct hw_xmit) *
959 pxmitpriv->hwxmit_entry);
960 if (pxmitpriv->hwxmits == NULL)
961 return;
962 hwxmits = pxmitpriv->hwxmits;
963 if (pxmitpriv->hwxmit_entry == 5) {
964 pxmitpriv->bmc_txqueue.head = 0;
965 hwxmits[0] .phwtxqueue = &pxmitpriv->bmc_txqueue;
966 hwxmits[0] .sta_queue = &pxmitpriv->bm_pending;
967 pxmitpriv->vo_txqueue.head = 0;
968 hwxmits[1] .phwtxqueue = &pxmitpriv->vo_txqueue;
969 hwxmits[1] .sta_queue = &pxmitpriv->vo_pending;
970 pxmitpriv->vi_txqueue.head = 0;
971 hwxmits[2] .phwtxqueue = &pxmitpriv->vi_txqueue;
972 hwxmits[2] .sta_queue = &pxmitpriv->vi_pending;
973 pxmitpriv->bk_txqueue.head = 0;
974 hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue;
975 hwxmits[3] .sta_queue = &pxmitpriv->bk_pending;
976 pxmitpriv->be_txqueue.head = 0;
977 hwxmits[4] .phwtxqueue = &pxmitpriv->be_txqueue;
978 hwxmits[4] .sta_queue = &pxmitpriv->be_pending;
979 } else if (pxmitpriv->hwxmit_entry == 4) {
980 pxmitpriv->vo_txqueue.head = 0;
981 hwxmits[0] .phwtxqueue = &pxmitpriv->vo_txqueue;
982 hwxmits[0] .sta_queue = &pxmitpriv->vo_pending;
983 pxmitpriv->vi_txqueue.head = 0;
984 hwxmits[1] .phwtxqueue = &pxmitpriv->vi_txqueue;
985 hwxmits[1] .sta_queue = &pxmitpriv->vi_pending;
986 pxmitpriv->be_txqueue.head = 0;
987 hwxmits[2] .phwtxqueue = &pxmitpriv->be_txqueue;
988 hwxmits[2] .sta_queue = &pxmitpriv->be_pending;
989 pxmitpriv->bk_txqueue.head = 0;
990 hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue;
991 hwxmits[3] .sta_queue = &pxmitpriv->bk_pending;
992 }
993}
994
995static void free_hwxmits(struct _adapter *padapter)
996{
997 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
998
999 if (pxmitpriv->hwxmits)
1000 kfree((u8 *)pxmitpriv->hwxmits);
1001}
1002
1003static void init_hwxmits(struct hw_xmit *phwxmit, sint entry)
1004{
1005 sint i;
1006
1007 for (i = 0; i < entry; i++, phwxmit++) {
1008 spin_lock_init(&phwxmit->xmit_lock);
1009 _init_listhead(&phwxmit->pending);
1010 phwxmit->txcmdcnt = 0;
1011 phwxmit->accnt = 0;
1012 }
1013}
1014
1015/*
1016 * tx_action == 0 == no frames to transmit
1017 * tx_action > 0 ==> we have frames to transmit
1018 * tx_action < 0 ==> we have frames to transmit, but TXFF is not even enough
1019 * to transmit 1 frame.
1020 */
1021
1022int r8712_pre_xmit(struct _adapter *padapter, struct xmit_frame *pxmitframe)
1023{
1024 unsigned long irqL;
1025 int ret;
1026 struct xmit_buf *pxmitbuf = NULL;
1027 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
1028 struct pkt_attrib *pattrib = &pxmitframe->attrib;
1029
1030 r8712_do_queue_select(padapter, pattrib);
1031 spin_lock_irqsave(&pxmitpriv->lock, irqL);
1032 if (r8712_txframes_sta_ac_pending(padapter, pattrib) > 0) {
1033 ret = false;
1034 r8712_xmit_enqueue(padapter, pxmitframe);
1035 spin_unlock_irqrestore(&pxmitpriv->lock, irqL);
1036 return ret;
1037 }
1038 pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv);
1039 if (pxmitbuf == NULL) { /*enqueue packet*/
1040 ret = false;
1041 r8712_xmit_enqueue(padapter, pxmitframe);
1042 spin_unlock_irqrestore(&pxmitpriv->lock, irqL);
1043 } else { /*dump packet directly*/
1044 spin_unlock_irqrestore(&pxmitpriv->lock, irqL);
1045 ret = true;
1046 pxmitframe->pxmitbuf = pxmitbuf;
1047 pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0];
1048 pxmitframe->buf_addr = pxmitbuf->pbuf;
1049 r8712_xmit_direct(padapter, pxmitframe);
1050 }
1051 return ret;
1052}