Commit | Line | Data |
---|---|---|
2865d42c LF |
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 | ||
39 | static const u8 P802_1H_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0xf8}; | |
40 | static const u8 RFC1042_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0x00}; | |
41 | static void init_hwxmits(struct hw_xmit *phwxmit, sint entry); | |
42 | static void alloc_hwxmits(struct _adapter *padapter); | |
43 | static void free_hwxmits(struct _adapter *padapter); | |
44 | ||
45 | static 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 | ||
52 | void _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 | ||
65 | sint _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 | ||
163 | void _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 | ||
187 | sint 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 *)ðerhdr, 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, ðerhdr.h_dest, ETH_ALEN); | |
223 | memcpy(pattrib->src, ðerhdr.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 | ||
349 | static 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 | ||
454 | static 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 | ||
478 | static 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 | ||
557 | static 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 | */ | |
586 | sint 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 | ||
709 | void 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 | ||
742 | struct 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 | ||
764 | int 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 | /* | |
780 | Calling context: | |
781 | 1. OS_TXENTRY | |
782 | 2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) | |
783 | ||
784 | If we turn on USE_RXTHREAD, then, no need for critical section. | |
785 | Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... | |
786 | ||
787 | Must be very very cautious... | |
788 | ||
789 | */ | |
790 | ||
791 | struct 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 | ||
823 | void 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 | ||
843 | void 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 | ||
852 | void 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 | ||
870 | static 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 | */ | |
912 | sint 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 | ||
952 | static 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 | ||
995 | static 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 | ||
1003 | static 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 | ||
1022 | int 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 | } |