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 | { | |
534c4acd | 46 | INIT_LIST_HEAD(&ptxservq->tx_pending); |
2865d42c LF |
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); | |
534c4acd JS |
60 | INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz); |
61 | INIT_LIST_HEAD(&psta_xmitpriv->apsd); | |
2865d42c LF |
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++) { | |
534c4acd | 100 | INIT_LIST_HEAD(&(pxframe->list)); |
2865d42c LF |
101 | pxframe->padapter = padapter; |
102 | pxframe->frame_tag = DATA_FRAMETAG; | |
103 | pxframe->pkt = NULL; | |
104 | pxframe->buf_addr = NULL; | |
105 | pxframe->pxmitbuf = NULL; | |
fdfbf789 | 106 | list_add_tail(&(pxframe->list), |
2865d42c LF |
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++) { | |
534c4acd | 137 | INIT_LIST_HEAD(&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); | |
fdfbf789 | 146 | list_add_tail(&pxmitbuf->list, |
2865d42c LF |
147 | &(pxmitpriv->free_xmitbuf_queue.queue)); |
148 | pxmitbuf++; | |
149 | } | |
150 | pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; | |
9f952489 | 151 | INIT_WORK(&padapter->wkFilterRxFF0, r8712_SetFilter); |
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 | { | |
2865d42c LF |
187 | struct pkt_file pktfile; |
188 | struct sta_info *psta = NULL; | |
189 | struct ethhdr etherhdr; | |
190 | ||
191 | struct tx_cmd txdesc; | |
192 | ||
193 | sint bmcast; | |
194 | struct sta_priv *pstapriv = &padapter->stapriv; | |
195 | struct security_priv *psecuritypriv = &padapter->securitypriv; | |
196 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
197 | struct qos_priv *pqospriv = &pmlmepriv->qospriv; | |
198 | ||
199 | _r8712_open_pktfile(pkt, &pktfile); | |
200 | ||
e29d3ebc | 201 | _r8712_pktfile_read(&pktfile, (unsigned char *)ðerhdr, ETH_HLEN); |
2865d42c LF |
202 | |
203 | pattrib->ether_type = ntohs(etherhdr.h_proto); | |
204 | ||
205 | { | |
2865d42c LF |
206 | /*If driver xmit ARP packet, driver can set ps mode to initial |
207 | * setting. It stands for getting DHCP or fix IP.*/ | |
208 | if (pattrib->ether_type == 0x0806) { | |
209 | if (padapter->pwrctrlpriv.pwr_mode != | |
210 | padapter->registrypriv.power_mgnt) { | |
382d020f | 211 | del_timer_sync(&pmlmepriv->dhcp_timer); |
2865d42c LF |
212 | r8712_set_ps_mode(padapter, padapter->registrypriv. |
213 | power_mgnt, padapter->registrypriv.smart_ps); | |
214 | } | |
215 | } | |
216 | } | |
217 | memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); | |
218 | memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); | |
219 | pattrib->pctrl = 0; | |
1ca96884 LB |
220 | if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || |
221 | check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { | |
2865d42c LF |
222 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); |
223 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); | |
224 | } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { | |
225 | memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); | |
226 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); | |
227 | } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { | |
228 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); | |
229 | memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); | |
1ca96884 | 230 | } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { |
2865d42c LF |
231 | /*firstly, filter packet not belongs to mp*/ |
232 | if (pattrib->ether_type != 0x8712) | |
233 | return _FAIL; | |
234 | /* for mp storing the txcmd per packet, | |
235 | * according to the info of txcmd to update pattrib */ | |
236 | /*get MP_TXDESC_SIZE bytes txcmd per packet*/ | |
e29d3ebc | 237 | _r8712_pktfile_read(&pktfile, (u8 *)&txdesc, TXDESC_SIZE); |
2865d42c LF |
238 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); |
239 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); | |
240 | pattrib->pctrl = 1; | |
241 | } | |
242 | /* r8712_xmitframe_coalesce() overwrite this!*/ | |
243 | pattrib->pktlen = pktfile.pkt_len; | |
244 | if (ETH_P_IP == pattrib->ether_type) { | |
245 | /* The following is for DHCP and ARP packet, we use cck1M to | |
246 | * tx these packets and let LPS awake some time | |
247 | * to prevent DHCP protocol fail */ | |
248 | u8 tmp[24]; | |
c5861b73 | 249 | |
2865d42c LF |
250 | _r8712_pktfile_read(&pktfile, &tmp[0], 24); |
251 | pattrib->dhcp_pkt = 0; | |
252 | if (pktfile.pkt_len > 282) {/*MINIMUM_DHCP_PACKET_SIZE)*/ | |
253 | if (ETH_P_IP == pattrib->ether_type) {/* IP header*/ | |
254 | if (((tmp[21] == 68) && (tmp[23] == 67)) || | |
255 | ((tmp[21] == 67) && (tmp[23] == 68))) { | |
256 | /* 68 : UDP BOOTP client | |
257 | * 67 : UDP BOOTP server | |
258 | * Use low rate to send DHCP packet.*/ | |
259 | pattrib->dhcp_pkt = 1; | |
260 | } | |
261 | } | |
262 | } | |
263 | } | |
264 | bmcast = IS_MCAST(pattrib->ra); | |
265 | /* get sta_info*/ | |
266 | if (bmcast) { | |
267 | psta = r8712_get_bcmc_stainfo(padapter); | |
268 | pattrib->mac_id = 4; | |
269 | } else { | |
1ca96884 | 270 | if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { |
2865d42c LF |
271 | psta = r8712_get_stainfo(pstapriv, |
272 | get_bssid(pmlmepriv)); | |
273 | pattrib->mac_id = 5; | |
274 | } else { | |
275 | psta = r8712_get_stainfo(pstapriv, pattrib->ra); | |
276 | if (psta == NULL) /* drop the pkt */ | |
277 | return _FAIL; | |
278 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) | |
279 | pattrib->mac_id = 5; | |
280 | else | |
281 | pattrib->mac_id = psta->mac_id; | |
282 | } | |
283 | } | |
284 | ||
285 | if (psta) { | |
286 | pattrib->psta = psta; | |
287 | } else { | |
288 | /* if we cannot get psta => drrp the pkt */ | |
289 | return _FAIL; | |
290 | } | |
291 | ||
292 | pattrib->ack_policy = 0; | |
293 | /* get ether_hdr_len */ | |
294 | pattrib->pkt_hdrlen = ETH_HLEN; | |
295 | ||
168a2c10 | 296 | if (pqospriv->qos_option) { |
2865d42c | 297 | r8712_set_qos(&pktfile, pattrib); |
168a2c10 | 298 | } else { |
2865d42c LF |
299 | pattrib->hdrlen = WLAN_HDR_A3_LEN; |
300 | pattrib->subtype = WIFI_DATA_TYPE; | |
301 | pattrib->priority = 0; | |
302 | } | |
1ca96884 | 303 | if (psta->ieee8021x_blocked) { |
2865d42c LF |
304 | pattrib->encrypt = 0; |
305 | if ((pattrib->ether_type != 0x888e) && | |
1ca96884 | 306 | !check_fwstate(pmlmepriv, WIFI_MP_STATE)) |
2865d42c | 307 | return _FAIL; |
168a2c10 | 308 | } else { |
2865d42c | 309 | GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); |
168a2c10 | 310 | } |
2865d42c LF |
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 && | |
1ca96884 LB |
334 | (padapter->securitypriv.sw_encrypt || |
335 | !psecuritypriv->hw_decrypted)) | |
2865d42c LF |
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.*/ | |
1ca96884 | 341 | if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) |
2865d42c LF |
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 | { | |
e29d3ebc | 349 | u32 curfragnum, length; |
2865d42c LF |
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}; | |
859171ca | 371 | pframe = pxmitframe->buf_addr + TXDESC_OFFSET; |
2865d42c LF |
372 | if (bmcst) { |
373 | if (!memcmp(psecuritypriv->XGrptxmickey | |
374 | [psecuritypriv->XGrpKeyid].skey, | |
375 | null_key, 16)) | |
376 | return _FAIL; | |
377 | /*start to calculate the mic code*/ | |
378 | r8712_secmicsetkey(&micdata, | |
379 | psecuritypriv-> | |
380 | XGrptxmickey[psecuritypriv-> | |
381 | XGrpKeyid].skey); | |
382 | } else { | |
383 | if (!memcmp(&stainfo->tkiptxmickey.skey[0], | |
384 | null_key, 16)) | |
385 | return _FAIL; | |
386 | /* start to calculate the mic code */ | |
387 | r8712_secmicsetkey(&micdata, | |
388 | &stainfo->tkiptxmickey.skey[0]); | |
389 | } | |
390 | if (pframe[1] & 1) { /* ToDS==1 */ | |
391 | r8712_secmicappend(&micdata, | |
392 | &pframe[16], 6); /*DA*/ | |
4ef2de5a | 393 | if (pframe[1] & 2) /* From Ds==1 */ |
2865d42c LF |
394 | r8712_secmicappend(&micdata, |
395 | &pframe[24], 6); | |
396 | else | |
397 | r8712_secmicappend(&micdata, | |
398 | &pframe[10], 6); | |
399 | } else { /* ToDS==0 */ | |
400 | r8712_secmicappend(&micdata, | |
401 | &pframe[4], 6); /* DA */ | |
4ef2de5a | 402 | if (pframe[1] & 2) /* From Ds==1 */ |
2865d42c LF |
403 | r8712_secmicappend(&micdata, |
404 | &pframe[16], 6); | |
405 | else | |
406 | r8712_secmicappend(&micdata, | |
407 | &pframe[10], 6); | |
408 | } | |
409 | if (pqospriv->qos_option == 1) | |
410 | priority[0] = (u8)pxmitframe-> | |
411 | attrib.priority; | |
412 | r8712_secmicappend(&micdata, &priority[0], 4); | |
413 | payload = pframe; | |
414 | for (curfragnum = 0; curfragnum < pattrib->nr_frags; | |
415 | curfragnum++) { | |
416 | payload = (u8 *)RND4((addr_t)(payload)); | |
4ef2de5a LB |
417 | payload = payload + pattrib-> |
418 | hdrlen + pattrib->iv_len; | |
2865d42c LF |
419 | if ((curfragnum + 1) == pattrib->nr_frags) { |
420 | length = pattrib->last_txcmdsz - | |
421 | pattrib->hdrlen - | |
422 | pattrib->iv_len - | |
423 | ((psecuritypriv->sw_encrypt) | |
424 | ? pattrib->icv_len : 0); | |
425 | r8712_secmicappend(&micdata, payload, | |
426 | length); | |
4ef2de5a | 427 | payload = payload + length; |
2865d42c LF |
428 | } else{ |
429 | length = pxmitpriv->frag_len - | |
4ef2de5a | 430 | pattrib->hdrlen - pattrib->iv_len - |
2865d42c LF |
431 | ((psecuritypriv->sw_encrypt) ? |
432 | pattrib->icv_len : 0); | |
433 | r8712_secmicappend(&micdata, payload, | |
434 | length); | |
435 | payload = payload + length + | |
436 | pattrib->icv_len; | |
437 | } | |
438 | } | |
439 | r8712_secgetmic(&micdata, &(mic[0])); | |
440 | /* add mic code and add the mic code length in | |
441 | * last_txcmdsz */ | |
442 | memcpy(payload, &(mic[0]), 8); | |
443 | pattrib->last_txcmdsz += 8; | |
4ef2de5a | 444 | payload = payload - pattrib->last_txcmdsz + 8; |
2865d42c LF |
445 | } |
446 | } | |
447 | return _SUCCESS; | |
448 | } | |
449 | ||
450 | static sint xmitframe_swencrypt(struct _adapter *padapter, | |
451 | struct xmit_frame *pxmitframe) | |
452 | { | |
453 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
454 | ||
455 | if (pattrib->bswenc) { | |
456 | switch (pattrib->encrypt) { | |
457 | case _WEP40_: | |
458 | case _WEP104_: | |
459 | r8712_wep_encrypt(padapter, (u8 *)pxmitframe); | |
460 | break; | |
461 | case _TKIP_: | |
462 | r8712_tkip_encrypt(padapter, (u8 *)pxmitframe); | |
463 | break; | |
464 | case _AES_: | |
465 | r8712_aes_encrypt(padapter, (u8 *)pxmitframe); | |
466 | break; | |
467 | default: | |
468 | break; | |
469 | } | |
470 | } | |
471 | return _SUCCESS; | |
472 | } | |
473 | ||
0636b460 | 474 | static sint make_wlanhdr(struct _adapter *padapter, u8 *hdr, |
2865d42c LF |
475 | struct pkt_attrib *pattrib) |
476 | { | |
477 | u16 *qc; | |
478 | ||
479 | struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr; | |
480 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
481 | struct qos_priv *pqospriv = &pmlmepriv->qospriv; | |
482 | u16 *fctrl = &pwlanhdr->frame_ctl; | |
c5861b73 | 483 | |
2865d42c LF |
484 | memset(hdr, 0, WLANHDR_OFFSET); |
485 | SetFrameSubType(fctrl, pattrib->subtype); | |
486 | if (pattrib->subtype & WIFI_DATA_TYPE) { | |
1ca96884 | 487 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { |
2865d42c LF |
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); | |
1ca96884 | 494 | } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { |
2865d42c LF |
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); | |
1ca96884 LB |
501 | } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || |
502 | check_fwstate(pmlmepriv, | |
503 | WIFI_ADHOC_MASTER_STATE)) { | |
2865d42c LF |
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); | |
1ca96884 | 508 | } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { |
2865d42c LF |
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); | |
168a2c10 | 513 | } else { |
2865d42c | 514 | return _FAIL; |
168a2c10 | 515 | } |
2865d42c LF |
516 | |
517 | if (pattrib->encrypt) | |
518 | SetPrivacy(fctrl); | |
519 | if (pqospriv->qos_option) { | |
520 | qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); | |
521 | if (pattrib->priority) | |
522 | SetPriority(qc, pattrib->priority); | |
523 | SetAckpolicy(qc, pattrib->ack_policy); | |
524 | } | |
525 | /* TODO: fill HT Control Field */ | |
526 | /* Update Seq Num will be handled by f/w */ | |
527 | { | |
528 | struct sta_info *psta; | |
2865d42c | 529 | sint bmcst = IS_MCAST(pattrib->ra); |
c5861b73 | 530 | |
168a2c10 | 531 | if (pattrib->psta) { |
2865d42c | 532 | psta = pattrib->psta; |
168a2c10 | 533 | } else { |
2865d42c LF |
534 | if (bmcst) |
535 | psta = r8712_get_bcmc_stainfo(padapter); | |
536 | else | |
537 | psta = | |
538 | r8712_get_stainfo(&padapter->stapriv, | |
539 | pattrib->ra); | |
540 | } | |
541 | if (psta) { | |
542 | psta->sta_xmitpriv.txseq_tid | |
543 | [pattrib->priority]++; | |
544 | psta->sta_xmitpriv.txseq_tid[pattrib->priority] | |
545 | &= 0xFFF; | |
546 | pattrib->seqnum = psta->sta_xmitpriv. | |
547 | txseq_tid[pattrib->priority]; | |
548 | SetSeqNum(hdr, pattrib->seqnum); | |
549 | } | |
550 | } | |
551 | } | |
552 | return _SUCCESS; | |
553 | } | |
554 | ||
555 | static sint r8712_put_snap(u8 *data, u16 h_proto) | |
556 | { | |
557 | struct ieee80211_snap_hdr *snap; | |
558 | const u8 *oui; | |
559 | ||
560 | snap = (struct ieee80211_snap_hdr *)data; | |
561 | snap->dsap = 0xaa; | |
562 | snap->ssap = 0xaa; | |
563 | snap->ctrl = 0x03; | |
564 | if (h_proto == 0x8137 || h_proto == 0x80f3) | |
565 | oui = P802_1H_OUI; | |
566 | else | |
567 | oui = RFC1042_OUI; | |
568 | snap->oui[0] = oui[0]; | |
569 | snap->oui[1] = oui[1]; | |
570 | snap->oui[2] = oui[2]; | |
571 | *(u16 *)(data + SNAP_SIZE) = htons(h_proto); | |
572 | return SNAP_SIZE + sizeof(u16); | |
573 | } | |
574 | ||
575 | /* | |
576 | * This sub-routine will perform all the following: | |
577 | * 1. remove 802.3 header. | |
578 | * 2. create wlan_header, based on the info in pxmitframe | |
579 | * 3. append sta's iv/ext-iv | |
580 | * 4. append LLC | |
581 | * 5. move frag chunk from pframe to pxmitframe->mem | |
582 | * 6. apply sw-encrypt, if necessary. | |
583 | */ | |
584 | sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt, | |
585 | struct xmit_frame *pxmitframe) | |
586 | { | |
587 | struct pkt_file pktfile; | |
588 | ||
589 | sint frg_len, mpdu_len, llc_sz; | |
590 | u32 mem_sz; | |
591 | u8 frg_inx; | |
592 | addr_t addr; | |
593 | u8 *pframe, *mem_start, *ptxdesc; | |
594 | struct sta_info *psta; | |
595 | struct security_priv *psecuritypriv = &padapter->securitypriv; | |
596 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
597 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
598 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
599 | u8 *pbuf_start; | |
600 | sint bmcst = IS_MCAST(pattrib->ra); | |
601 | ||
602 | if (pattrib->psta == NULL) | |
603 | return _FAIL; | |
604 | psta = pattrib->psta; | |
605 | if (pxmitframe->buf_addr == NULL) | |
606 | return _FAIL; | |
607 | pbuf_start = pxmitframe->buf_addr; | |
608 | ptxdesc = pbuf_start; | |
609 | mem_start = pbuf_start + TXDESC_OFFSET; | |
610 | if (make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) | |
611 | return _FAIL; | |
612 | _r8712_open_pktfile(pkt, &pktfile); | |
f95302ee | 613 | _r8712_pktfile_read(&pktfile, NULL, (uint) pattrib->pkt_hdrlen); |
1ca96884 | 614 | if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { |
2865d42c LF |
615 | /* truncate TXDESC_SIZE bytes txcmd if at mp mode for 871x */ |
616 | if (pattrib->ether_type == 0x8712) { | |
617 | /* take care - update_txdesc overwrite this */ | |
618 | _r8712_pktfile_read(&pktfile, ptxdesc, TXDESC_SIZE); | |
619 | } | |
620 | } | |
621 | pattrib->pktlen = pktfile.pkt_len; | |
622 | frg_inx = 0; | |
623 | frg_len = pxmitpriv->frag_len - 4; | |
624 | while (1) { | |
625 | llc_sz = 0; | |
626 | mpdu_len = frg_len; | |
627 | pframe = mem_start; | |
628 | SetMFrag(mem_start); | |
629 | pframe += pattrib->hdrlen; | |
630 | mpdu_len -= pattrib->hdrlen; | |
631 | /* adding icv, if necessary...*/ | |
632 | if (pattrib->iv_len) { | |
633 | if (psta != NULL) { | |
634 | switch (pattrib->encrypt) { | |
635 | case _WEP40_: | |
636 | case _WEP104_: | |
637 | WEP_IV(pattrib->iv, psta->txpn, | |
638 | (u8)psecuritypriv-> | |
639 | PrivacyKeyIndex); | |
640 | break; | |
641 | case _TKIP_: | |
642 | if (bmcst) | |
643 | TKIP_IV(pattrib->iv, | |
644 | psta->txpn, | |
645 | (u8)psecuritypriv-> | |
646 | XGrpKeyid); | |
647 | else | |
648 | TKIP_IV(pattrib->iv, psta->txpn, | |
649 | 0); | |
650 | break; | |
651 | case _AES_: | |
652 | if (bmcst) | |
653 | AES_IV(pattrib->iv, psta->txpn, | |
654 | (u8)psecuritypriv-> | |
655 | XGrpKeyid); | |
656 | else | |
657 | AES_IV(pattrib->iv, psta->txpn, | |
658 | 0); | |
659 | break; | |
660 | } | |
661 | } | |
662 | memcpy(pframe, pattrib->iv, pattrib->iv_len); | |
663 | pframe += pattrib->iv_len; | |
664 | mpdu_len -= pattrib->iv_len; | |
665 | } | |
666 | if (frg_inx == 0) { | |
667 | llc_sz = r8712_put_snap(pframe, pattrib->ether_type); | |
668 | pframe += llc_sz; | |
669 | mpdu_len -= llc_sz; | |
670 | } | |
671 | if ((pattrib->icv_len > 0) && (pattrib->bswenc)) | |
672 | mpdu_len -= pattrib->icv_len; | |
673 | if (bmcst) | |
674 | mem_sz = _r8712_pktfile_read(&pktfile, pframe, | |
675 | pattrib->pktlen); | |
676 | else | |
677 | mem_sz = _r8712_pktfile_read(&pktfile, pframe, | |
678 | mpdu_len); | |
679 | pframe += mem_sz; | |
680 | if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { | |
681 | memcpy(pframe, pattrib->icv, pattrib->icv_len); | |
682 | pframe += pattrib->icv_len; | |
683 | } | |
684 | frg_inx++; | |
1ca96884 | 685 | if (bmcst || r8712_endofpktfile(&pktfile)) { |
2865d42c LF |
686 | pattrib->nr_frags = frg_inx; |
687 | pattrib->last_txcmdsz = pattrib->hdrlen + | |
688 | pattrib->iv_len + | |
689 | ((pattrib->nr_frags == 1) ? | |
690 | llc_sz : 0) + | |
691 | ((pattrib->bswenc) ? | |
692 | pattrib->icv_len : 0) + mem_sz; | |
693 | ClearMFrag(mem_start); | |
694 | break; | |
695 | } | |
696 | addr = (addr_t)(pframe); | |
697 | mem_start = (unsigned char *)RND4(addr) + TXDESC_OFFSET; | |
698 | memcpy(mem_start, pbuf_start + TXDESC_OFFSET, pattrib->hdrlen); | |
699 | } | |
700 | ||
701 | if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) | |
702 | return _FAIL; | |
703 | xmitframe_swencrypt(padapter, pxmitframe); | |
704 | return _SUCCESS; | |
705 | } | |
706 | ||
707 | void r8712_update_protection(struct _adapter *padapter, u8 *ie, uint ie_len) | |
708 | { | |
709 | uint protection; | |
710 | u8 *perp; | |
711 | sint erp_len; | |
712 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
713 | struct registry_priv *pregistrypriv = &padapter->registrypriv; | |
714 | ||
715 | switch (pxmitpriv->vcs_setting) { | |
716 | case DISABLE_VCS: | |
717 | pxmitpriv->vcs = NONE_VCS; | |
718 | break; | |
719 | case ENABLE_VCS: | |
720 | break; | |
721 | case AUTO_VCS: | |
722 | default: | |
723 | perp = r8712_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len); | |
168a2c10 | 724 | if (perp == NULL) { |
2865d42c | 725 | pxmitpriv->vcs = NONE_VCS; |
168a2c10 | 726 | } else { |
2865d42c LF |
727 | protection = (*(perp + 2)) & BIT(1); |
728 | if (protection) { | |
729 | if (pregistrypriv->vcs_type == RTS_CTS) | |
730 | pxmitpriv->vcs = RTS_CTS; | |
731 | else | |
732 | pxmitpriv->vcs = CTS_TO_SELF; | |
168a2c10 | 733 | } else { |
2865d42c | 734 | pxmitpriv->vcs = NONE_VCS; |
168a2c10 | 735 | } |
2865d42c LF |
736 | } |
737 | break; | |
738 | } | |
739 | } | |
740 | ||
741 | struct xmit_buf *r8712_alloc_xmitbuf(struct xmit_priv *pxmitpriv) | |
742 | { | |
743 | unsigned long irqL; | |
744 | struct xmit_buf *pxmitbuf = NULL; | |
745 | struct list_head *plist, *phead; | |
746 | struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; | |
747 | ||
748 | spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); | |
168a2c10 | 749 | if (list_empty(&pfree_xmitbuf_queue->queue)) { |
2865d42c | 750 | pxmitbuf = NULL; |
168a2c10 | 751 | } else { |
e99a428a | 752 | phead = &pfree_xmitbuf_queue->queue; |
849fb0a8 | 753 | plist = phead->next; |
2865d42c | 754 | pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); |
29197b7c | 755 | list_del_init(&(pxmitbuf->list)); |
2865d42c LF |
756 | } |
757 | if (pxmitbuf != NULL) | |
758 | pxmitpriv->free_xmitbuf_cnt--; | |
759 | spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); | |
760 | return pxmitbuf; | |
761 | } | |
762 | ||
763 | int r8712_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) | |
764 | { | |
765 | unsigned long irqL; | |
766 | struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; | |
767 | ||
768 | if (pxmitbuf == NULL) | |
769 | return _FAIL; | |
770 | spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); | |
29197b7c | 771 | list_del_init(&pxmitbuf->list); |
e99a428a | 772 | list_add_tail(&(pxmitbuf->list), &pfree_xmitbuf_queue->queue); |
2865d42c LF |
773 | pxmitpriv->free_xmitbuf_cnt++; |
774 | spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); | |
775 | return _SUCCESS; | |
776 | } | |
777 | ||
778 | /* | |
779 | Calling context: | |
780 | 1. OS_TXENTRY | |
781 | 2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) | |
782 | ||
783 | If we turn on USE_RXTHREAD, then, no need for critical section. | |
784 | Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... | |
785 | ||
786 | Must be very very cautious... | |
787 | ||
788 | */ | |
789 | ||
790 | struct xmit_frame *r8712_alloc_xmitframe(struct xmit_priv *pxmitpriv) | |
791 | { | |
792 | /* | |
793 | Please remember to use all the osdep_service api, | |
794 | and lock/unlock or _enter/_exit critical to protect | |
795 | pfree_xmit_queue | |
796 | */ | |
797 | unsigned long irqL; | |
798 | struct xmit_frame *pxframe = NULL; | |
799 | struct list_head *plist, *phead; | |
800 | struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; | |
801 | ||
802 | spin_lock_irqsave(&pfree_xmit_queue->lock, irqL); | |
168a2c10 | 803 | if (list_empty(&pfree_xmit_queue->queue)) { |
2865d42c | 804 | pxframe = NULL; |
168a2c10 | 805 | } else { |
e99a428a | 806 | phead = &pfree_xmit_queue->queue; |
849fb0a8 | 807 | plist = phead->next; |
2865d42c | 808 | pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list); |
29197b7c | 809 | list_del_init(&(pxframe->list)); |
2865d42c LF |
810 | } |
811 | if (pxframe != NULL) { | |
812 | pxmitpriv->free_xmitframe_cnt--; | |
813 | pxframe->buf_addr = NULL; | |
814 | pxframe->pxmitbuf = NULL; | |
815 | pxframe->attrib.psta = NULL; | |
816 | pxframe->pkt = NULL; | |
817 | } | |
818 | spin_unlock_irqrestore(&pfree_xmit_queue->lock, irqL); | |
819 | return pxframe; | |
820 | } | |
821 | ||
822 | void r8712_free_xmitframe(struct xmit_priv *pxmitpriv, | |
823 | struct xmit_frame *pxmitframe) | |
824 | { | |
825 | unsigned long irqL; | |
826 | struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; | |
827 | struct _adapter *padapter = pxmitpriv->adapter; | |
828 | ||
829 | if (pxmitframe == NULL) | |
830 | return; | |
2865d42c | 831 | spin_lock_irqsave(&pfree_xmit_queue->lock, irqL); |
29197b7c | 832 | list_del_init(&pxmitframe->list); |
e29d3ebc | 833 | if (pxmitframe->pkt) |
f95302ee | 834 | pxmitframe->pkt = NULL; |
e99a428a | 835 | list_add_tail(&pxmitframe->list, &pfree_xmit_queue->queue); |
2865d42c LF |
836 | pxmitpriv->free_xmitframe_cnt++; |
837 | spin_unlock_irqrestore(&pfree_xmit_queue->lock, irqL); | |
838 | if (netif_queue_stopped(padapter->pnetdev)) | |
839 | netif_wake_queue(padapter->pnetdev); | |
840 | } | |
841 | ||
842 | void r8712_free_xmitframe_ex(struct xmit_priv *pxmitpriv, | |
843 | struct xmit_frame *pxmitframe) | |
844 | { | |
845 | if (pxmitframe == NULL) | |
846 | return; | |
847 | if (pxmitframe->frame_tag == DATA_FRAMETAG) | |
848 | r8712_free_xmitframe(pxmitpriv, pxmitframe); | |
849 | } | |
850 | ||
851 | void r8712_free_xmitframe_queue(struct xmit_priv *pxmitpriv, | |
852 | struct __queue *pframequeue) | |
853 | { | |
854 | unsigned long irqL; | |
855 | struct list_head *plist, *phead; | |
856 | struct xmit_frame *pxmitframe; | |
857 | ||
858 | spin_lock_irqsave(&(pframequeue->lock), irqL); | |
e99a428a | 859 | phead = &pframequeue->queue; |
849fb0a8 | 860 | plist = phead->next; |
1ca96884 | 861 | while (!end_of_queue_search(phead, plist)) { |
2865d42c | 862 | pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list); |
849fb0a8 | 863 | plist = plist->next; |
2865d42c LF |
864 | r8712_free_xmitframe(pxmitpriv, pxmitframe); |
865 | } | |
866 | spin_unlock_irqrestore(&(pframequeue->lock), irqL); | |
867 | } | |
868 | ||
869 | static inline struct tx_servq *get_sta_pending(struct _adapter *padapter, | |
870 | struct __queue **ppstapending, | |
871 | struct sta_info *psta, sint up) | |
872 | { | |
873 | ||
874 | struct tx_servq *ptxservq; | |
875 | struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; | |
876 | ||
877 | switch (up) { | |
878 | case 1: | |
879 | case 2: | |
880 | ptxservq = &(psta->sta_xmitpriv.bk_q); | |
881 | *ppstapending = &padapter->xmitpriv.bk_pending; | |
4ef2de5a | 882 | (phwxmits + 3)->accnt++; |
2865d42c LF |
883 | break; |
884 | case 4: | |
885 | case 5: | |
886 | ptxservq = &(psta->sta_xmitpriv.vi_q); | |
887 | *ppstapending = &padapter->xmitpriv.vi_pending; | |
4ef2de5a | 888 | (phwxmits + 1)->accnt++; |
2865d42c LF |
889 | break; |
890 | case 6: | |
891 | case 7: | |
892 | ptxservq = &(psta->sta_xmitpriv.vo_q); | |
893 | *ppstapending = &padapter->xmitpriv.vo_pending; | |
4ef2de5a | 894 | (phwxmits + 0)->accnt++; |
2865d42c LF |
895 | break; |
896 | case 0: | |
897 | case 3: | |
898 | default: | |
899 | ptxservq = &(psta->sta_xmitpriv.be_q); | |
900 | *ppstapending = &padapter->xmitpriv.be_pending; | |
901 | (phwxmits + 2)->accnt++; | |
902 | break; | |
903 | } | |
904 | return ptxservq; | |
905 | } | |
906 | ||
907 | /* | |
908 | * Will enqueue pxmitframe to the proper queue, and indicate it | |
909 | * to xx_pending list..... | |
910 | */ | |
911 | sint r8712_xmit_classifier(struct _adapter *padapter, | |
912 | struct xmit_frame *pxmitframe) | |
913 | { | |
914 | unsigned long irqL0; | |
915 | struct __queue *pstapending; | |
916 | struct sta_info *psta; | |
917 | struct tx_servq *ptxservq; | |
918 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
919 | struct sta_priv *pstapriv = &padapter->stapriv; | |
920 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
921 | sint bmcst = IS_MCAST(pattrib->ra); | |
922 | ||
168a2c10 | 923 | if (pattrib->psta) { |
2865d42c | 924 | psta = pattrib->psta; |
168a2c10 LB |
925 | } else { |
926 | if (bmcst) { | |
2865d42c | 927 | psta = r8712_get_bcmc_stainfo(padapter); |
168a2c10 | 928 | } else { |
1ca96884 | 929 | if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) |
2865d42c LF |
930 | psta = r8712_get_stainfo(pstapriv, |
931 | get_bssid(pmlmepriv)); | |
932 | else | |
933 | psta = r8712_get_stainfo(pstapriv, pattrib->ra); | |
934 | } | |
935 | } | |
936 | if (psta == NULL) | |
937 | return _FAIL; | |
938 | ptxservq = get_sta_pending(padapter, &pstapending, | |
939 | psta, pattrib->priority); | |
940 | spin_lock_irqsave(&pstapending->lock, irqL0); | |
9672b1bd | 941 | if (list_empty(&ptxservq->tx_pending)) |
e99a428a JS |
942 | list_add_tail(&ptxservq->tx_pending, &pstapending->queue); |
943 | list_add_tail(&pxmitframe->list, &ptxservq->sta_pending.queue); | |
2865d42c LF |
944 | ptxservq->qcnt++; |
945 | spin_unlock_irqrestore(&pstapending->lock, irqL0); | |
946 | return _SUCCESS; | |
947 | } | |
948 | ||
949 | static void alloc_hwxmits(struct _adapter *padapter) | |
950 | { | |
951 | struct hw_xmit *hwxmits; | |
952 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
953 | ||
954 | pxmitpriv->hwxmit_entry = HWXMIT_ENTRY; | |
9d76a7e4 TP |
955 | pxmitpriv->hwxmits = kmalloc_array(pxmitpriv->hwxmit_entry, |
956 | sizeof(struct hw_xmit), GFP_ATOMIC); | |
2865d42c LF |
957 | if (pxmitpriv->hwxmits == NULL) |
958 | return; | |
959 | hwxmits = pxmitpriv->hwxmits; | |
960 | if (pxmitpriv->hwxmit_entry == 5) { | |
961 | pxmitpriv->bmc_txqueue.head = 0; | |
962 | hwxmits[0] .phwtxqueue = &pxmitpriv->bmc_txqueue; | |
963 | hwxmits[0] .sta_queue = &pxmitpriv->bm_pending; | |
964 | pxmitpriv->vo_txqueue.head = 0; | |
965 | hwxmits[1] .phwtxqueue = &pxmitpriv->vo_txqueue; | |
966 | hwxmits[1] .sta_queue = &pxmitpriv->vo_pending; | |
967 | pxmitpriv->vi_txqueue.head = 0; | |
968 | hwxmits[2] .phwtxqueue = &pxmitpriv->vi_txqueue; | |
969 | hwxmits[2] .sta_queue = &pxmitpriv->vi_pending; | |
970 | pxmitpriv->bk_txqueue.head = 0; | |
971 | hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; | |
972 | hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; | |
973 | pxmitpriv->be_txqueue.head = 0; | |
974 | hwxmits[4] .phwtxqueue = &pxmitpriv->be_txqueue; | |
975 | hwxmits[4] .sta_queue = &pxmitpriv->be_pending; | |
976 | } else if (pxmitpriv->hwxmit_entry == 4) { | |
977 | pxmitpriv->vo_txqueue.head = 0; | |
978 | hwxmits[0] .phwtxqueue = &pxmitpriv->vo_txqueue; | |
979 | hwxmits[0] .sta_queue = &pxmitpriv->vo_pending; | |
980 | pxmitpriv->vi_txqueue.head = 0; | |
981 | hwxmits[1] .phwtxqueue = &pxmitpriv->vi_txqueue; | |
982 | hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; | |
983 | pxmitpriv->be_txqueue.head = 0; | |
984 | hwxmits[2] .phwtxqueue = &pxmitpriv->be_txqueue; | |
985 | hwxmits[2] .sta_queue = &pxmitpriv->be_pending; | |
986 | pxmitpriv->bk_txqueue.head = 0; | |
987 | hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; | |
988 | hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; | |
989 | } | |
990 | } | |
991 | ||
992 | static void free_hwxmits(struct _adapter *padapter) | |
993 | { | |
994 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
995 | ||
40083865 | 996 | kfree(pxmitpriv->hwxmits); |
2865d42c LF |
997 | } |
998 | ||
999 | static void init_hwxmits(struct hw_xmit *phwxmit, sint entry) | |
1000 | { | |
1001 | sint i; | |
1002 | ||
1003 | for (i = 0; i < entry; i++, phwxmit++) { | |
1004 | spin_lock_init(&phwxmit->xmit_lock); | |
534c4acd | 1005 | INIT_LIST_HEAD(&phwxmit->pending); |
2865d42c LF |
1006 | phwxmit->txcmdcnt = 0; |
1007 | phwxmit->accnt = 0; | |
1008 | } | |
1009 | } | |
1010 | ||
07a6b037 AB |
1011 | void xmitframe_xmitbuf_attach(struct xmit_frame *pxmitframe, |
1012 | struct xmit_buf *pxmitbuf) | |
1013 | { | |
1014 | /* pxmitbuf attach to pxmitframe */ | |
1015 | pxmitframe->pxmitbuf = pxmitbuf; | |
1016 | /* urb and irp connection */ | |
1017 | pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; | |
1018 | /* buffer addr assoc */ | |
1019 | pxmitframe->buf_addr = pxmitbuf->pbuf; | |
1020 | /* pxmitframe attach to pxmitbuf */ | |
1021 | pxmitbuf->priv_data = pxmitframe; | |
1022 | } | |
1023 | ||
2865d42c LF |
1024 | /* |
1025 | * tx_action == 0 == no frames to transmit | |
1026 | * tx_action > 0 ==> we have frames to transmit | |
1027 | * tx_action < 0 ==> we have frames to transmit, but TXFF is not even enough | |
1028 | * to transmit 1 frame. | |
1029 | */ | |
1030 | ||
1031 | int r8712_pre_xmit(struct _adapter *padapter, struct xmit_frame *pxmitframe) | |
1032 | { | |
1033 | unsigned long irqL; | |
1034 | int ret; | |
1035 | struct xmit_buf *pxmitbuf = NULL; | |
1036 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
1037 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
1038 | ||
1039 | r8712_do_queue_select(padapter, pattrib); | |
1040 | spin_lock_irqsave(&pxmitpriv->lock, irqL); | |
1041 | if (r8712_txframes_sta_ac_pending(padapter, pattrib) > 0) { | |
1042 | ret = false; | |
1043 | r8712_xmit_enqueue(padapter, pxmitframe); | |
1044 | spin_unlock_irqrestore(&pxmitpriv->lock, irqL); | |
1045 | return ret; | |
1046 | } | |
1047 | pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv); | |
1048 | if (pxmitbuf == NULL) { /*enqueue packet*/ | |
1049 | ret = false; | |
1050 | r8712_xmit_enqueue(padapter, pxmitframe); | |
1051 | spin_unlock_irqrestore(&pxmitpriv->lock, irqL); | |
1052 | } else { /*dump packet directly*/ | |
1053 | spin_unlock_irqrestore(&pxmitpriv->lock, irqL); | |
1054 | ret = true; | |
07a6b037 | 1055 | xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); |
2865d42c LF |
1056 | r8712_xmit_direct(padapter, pxmitframe); |
1057 | } | |
1058 | return ret; | |
1059 | } |