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