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" | |
2865d42c LF |
33 | #include "wifi.h" |
34 | #include "osdep_intf.h" | |
35 | #include "usb_ops.h" | |
36 | ||
37 | ||
38 | static const u8 P802_1H_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0xf8}; | |
39 | static const u8 RFC1042_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0x00}; | |
40 | static void init_hwxmits(struct hw_xmit *phwxmit, sint entry); | |
41 | static void alloc_hwxmits(struct _adapter *padapter); | |
42 | static void free_hwxmits(struct _adapter *padapter); | |
43 | ||
44 | static void _init_txservq(struct tx_servq *ptxservq) | |
45 | { | |
46 | _init_listhead(&ptxservq->tx_pending); | |
47 | _init_queue(&ptxservq->sta_pending); | |
48 | ptxservq->qcnt = 0; | |
49 | } | |
50 | ||
51 | void _r8712_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) | |
52 | { | |
53 | memset((unsigned char *)psta_xmitpriv, 0, | |
54 | sizeof(struct sta_xmit_priv)); | |
55 | spin_lock_init(&psta_xmitpriv->lock); | |
56 | _init_txservq(&psta_xmitpriv->be_q); | |
57 | _init_txservq(&psta_xmitpriv->bk_q); | |
58 | _init_txservq(&psta_xmitpriv->vi_q); | |
59 | _init_txservq(&psta_xmitpriv->vo_q); | |
60 | _init_listhead(&psta_xmitpriv->legacy_dz); | |
61 | _init_listhead(&psta_xmitpriv->apsd); | |
62 | } | |
63 | ||
64 | sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv, | |
65 | struct _adapter *padapter) | |
66 | { | |
67 | sint i; | |
68 | struct xmit_buf *pxmitbuf; | |
69 | struct xmit_frame *pxframe; | |
70 | ||
71 | memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv)); | |
72 | spin_lock_init(&pxmitpriv->lock); | |
2865d42c | 73 | /* |
be10ac2b | 74 | Please insert all the queue initialization using _init_queue below |
2865d42c LF |
75 | */ |
76 | pxmitpriv->adapter = padapter; | |
77 | _init_queue(&pxmitpriv->be_pending); | |
78 | _init_queue(&pxmitpriv->bk_pending); | |
79 | _init_queue(&pxmitpriv->vi_pending); | |
80 | _init_queue(&pxmitpriv->vo_pending); | |
81 | _init_queue(&pxmitpriv->bm_pending); | |
82 | _init_queue(&pxmitpriv->legacy_dz_queue); | |
83 | _init_queue(&pxmitpriv->apsd_queue); | |
84 | _init_queue(&pxmitpriv->free_xmit_queue); | |
85 | /* | |
86 | Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME, | |
87 | and initialize free_xmit_frame below. | |
88 | Please also apply free_txobj to link_up all the xmit_frames... | |
89 | */ | |
91d435fe VO |
90 | pxmitpriv->pallocated_frame_buf = kmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4, |
91 | GFP_ATOMIC); | |
2865d42c LF |
92 | if (pxmitpriv->pallocated_frame_buf == NULL) { |
93 | pxmitpriv->pxmit_frame_buf = NULL; | |
94 | return _FAIL; | |
95 | } | |
96 | pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - | |
97 | ((addr_t) (pxmitpriv->pallocated_frame_buf) & 3); | |
98 | pxframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf; | |
99 | for (i = 0; i < NR_XMITFRAME; i++) { | |
100 | _init_listhead(&(pxframe->list)); | |
101 | pxframe->padapter = padapter; | |
102 | pxframe->frame_tag = DATA_FRAMETAG; | |
103 | pxframe->pkt = NULL; | |
104 | pxframe->buf_addr = NULL; | |
105 | pxframe->pxmitbuf = NULL; | |
106 | list_insert_tail(&(pxframe->list), | |
107 | &(pxmitpriv->free_xmit_queue.queue)); | |
108 | pxframe++; | |
109 | } | |
110 | pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME; | |
111 | /* | |
112 | init xmit hw_txqueue | |
113 | */ | |
114 | _r8712_init_hw_txqueue(&pxmitpriv->be_txqueue, BE_QUEUE_INX); | |
115 | _r8712_init_hw_txqueue(&pxmitpriv->bk_txqueue, BK_QUEUE_INX); | |
116 | _r8712_init_hw_txqueue(&pxmitpriv->vi_txqueue, VI_QUEUE_INX); | |
117 | _r8712_init_hw_txqueue(&pxmitpriv->vo_txqueue, VO_QUEUE_INX); | |
118 | _r8712_init_hw_txqueue(&pxmitpriv->bmc_txqueue, BMC_QUEUE_INX); | |
119 | pxmitpriv->frag_len = MAX_FRAG_THRESHOLD; | |
120 | pxmitpriv->txirp_cnt = 1; | |
2865d42c LF |
121 | /*per AC pending irp*/ |
122 | pxmitpriv->beq_cnt = 0; | |
123 | pxmitpriv->bkq_cnt = 0; | |
124 | pxmitpriv->viq_cnt = 0; | |
125 | pxmitpriv->voq_cnt = 0; | |
126 | /*init xmit_buf*/ | |
127 | _init_queue(&pxmitpriv->free_xmitbuf_queue); | |
128 | _init_queue(&pxmitpriv->pending_xmitbuf_queue); | |
91d435fe VO |
129 | pxmitpriv->pallocated_xmitbuf = kmalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4, |
130 | GFP_ATOMIC); | |
2865d42c LF |
131 | if (pxmitpriv->pallocated_xmitbuf == NULL) |
132 | return _FAIL; | |
133 | pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - | |
134 | ((addr_t)(pxmitpriv->pallocated_xmitbuf) & 3); | |
135 | pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; | |
136 | for (i = 0; i < NR_XMITBUFF; i++) { | |
137 | _init_listhead(&pxmitbuf->list); | |
91d435fe VO |
138 | pxmitbuf->pallocated_buf = kmalloc(MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ, |
139 | GFP_ATOMIC); | |
2865d42c LF |
140 | if (pxmitbuf->pallocated_buf == NULL) |
141 | return _FAIL; | |
142 | pxmitbuf->pbuf = pxmitbuf->pallocated_buf + XMITBUF_ALIGN_SZ - | |
143 | ((addr_t) (pxmitbuf->pallocated_buf) & | |
144 | (XMITBUF_ALIGN_SZ - 1)); | |
145 | r8712_xmit_resource_alloc(padapter, pxmitbuf); | |
146 | list_insert_tail(&pxmitbuf->list, | |
147 | &(pxmitpriv->free_xmitbuf_queue.queue)); | |
148 | pxmitbuf++; | |
149 | } | |
150 | pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; | |
f95302ee | 151 | _init_workitem(&padapter->wkFilterRxFF0, r8712_SetFilter, padapter); |
2865d42c LF |
152 | alloc_hwxmits(padapter); |
153 | init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); | |
154 | tasklet_init(&pxmitpriv->xmit_tasklet, | |
f95302ee AB |
155 | (void(*)(unsigned long))r8712_xmit_bh, |
156 | (unsigned long)padapter); | |
2865d42c LF |
157 | return _SUCCESS; |
158 | } | |
159 | ||
160 | void _free_xmit_priv(struct xmit_priv *pxmitpriv) | |
161 | { | |
162 | int i; | |
163 | struct _adapter *padapter = pxmitpriv->adapter; | |
164 | struct xmit_frame *pxmitframe = (struct xmit_frame *) | |
165 | pxmitpriv->pxmit_frame_buf; | |
166 | struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; | |
167 | ||
168 | if (pxmitpriv->pxmit_frame_buf == NULL) | |
169 | return; | |
170 | for (i = 0; i < NR_XMITFRAME; i++) { | |
171 | r8712_xmit_complete(padapter, pxmitframe); | |
172 | pxmitframe++; | |
173 | } | |
174 | for (i = 0; i < NR_XMITBUFF; i++) { | |
175 | r8712_xmit_resource_free(padapter, pxmitbuf); | |
176 | kfree(pxmitbuf->pallocated_buf); | |
177 | pxmitbuf++; | |
178 | } | |
179 | kfree(pxmitpriv->pallocated_frame_buf); | |
180 | kfree(pxmitpriv->pallocated_xmitbuf); | |
181 | free_hwxmits(padapter); | |
182 | } | |
183 | ||
184 | sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt, | |
185 | struct pkt_attrib *pattrib) | |
186 | { | |
187 | uint i; | |
188 | struct pkt_file pktfile; | |
189 | struct sta_info *psta = NULL; | |
190 | struct ethhdr etherhdr; | |
191 | ||
192 | struct tx_cmd txdesc; | |
193 | ||
194 | sint bmcast; | |
195 | struct sta_priv *pstapriv = &padapter->stapriv; | |
196 | struct security_priv *psecuritypriv = &padapter->securitypriv; | |
197 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
198 | struct qos_priv *pqospriv = &pmlmepriv->qospriv; | |
199 | ||
200 | _r8712_open_pktfile(pkt, &pktfile); | |
201 | ||
202 | i = _r8712_pktfile_read(&pktfile, (unsigned char *)ðerhdr, ETH_HLEN); | |
203 | ||
204 | pattrib->ether_type = ntohs(etherhdr.h_proto); | |
205 | ||
206 | { | |
207 | u8 bool; | |
208 | /*If driver xmit ARP packet, driver can set ps mode to initial | |
209 | * setting. It stands for getting DHCP or fix IP.*/ | |
210 | if (pattrib->ether_type == 0x0806) { | |
211 | if (padapter->pwrctrlpriv.pwr_mode != | |
212 | padapter->registrypriv.power_mgnt) { | |
213 | _cancel_timer(&(pmlmepriv->dhcp_timer), &bool); | |
214 | r8712_set_ps_mode(padapter, padapter->registrypriv. | |
215 | power_mgnt, padapter->registrypriv.smart_ps); | |
216 | } | |
217 | } | |
218 | } | |
219 | memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); | |
220 | memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); | |
221 | pattrib->pctrl = 0; | |
222 | if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || | |
223 | (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { | |
224 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); | |
225 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); | |
226 | } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { | |
227 | memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); | |
228 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); | |
229 | } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { | |
230 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); | |
231 | memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); | |
232 | } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { | |
233 | /*firstly, filter packet not belongs to mp*/ | |
234 | if (pattrib->ether_type != 0x8712) | |
235 | return _FAIL; | |
236 | /* for mp storing the txcmd per packet, | |
237 | * according to the info of txcmd to update pattrib */ | |
238 | /*get MP_TXDESC_SIZE bytes txcmd per packet*/ | |
239 | i = _r8712_pktfile_read(&pktfile, (u8 *)&txdesc, TXDESC_SIZE); | |
240 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); | |
241 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); | |
242 | pattrib->pctrl = 1; | |
243 | } | |
244 | /* r8712_xmitframe_coalesce() overwrite this!*/ | |
245 | pattrib->pktlen = pktfile.pkt_len; | |
246 | if (ETH_P_IP == pattrib->ether_type) { | |
247 | /* The following is for DHCP and ARP packet, we use cck1M to | |
248 | * tx these packets and let LPS awake some time | |
249 | * to prevent DHCP protocol fail */ | |
250 | u8 tmp[24]; | |
251 | _r8712_pktfile_read(&pktfile, &tmp[0], 24); | |
252 | pattrib->dhcp_pkt = 0; | |
253 | if (pktfile.pkt_len > 282) {/*MINIMUM_DHCP_PACKET_SIZE)*/ | |
254 | if (ETH_P_IP == pattrib->ether_type) {/* IP header*/ | |
255 | if (((tmp[21] == 68) && (tmp[23] == 67)) || | |
256 | ((tmp[21] == 67) && (tmp[23] == 68))) { | |
257 | /* 68 : UDP BOOTP client | |
258 | * 67 : UDP BOOTP server | |
259 | * Use low rate to send DHCP packet.*/ | |
260 | pattrib->dhcp_pkt = 1; | |
261 | } | |
262 | } | |
263 | } | |
264 | } | |
265 | bmcast = IS_MCAST(pattrib->ra); | |
266 | /* get sta_info*/ | |
267 | if (bmcast) { | |
268 | psta = r8712_get_bcmc_stainfo(padapter); | |
269 | pattrib->mac_id = 4; | |
270 | } else { | |
271 | if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { | |
272 | psta = r8712_get_stainfo(pstapriv, | |
273 | get_bssid(pmlmepriv)); | |
274 | pattrib->mac_id = 5; | |
275 | } else { | |
276 | psta = r8712_get_stainfo(pstapriv, pattrib->ra); | |
277 | if (psta == NULL) /* drop the pkt */ | |
278 | return _FAIL; | |
279 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) | |
280 | pattrib->mac_id = 5; | |
281 | else | |
282 | pattrib->mac_id = psta->mac_id; | |
283 | } | |
284 | } | |
285 | ||
286 | if (psta) { | |
287 | pattrib->psta = psta; | |
288 | } else { | |
289 | /* if we cannot get psta => drrp the pkt */ | |
290 | return _FAIL; | |
291 | } | |
292 | ||
293 | pattrib->ack_policy = 0; | |
294 | /* get ether_hdr_len */ | |
295 | pattrib->pkt_hdrlen = ETH_HLEN; | |
296 | ||
297 | if (pqospriv->qos_option) | |
298 | r8712_set_qos(&pktfile, pattrib); | |
299 | else { | |
300 | pattrib->hdrlen = WLAN_HDR_A3_LEN; | |
301 | pattrib->subtype = WIFI_DATA_TYPE; | |
302 | pattrib->priority = 0; | |
303 | } | |
304 | if (psta->ieee8021x_blocked == true) { | |
305 | pattrib->encrypt = 0; | |
306 | if ((pattrib->ether_type != 0x888e) && | |
307 | (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false)) | |
308 | return _FAIL; | |
309 | } else | |
310 | GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); | |
311 | switch (pattrib->encrypt) { | |
312 | case _WEP40_: | |
313 | case _WEP104_: | |
314 | pattrib->iv_len = 4; | |
315 | pattrib->icv_len = 4; | |
316 | break; | |
317 | case _TKIP_: | |
318 | pattrib->iv_len = 8; | |
319 | pattrib->icv_len = 4; | |
320 | if (padapter->securitypriv.busetkipkey == _FAIL) | |
321 | return _FAIL; | |
322 | break; | |
323 | case _AES_: | |
324 | pattrib->iv_len = 8; | |
325 | pattrib->icv_len = 8; | |
326 | break; | |
327 | default: | |
328 | pattrib->iv_len = 0; | |
329 | pattrib->icv_len = 0; | |
330 | break; | |
331 | } | |
332 | ||
333 | if (pattrib->encrypt && | |
334 | ((padapter->securitypriv.sw_encrypt == true) || | |
335 | (psecuritypriv->hw_decrypted == false))) | |
336 | pattrib->bswenc = true; | |
337 | else | |
338 | pattrib->bswenc = false; | |
339 | /* if in MP_STATE, update pkt_attrib from mp_txcmd, and overwrite | |
340 | * some settings above.*/ | |
341 | if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) | |
342 | pattrib->priority = (txdesc.txdw1 >> QSEL_SHT) & 0x1f; | |
343 | return _SUCCESS; | |
344 | } | |
345 | ||
346 | static sint xmitframe_addmic(struct _adapter *padapter, | |
347 | struct xmit_frame *pxmitframe) | |
348 | { | |
349 | u32 curfragnum, length, datalen; | |
350 | u8 *pframe, *payload, mic[8]; | |
351 | struct mic_data micdata; | |
352 | struct sta_info *stainfo; | |
353 | struct qos_priv *pqospriv = &(padapter->mlmepriv.qospriv); | |
354 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
355 | struct security_priv *psecuritypriv = &padapter->securitypriv; | |
356 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
357 | u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; | |
358 | sint bmcst = IS_MCAST(pattrib->ra); | |
359 | ||
360 | if (pattrib->psta) | |
361 | stainfo = pattrib->psta; | |
362 | else | |
363 | stainfo = r8712_get_stainfo(&padapter->stapriv, | |
364 | &pattrib->ra[0]); | |
365 | if (pattrib->encrypt == _TKIP_) { | |
366 | /*encode mic code*/ | |
367 | if (stainfo != NULL) { | |
368 | u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
369 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
370 | 0x0, 0x0}; | |
371 | datalen = pattrib->pktlen - pattrib->hdrlen; | |
859171ca | 372 | pframe = pxmitframe->buf_addr + TXDESC_OFFSET; |
2865d42c LF |
373 | if (bmcst) { |
374 | if (!memcmp(psecuritypriv->XGrptxmickey | |
375 | [psecuritypriv->XGrpKeyid].skey, | |
376 | null_key, 16)) | |
377 | return _FAIL; | |
378 | /*start to calculate the mic code*/ | |
379 | r8712_secmicsetkey(&micdata, | |
380 | psecuritypriv-> | |
381 | XGrptxmickey[psecuritypriv-> | |
382 | XGrpKeyid].skey); | |
383 | } else { | |
384 | if (!memcmp(&stainfo->tkiptxmickey.skey[0], | |
385 | null_key, 16)) | |
386 | return _FAIL; | |
387 | /* start to calculate the mic code */ | |
388 | r8712_secmicsetkey(&micdata, | |
389 | &stainfo->tkiptxmickey.skey[0]); | |
390 | } | |
391 | if (pframe[1] & 1) { /* ToDS==1 */ | |
392 | r8712_secmicappend(&micdata, | |
393 | &pframe[16], 6); /*DA*/ | |
394 | if (pframe[1]&2) /* From Ds==1 */ | |
395 | r8712_secmicappend(&micdata, | |
396 | &pframe[24], 6); | |
397 | else | |
398 | r8712_secmicappend(&micdata, | |
399 | &pframe[10], 6); | |
400 | } else { /* ToDS==0 */ | |
401 | r8712_secmicappend(&micdata, | |
402 | &pframe[4], 6); /* DA */ | |
403 | if (pframe[1]&2) /* From Ds==1 */ | |
404 | r8712_secmicappend(&micdata, | |
405 | &pframe[16], 6); | |
406 | else | |
407 | r8712_secmicappend(&micdata, | |
408 | &pframe[10], 6); | |
409 | } | |
410 | if (pqospriv->qos_option == 1) | |
411 | priority[0] = (u8)pxmitframe-> | |
412 | attrib.priority; | |
413 | r8712_secmicappend(&micdata, &priority[0], 4); | |
414 | payload = pframe; | |
415 | for (curfragnum = 0; curfragnum < pattrib->nr_frags; | |
416 | curfragnum++) { | |
417 | payload = (u8 *)RND4((addr_t)(payload)); | |
418 | payload = payload+pattrib-> | |
419 | hdrlen+pattrib->iv_len; | |
420 | if ((curfragnum + 1) == pattrib->nr_frags) { | |
421 | length = pattrib->last_txcmdsz - | |
422 | pattrib->hdrlen - | |
423 | pattrib->iv_len - | |
424 | ((psecuritypriv->sw_encrypt) | |
425 | ? pattrib->icv_len : 0); | |
426 | r8712_secmicappend(&micdata, payload, | |
427 | length); | |
428 | payload = payload+length; | |
429 | } else{ | |
430 | length = pxmitpriv->frag_len - | |
431 | pattrib->hdrlen-pattrib->iv_len - | |
432 | ((psecuritypriv->sw_encrypt) ? | |
433 | pattrib->icv_len : 0); | |
434 | r8712_secmicappend(&micdata, payload, | |
435 | length); | |
436 | payload = payload + length + | |
437 | pattrib->icv_len; | |
438 | } | |
439 | } | |
440 | r8712_secgetmic(&micdata, &(mic[0])); | |
441 | /* add mic code and add the mic code length in | |
442 | * last_txcmdsz */ | |
443 | memcpy(payload, &(mic[0]), 8); | |
444 | pattrib->last_txcmdsz += 8; | |
445 | payload = payload-pattrib->last_txcmdsz + 8; | |
446 | } | |
447 | } | |
448 | return _SUCCESS; | |
449 | } | |
450 | ||
451 | static sint xmitframe_swencrypt(struct _adapter *padapter, | |
452 | struct xmit_frame *pxmitframe) | |
453 | { | |
454 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
455 | ||
456 | if (pattrib->bswenc) { | |
457 | switch (pattrib->encrypt) { | |
458 | case _WEP40_: | |
459 | case _WEP104_: | |
460 | r8712_wep_encrypt(padapter, (u8 *)pxmitframe); | |
461 | break; | |
462 | case _TKIP_: | |
463 | r8712_tkip_encrypt(padapter, (u8 *)pxmitframe); | |
464 | break; | |
465 | case _AES_: | |
466 | r8712_aes_encrypt(padapter, (u8 *)pxmitframe); | |
467 | break; | |
468 | default: | |
469 | break; | |
470 | } | |
471 | } | |
472 | return _SUCCESS; | |
473 | } | |
474 | ||
475 | static sint make_wlanhdr(struct _adapter *padapter , u8 *hdr, | |
476 | struct pkt_attrib *pattrib) | |
477 | { | |
478 | u16 *qc; | |
479 | ||
480 | struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr; | |
481 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
482 | struct qos_priv *pqospriv = &pmlmepriv->qospriv; | |
483 | u16 *fctrl = &pwlanhdr->frame_ctl; | |
484 | memset(hdr, 0, WLANHDR_OFFSET); | |
485 | SetFrameSubType(fctrl, pattrib->subtype); | |
486 | if (pattrib->subtype & WIFI_DATA_TYPE) { | |
487 | if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)) { | |
488 | /* to_ds = 1, fr_ds = 0; */ | |
489 | SetToDs(fctrl); | |
490 | memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), | |
491 | ETH_ALEN); | |
492 | memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); | |
493 | memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); | |
494 | } else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)) { | |
495 | /* to_ds = 0, fr_ds = 1; */ | |
496 | SetFrDs(fctrl); | |
497 | memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); | |
498 | memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), | |
499 | ETH_ALEN); | |
500 | memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN); | |
501 | } else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) | |
502 | || (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) | |
503 | == true)) { | |
504 | memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); | |
505 | memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); | |
506 | memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), | |
507 | ETH_ALEN); | |
508 | } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { | |
509 | memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); | |
510 | memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); | |
511 | memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), | |
512 | ETH_ALEN); | |
513 | } else | |
514 | return _FAIL; | |
515 | ||
516 | if (pattrib->encrypt) | |
517 | SetPrivacy(fctrl); | |
518 | if (pqospriv->qos_option) { | |
519 | qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); | |
520 | if (pattrib->priority) | |
521 | SetPriority(qc, pattrib->priority); | |
522 | SetAckpolicy(qc, pattrib->ack_policy); | |
523 | } | |
524 | /* TODO: fill HT Control Field */ | |
525 | /* Update Seq Num will be handled by f/w */ | |
526 | { | |
527 | struct sta_info *psta; | |
528 | ||
529 | sint bmcst = IS_MCAST(pattrib->ra); | |
530 | if (pattrib->psta) | |
531 | psta = pattrib->psta; | |
532 | else { | |
533 | if (bmcst) | |
534 | psta = r8712_get_bcmc_stainfo(padapter); | |
535 | else | |
536 | psta = | |
537 | r8712_get_stainfo(&padapter->stapriv, | |
538 | pattrib->ra); | |
539 | } | |
540 | if (psta) { | |
541 | psta->sta_xmitpriv.txseq_tid | |
542 | [pattrib->priority]++; | |
543 | psta->sta_xmitpriv.txseq_tid[pattrib->priority] | |
544 | &= 0xFFF; | |
545 | pattrib->seqnum = psta->sta_xmitpriv. | |
546 | txseq_tid[pattrib->priority]; | |
547 | SetSeqNum(hdr, pattrib->seqnum); | |
548 | } | |
549 | } | |
550 | } | |
551 | return _SUCCESS; | |
552 | } | |
553 | ||
554 | static sint r8712_put_snap(u8 *data, u16 h_proto) | |
555 | { | |
556 | struct ieee80211_snap_hdr *snap; | |
557 | const u8 *oui; | |
558 | ||
559 | snap = (struct ieee80211_snap_hdr *)data; | |
560 | snap->dsap = 0xaa; | |
561 | snap->ssap = 0xaa; | |
562 | snap->ctrl = 0x03; | |
563 | if (h_proto == 0x8137 || h_proto == 0x80f3) | |
564 | oui = P802_1H_OUI; | |
565 | else | |
566 | oui = RFC1042_OUI; | |
567 | snap->oui[0] = oui[0]; | |
568 | snap->oui[1] = oui[1]; | |
569 | snap->oui[2] = oui[2]; | |
570 | *(u16 *)(data + SNAP_SIZE) = htons(h_proto); | |
571 | return SNAP_SIZE + sizeof(u16); | |
572 | } | |
573 | ||
574 | /* | |
575 | * This sub-routine will perform all the following: | |
576 | * 1. remove 802.3 header. | |
577 | * 2. create wlan_header, based on the info in pxmitframe | |
578 | * 3. append sta's iv/ext-iv | |
579 | * 4. append LLC | |
580 | * 5. move frag chunk from pframe to pxmitframe->mem | |
581 | * 6. apply sw-encrypt, if necessary. | |
582 | */ | |
583 | sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt, | |
584 | struct xmit_frame *pxmitframe) | |
585 | { | |
586 | struct pkt_file pktfile; | |
587 | ||
588 | sint frg_len, mpdu_len, llc_sz; | |
589 | u32 mem_sz; | |
590 | u8 frg_inx; | |
591 | addr_t addr; | |
592 | u8 *pframe, *mem_start, *ptxdesc; | |
593 | struct sta_info *psta; | |
594 | struct security_priv *psecuritypriv = &padapter->securitypriv; | |
595 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
596 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
597 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
598 | u8 *pbuf_start; | |
599 | sint bmcst = IS_MCAST(pattrib->ra); | |
600 | ||
601 | if (pattrib->psta == NULL) | |
602 | return _FAIL; | |
603 | psta = pattrib->psta; | |
604 | if (pxmitframe->buf_addr == NULL) | |
605 | return _FAIL; | |
606 | pbuf_start = pxmitframe->buf_addr; | |
607 | ptxdesc = pbuf_start; | |
608 | mem_start = pbuf_start + TXDESC_OFFSET; | |
609 | if (make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) | |
610 | return _FAIL; | |
611 | _r8712_open_pktfile(pkt, &pktfile); | |
f95302ee | 612 | _r8712_pktfile_read(&pktfile, NULL, (uint) pattrib->pkt_hdrlen); |
2865d42c LF |
613 | if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { |
614 | /* truncate TXDESC_SIZE bytes txcmd if at mp mode for 871x */ | |
615 | if (pattrib->ether_type == 0x8712) { | |
616 | /* take care - update_txdesc overwrite this */ | |
617 | _r8712_pktfile_read(&pktfile, ptxdesc, TXDESC_SIZE); | |
618 | } | |
619 | } | |
620 | pattrib->pktlen = pktfile.pkt_len; | |
621 | frg_inx = 0; | |
622 | frg_len = pxmitpriv->frag_len - 4; | |
623 | while (1) { | |
624 | llc_sz = 0; | |
625 | mpdu_len = frg_len; | |
626 | pframe = mem_start; | |
627 | SetMFrag(mem_start); | |
628 | pframe += pattrib->hdrlen; | |
629 | mpdu_len -= pattrib->hdrlen; | |
630 | /* adding icv, if necessary...*/ | |
631 | if (pattrib->iv_len) { | |
632 | if (psta != NULL) { | |
633 | switch (pattrib->encrypt) { | |
634 | case _WEP40_: | |
635 | case _WEP104_: | |
636 | WEP_IV(pattrib->iv, psta->txpn, | |
637 | (u8)psecuritypriv-> | |
638 | PrivacyKeyIndex); | |
639 | break; | |
640 | case _TKIP_: | |
641 | if (bmcst) | |
642 | TKIP_IV(pattrib->iv, | |
643 | psta->txpn, | |
644 | (u8)psecuritypriv-> | |
645 | XGrpKeyid); | |
646 | else | |
647 | TKIP_IV(pattrib->iv, psta->txpn, | |
648 | 0); | |
649 | break; | |
650 | case _AES_: | |
651 | if (bmcst) | |
652 | AES_IV(pattrib->iv, psta->txpn, | |
653 | (u8)psecuritypriv-> | |
654 | XGrpKeyid); | |
655 | else | |
656 | AES_IV(pattrib->iv, psta->txpn, | |
657 | 0); | |
658 | break; | |
659 | } | |
660 | } | |
661 | memcpy(pframe, pattrib->iv, pattrib->iv_len); | |
662 | pframe += pattrib->iv_len; | |
663 | mpdu_len -= pattrib->iv_len; | |
664 | } | |
665 | if (frg_inx == 0) { | |
666 | llc_sz = r8712_put_snap(pframe, pattrib->ether_type); | |
667 | pframe += llc_sz; | |
668 | mpdu_len -= llc_sz; | |
669 | } | |
670 | if ((pattrib->icv_len > 0) && (pattrib->bswenc)) | |
671 | mpdu_len -= pattrib->icv_len; | |
672 | if (bmcst) | |
673 | mem_sz = _r8712_pktfile_read(&pktfile, pframe, | |
674 | pattrib->pktlen); | |
675 | else | |
676 | mem_sz = _r8712_pktfile_read(&pktfile, pframe, | |
677 | mpdu_len); | |
678 | pframe += mem_sz; | |
679 | if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { | |
680 | memcpy(pframe, pattrib->icv, pattrib->icv_len); | |
681 | pframe += pattrib->icv_len; | |
682 | } | |
683 | frg_inx++; | |
684 | if (bmcst || (r8712_endofpktfile(&pktfile) == true)) { | |
685 | pattrib->nr_frags = frg_inx; | |
686 | pattrib->last_txcmdsz = pattrib->hdrlen + | |
687 | pattrib->iv_len + | |
688 | ((pattrib->nr_frags == 1) ? | |
689 | llc_sz : 0) + | |
690 | ((pattrib->bswenc) ? | |
691 | pattrib->icv_len : 0) + mem_sz; | |
692 | ClearMFrag(mem_start); | |
693 | break; | |
694 | } | |
695 | addr = (addr_t)(pframe); | |
696 | mem_start = (unsigned char *)RND4(addr) + TXDESC_OFFSET; | |
697 | memcpy(mem_start, pbuf_start + TXDESC_OFFSET, pattrib->hdrlen); | |
698 | } | |
699 | ||
700 | if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) | |
701 | return _FAIL; | |
702 | xmitframe_swencrypt(padapter, pxmitframe); | |
703 | return _SUCCESS; | |
704 | } | |
705 | ||
706 | void r8712_update_protection(struct _adapter *padapter, u8 *ie, uint ie_len) | |
707 | { | |
708 | uint protection; | |
709 | u8 *perp; | |
710 | sint erp_len; | |
711 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
712 | struct registry_priv *pregistrypriv = &padapter->registrypriv; | |
713 | ||
714 | switch (pxmitpriv->vcs_setting) { | |
715 | case DISABLE_VCS: | |
716 | pxmitpriv->vcs = NONE_VCS; | |
717 | break; | |
718 | case ENABLE_VCS: | |
719 | break; | |
720 | case AUTO_VCS: | |
721 | default: | |
722 | perp = r8712_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len); | |
723 | if (perp == NULL) | |
724 | pxmitpriv->vcs = NONE_VCS; | |
725 | else { | |
726 | protection = (*(perp + 2)) & BIT(1); | |
727 | if (protection) { | |
728 | if (pregistrypriv->vcs_type == RTS_CTS) | |
729 | pxmitpriv->vcs = RTS_CTS; | |
730 | else | |
731 | pxmitpriv->vcs = CTS_TO_SELF; | |
732 | } else | |
733 | pxmitpriv->vcs = NONE_VCS; | |
734 | } | |
735 | break; | |
736 | } | |
737 | } | |
738 | ||
739 | struct xmit_buf *r8712_alloc_xmitbuf(struct xmit_priv *pxmitpriv) | |
740 | { | |
741 | unsigned long irqL; | |
742 | struct xmit_buf *pxmitbuf = NULL; | |
743 | struct list_head *plist, *phead; | |
744 | struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; | |
745 | ||
746 | spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); | |
747 | if (_queue_empty(pfree_xmitbuf_queue) == true) | |
748 | pxmitbuf = NULL; | |
749 | else { | |
750 | phead = get_list_head(pfree_xmitbuf_queue); | |
751 | plist = get_next(phead); | |
752 | pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); | |
753 | list_delete(&(pxmitbuf->list)); | |
754 | } | |
755 | if (pxmitbuf != NULL) | |
756 | pxmitpriv->free_xmitbuf_cnt--; | |
757 | spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); | |
758 | return pxmitbuf; | |
759 | } | |
760 | ||
761 | int r8712_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) | |
762 | { | |
763 | unsigned long irqL; | |
764 | struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; | |
765 | ||
766 | if (pxmitbuf == NULL) | |
767 | return _FAIL; | |
768 | spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); | |
769 | list_delete(&pxmitbuf->list); | |
770 | list_insert_tail(&(pxmitbuf->list), get_list_head(pfree_xmitbuf_queue)); | |
771 | pxmitpriv->free_xmitbuf_cnt++; | |
772 | spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); | |
773 | return _SUCCESS; | |
774 | } | |
775 | ||
776 | /* | |
777 | Calling context: | |
778 | 1. OS_TXENTRY | |
779 | 2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) | |
780 | ||
781 | If we turn on USE_RXTHREAD, then, no need for critical section. | |
782 | Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... | |
783 | ||
784 | Must be very very cautious... | |
785 | ||
786 | */ | |
787 | ||
788 | struct xmit_frame *r8712_alloc_xmitframe(struct xmit_priv *pxmitpriv) | |
789 | { | |
790 | /* | |
791 | Please remember to use all the osdep_service api, | |
792 | and lock/unlock or _enter/_exit critical to protect | |
793 | pfree_xmit_queue | |
794 | */ | |
795 | unsigned long irqL; | |
796 | struct xmit_frame *pxframe = NULL; | |
797 | struct list_head *plist, *phead; | |
798 | struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; | |
799 | ||
800 | spin_lock_irqsave(&pfree_xmit_queue->lock, irqL); | |
801 | if (_queue_empty(pfree_xmit_queue) == true) | |
802 | pxframe = NULL; | |
803 | else { | |
804 | phead = get_list_head(pfree_xmit_queue); | |
805 | plist = get_next(phead); | |
806 | pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list); | |
807 | list_delete(&(pxframe->list)); | |
808 | } | |
809 | if (pxframe != NULL) { | |
810 | pxmitpriv->free_xmitframe_cnt--; | |
811 | pxframe->buf_addr = NULL; | |
812 | pxframe->pxmitbuf = NULL; | |
813 | pxframe->attrib.psta = NULL; | |
814 | pxframe->pkt = NULL; | |
815 | } | |
816 | spin_unlock_irqrestore(&pfree_xmit_queue->lock, irqL); | |
817 | return pxframe; | |
818 | } | |
819 | ||
820 | void r8712_free_xmitframe(struct xmit_priv *pxmitpriv, | |
821 | struct xmit_frame *pxmitframe) | |
822 | { | |
823 | unsigned long irqL; | |
824 | struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; | |
825 | struct _adapter *padapter = pxmitpriv->adapter; | |
f95302ee | 826 | struct sk_buff *pndis_pkt = NULL; |
2865d42c LF |
827 | |
828 | if (pxmitframe == NULL) | |
829 | return; | |
2865d42c LF |
830 | spin_lock_irqsave(&pfree_xmit_queue->lock, irqL); |
831 | list_delete(&pxmitframe->list); | |
f95302ee AB |
832 | if (pxmitframe->pkt) { |
833 | pndis_pkt = pxmitframe->pkt; | |
834 | pxmitframe->pkt = NULL; | |
835 | } | |
2865d42c LF |
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; | |
91d435fe VO |
958 | pxmitpriv->hwxmits = kmalloc(sizeof(struct hw_xmit) * pxmitpriv->hwxmit_entry, |
959 | GFP_ATOMIC); | |
2865d42c LF |
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 | ||
40083865 | 999 | kfree(pxmitpriv->hwxmits); |
2865d42c LF |
1000 | } |
1001 | ||
1002 | static void init_hwxmits(struct hw_xmit *phwxmit, sint entry) | |
1003 | { | |
1004 | sint i; | |
1005 | ||
1006 | for (i = 0; i < entry; i++, phwxmit++) { | |
1007 | spin_lock_init(&phwxmit->xmit_lock); | |
1008 | _init_listhead(&phwxmit->pending); | |
1009 | phwxmit->txcmdcnt = 0; | |
1010 | phwxmit->accnt = 0; | |
1011 | } | |
1012 | } | |
1013 | ||
07a6b037 AB |
1014 | void xmitframe_xmitbuf_attach(struct xmit_frame *pxmitframe, |
1015 | struct xmit_buf *pxmitbuf) | |
1016 | { | |
1017 | /* pxmitbuf attach to pxmitframe */ | |
1018 | pxmitframe->pxmitbuf = pxmitbuf; | |
1019 | /* urb and irp connection */ | |
1020 | pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; | |
1021 | /* buffer addr assoc */ | |
1022 | pxmitframe->buf_addr = pxmitbuf->pbuf; | |
1023 | /* pxmitframe attach to pxmitbuf */ | |
1024 | pxmitbuf->priv_data = pxmitframe; | |
1025 | } | |
1026 | ||
2865d42c LF |
1027 | /* |
1028 | * tx_action == 0 == no frames to transmit | |
1029 | * tx_action > 0 ==> we have frames to transmit | |
1030 | * tx_action < 0 ==> we have frames to transmit, but TXFF is not even enough | |
1031 | * to transmit 1 frame. | |
1032 | */ | |
1033 | ||
1034 | int r8712_pre_xmit(struct _adapter *padapter, struct xmit_frame *pxmitframe) | |
1035 | { | |
1036 | unsigned long irqL; | |
1037 | int ret; | |
1038 | struct xmit_buf *pxmitbuf = NULL; | |
1039 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
1040 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
1041 | ||
1042 | r8712_do_queue_select(padapter, pattrib); | |
1043 | spin_lock_irqsave(&pxmitpriv->lock, irqL); | |
1044 | if (r8712_txframes_sta_ac_pending(padapter, pattrib) > 0) { | |
1045 | ret = false; | |
1046 | r8712_xmit_enqueue(padapter, pxmitframe); | |
1047 | spin_unlock_irqrestore(&pxmitpriv->lock, irqL); | |
1048 | return ret; | |
1049 | } | |
1050 | pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv); | |
1051 | if (pxmitbuf == NULL) { /*enqueue packet*/ | |
1052 | ret = false; | |
1053 | r8712_xmit_enqueue(padapter, pxmitframe); | |
1054 | spin_unlock_irqrestore(&pxmitpriv->lock, irqL); | |
1055 | } else { /*dump packet directly*/ | |
1056 | spin_unlock_irqrestore(&pxmitpriv->lock, irqL); | |
1057 | ret = true; | |
07a6b037 | 1058 | xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); |
2865d42c LF |
1059 | r8712_xmit_direct(padapter, pxmitframe); |
1060 | } | |
1061 | return ret; | |
1062 | } |