1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. |
5 | * |
6 | ******************************************************************************/ |
7 | #include <drv_types.h> |
8 | #include <rtw_debug.h> |
9 | |
10 | static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; |
11 | static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; |
12 | |
13 | static void _init_txservq(struct tx_servq *ptxservq) |
14 | { |
15 | INIT_LIST_HEAD(list: &ptxservq->tx_pending); |
16 | INIT_LIST_HEAD(list: &ptxservq->sta_pending.queue); |
17 | spin_lock_init(&ptxservq->sta_pending.lock); |
18 | ptxservq->qcnt = 0; |
19 | } |
20 | |
21 | void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) |
22 | { |
23 | memset((unsigned char *)psta_xmitpriv, 0, sizeof(struct sta_xmit_priv)); |
24 | |
25 | spin_lock_init(&psta_xmitpriv->lock); |
26 | |
27 | _init_txservq(ptxservq: &psta_xmitpriv->be_q); |
28 | _init_txservq(ptxservq: &psta_xmitpriv->bk_q); |
29 | _init_txservq(ptxservq: &psta_xmitpriv->vi_q); |
30 | _init_txservq(ptxservq: &psta_xmitpriv->vo_q); |
31 | INIT_LIST_HEAD(list: &psta_xmitpriv->legacy_dz); |
32 | INIT_LIST_HEAD(list: &psta_xmitpriv->apsd); |
33 | } |
34 | |
35 | s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) |
36 | { |
37 | int i; |
38 | struct xmit_buf *pxmitbuf; |
39 | struct xmit_frame *pxframe; |
40 | signed int res = _SUCCESS; |
41 | |
42 | spin_lock_init(&pxmitpriv->lock); |
43 | spin_lock_init(&pxmitpriv->lock_sctx); |
44 | init_completion(x: &pxmitpriv->xmit_comp); |
45 | init_completion(x: &pxmitpriv->terminate_xmitthread_comp); |
46 | |
47 | /* |
48 | * Please insert all the queue initializaiton using _rtw_init_queue below |
49 | */ |
50 | |
51 | pxmitpriv->adapter = padapter; |
52 | |
53 | INIT_LIST_HEAD(list: &pxmitpriv->be_pending.queue); |
54 | spin_lock_init(&pxmitpriv->be_pending.lock); |
55 | INIT_LIST_HEAD(list: &pxmitpriv->bk_pending.queue); |
56 | spin_lock_init(&pxmitpriv->bk_pending.lock); |
57 | INIT_LIST_HEAD(list: &pxmitpriv->vi_pending.queue); |
58 | spin_lock_init(&pxmitpriv->vi_pending.lock); |
59 | INIT_LIST_HEAD(list: &pxmitpriv->vo_pending.queue); |
60 | spin_lock_init(&pxmitpriv->vo_pending.lock); |
61 | INIT_LIST_HEAD(list: &pxmitpriv->bm_pending.queue); |
62 | spin_lock_init(&pxmitpriv->bm_pending.lock); |
63 | |
64 | INIT_LIST_HEAD(list: &pxmitpriv->free_xmit_queue.queue); |
65 | spin_lock_init(&pxmitpriv->free_xmit_queue.lock); |
66 | |
67 | /* |
68 | * Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME, |
69 | * and initialize free_xmit_frame below. |
70 | * Please also apply free_txobj to link_up all the xmit_frames... |
71 | */ |
72 | |
73 | pxmitpriv->pallocated_frame_buf = vzalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4); |
74 | |
75 | if (!pxmitpriv->pallocated_frame_buf) { |
76 | pxmitpriv->pxmit_frame_buf = NULL; |
77 | res = _FAIL; |
78 | goto exit; |
79 | } |
80 | pxmitpriv->pxmit_frame_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_frame_buf), 4); |
81 | |
82 | pxframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf; |
83 | |
84 | for (i = 0; i < NR_XMITFRAME; i++) { |
85 | INIT_LIST_HEAD(list: &pxframe->list); |
86 | |
87 | pxframe->padapter = padapter; |
88 | pxframe->frame_tag = NULL_FRAMETAG; |
89 | |
90 | pxframe->pkt = NULL; |
91 | |
92 | pxframe->buf_addr = NULL; |
93 | pxframe->pxmitbuf = NULL; |
94 | |
95 | list_add_tail(new: &pxframe->list, |
96 | head: &pxmitpriv->free_xmit_queue.queue); |
97 | |
98 | pxframe++; |
99 | } |
100 | |
101 | pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME; |
102 | |
103 | pxmitpriv->frag_len = MAX_FRAG_THRESHOLD; |
104 | |
105 | /* init xmit_buf */ |
106 | INIT_LIST_HEAD(list: &pxmitpriv->free_xmitbuf_queue.queue); |
107 | spin_lock_init(&pxmitpriv->free_xmitbuf_queue.lock); |
108 | INIT_LIST_HEAD(list: &pxmitpriv->pending_xmitbuf_queue.queue); |
109 | spin_lock_init(&pxmitpriv->pending_xmitbuf_queue.lock); |
110 | |
111 | pxmitpriv->pallocated_xmitbuf = vzalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4); |
112 | |
113 | if (!pxmitpriv->pallocated_xmitbuf) { |
114 | res = _FAIL; |
115 | goto exit; |
116 | } |
117 | |
118 | pxmitpriv->pxmitbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_xmitbuf), 4); |
119 | |
120 | pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; |
121 | |
122 | for (i = 0; i < NR_XMITBUFF; i++) { |
123 | INIT_LIST_HEAD(list: &pxmitbuf->list); |
124 | |
125 | pxmitbuf->priv_data = NULL; |
126 | pxmitbuf->padapter = padapter; |
127 | pxmitbuf->buf_tag = XMITBUF_DATA; |
128 | |
129 | /* Tx buf allocation may fail sometimes, so sleep and retry. */ |
130 | res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, alloc_sz: (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ), flag: true); |
131 | if (res == _FAIL) { |
132 | msleep(msecs: 10); |
133 | res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, alloc_sz: (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ), flag: true); |
134 | if (res == _FAIL) |
135 | goto exit; |
136 | } |
137 | |
138 | pxmitbuf->phead = pxmitbuf->pbuf; |
139 | pxmitbuf->pend = pxmitbuf->pbuf + MAX_XMITBUF_SZ; |
140 | pxmitbuf->len = 0; |
141 | pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; |
142 | |
143 | pxmitbuf->flags = XMIT_VO_QUEUE; |
144 | |
145 | list_add_tail(new: &pxmitbuf->list, |
146 | head: &pxmitpriv->free_xmitbuf_queue.queue); |
147 | #ifdef DBG_XMIT_BUF |
148 | pxmitbuf->no = i; |
149 | #endif |
150 | |
151 | pxmitbuf++; |
152 | } |
153 | |
154 | pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; |
155 | |
156 | /* init xframe_ext queue, the same count as extbuf */ |
157 | INIT_LIST_HEAD(list: &pxmitpriv->free_xframe_ext_queue.queue); |
158 | spin_lock_init(&pxmitpriv->free_xframe_ext_queue.lock); |
159 | |
160 | pxmitpriv->xframe_ext_alloc_addr = vzalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_frame) + 4); |
161 | |
162 | if (!pxmitpriv->xframe_ext_alloc_addr) { |
163 | pxmitpriv->xframe_ext = NULL; |
164 | res = _FAIL; |
165 | goto exit; |
166 | } |
167 | pxmitpriv->xframe_ext = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->xframe_ext_alloc_addr), 4); |
168 | pxframe = (struct xmit_frame *)pxmitpriv->xframe_ext; |
169 | |
170 | for (i = 0; i < NR_XMIT_EXTBUFF; i++) { |
171 | INIT_LIST_HEAD(list: &pxframe->list); |
172 | |
173 | pxframe->padapter = padapter; |
174 | pxframe->frame_tag = NULL_FRAMETAG; |
175 | |
176 | pxframe->pkt = NULL; |
177 | |
178 | pxframe->buf_addr = NULL; |
179 | pxframe->pxmitbuf = NULL; |
180 | |
181 | pxframe->ext_tag = 1; |
182 | |
183 | list_add_tail(new: &pxframe->list, |
184 | head: &pxmitpriv->free_xframe_ext_queue.queue); |
185 | |
186 | pxframe++; |
187 | } |
188 | pxmitpriv->free_xframe_ext_cnt = NR_XMIT_EXTBUFF; |
189 | |
190 | /* Init xmit extension buff */ |
191 | INIT_LIST_HEAD(list: &pxmitpriv->free_xmit_extbuf_queue.queue); |
192 | spin_lock_init(&pxmitpriv->free_xmit_extbuf_queue.lock); |
193 | |
194 | pxmitpriv->pallocated_xmit_extbuf = vzalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_buf) + 4); |
195 | |
196 | if (!pxmitpriv->pallocated_xmit_extbuf) { |
197 | res = _FAIL; |
198 | goto exit; |
199 | } |
200 | |
201 | pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_xmit_extbuf), 4); |
202 | |
203 | pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; |
204 | |
205 | for (i = 0; i < NR_XMIT_EXTBUFF; i++) { |
206 | INIT_LIST_HEAD(list: &pxmitbuf->list); |
207 | |
208 | pxmitbuf->priv_data = NULL; |
209 | pxmitbuf->padapter = padapter; |
210 | pxmitbuf->buf_tag = XMITBUF_MGNT; |
211 | |
212 | res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, MAX_XMIT_EXTBUF_SZ + XMITBUF_ALIGN_SZ, flag: true); |
213 | if (res == _FAIL) { |
214 | res = _FAIL; |
215 | goto exit; |
216 | } |
217 | |
218 | pxmitbuf->phead = pxmitbuf->pbuf; |
219 | pxmitbuf->pend = pxmitbuf->pbuf + MAX_XMIT_EXTBUF_SZ; |
220 | pxmitbuf->len = 0; |
221 | pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; |
222 | |
223 | list_add_tail(new: &pxmitbuf->list, |
224 | head: &pxmitpriv->free_xmit_extbuf_queue.queue); |
225 | #ifdef DBG_XMIT_BUF_EXT |
226 | pxmitbuf->no = i; |
227 | #endif |
228 | pxmitbuf++; |
229 | } |
230 | |
231 | pxmitpriv->free_xmit_extbuf_cnt = NR_XMIT_EXTBUFF; |
232 | |
233 | for (i = 0; i < CMDBUF_MAX; i++) { |
234 | pxmitbuf = &pxmitpriv->pcmd_xmitbuf[i]; |
235 | if (pxmitbuf) { |
236 | INIT_LIST_HEAD(list: &pxmitbuf->list); |
237 | |
238 | pxmitbuf->priv_data = NULL; |
239 | pxmitbuf->padapter = padapter; |
240 | pxmitbuf->buf_tag = XMITBUF_CMD; |
241 | |
242 | res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, MAX_CMDBUF_SZ+XMITBUF_ALIGN_SZ, flag: true); |
243 | if (res == _FAIL) { |
244 | res = _FAIL; |
245 | goto exit; |
246 | } |
247 | |
248 | pxmitbuf->phead = pxmitbuf->pbuf; |
249 | pxmitbuf->pend = pxmitbuf->pbuf + MAX_CMDBUF_SZ; |
250 | pxmitbuf->len = 0; |
251 | pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; |
252 | pxmitbuf->alloc_sz = MAX_CMDBUF_SZ+XMITBUF_ALIGN_SZ; |
253 | } |
254 | } |
255 | |
256 | res = rtw_alloc_hwxmits(padapter); |
257 | if (res == _FAIL) |
258 | goto exit; |
259 | rtw_init_hwxmits(phwxmit: pxmitpriv->hwxmits, entry: pxmitpriv->hwxmit_entry); |
260 | |
261 | for (i = 0; i < 4; i++) |
262 | pxmitpriv->wmm_para_seq[i] = i; |
263 | |
264 | pxmitpriv->ack_tx = false; |
265 | mutex_init(&pxmitpriv->ack_tx_mutex); |
266 | rtw_sctx_init(sctx: &pxmitpriv->ack_tx_ops, timeout_ms: 0); |
267 | |
268 | rtw_hal_init_xmit_priv(padapter); |
269 | |
270 | exit: |
271 | return res; |
272 | } |
273 | |
274 | void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv) |
275 | { |
276 | int i; |
277 | struct adapter *padapter = pxmitpriv->adapter; |
278 | struct xmit_frame *pxmitframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf; |
279 | struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; |
280 | |
281 | rtw_hal_free_xmit_priv(padapter); |
282 | |
283 | if (!pxmitpriv->pxmit_frame_buf) |
284 | return; |
285 | |
286 | for (i = 0; i < NR_XMITFRAME; i++) { |
287 | rtw_os_xmit_complete(padapter, pxframe: pxmitframe); |
288 | |
289 | pxmitframe++; |
290 | } |
291 | |
292 | for (i = 0; i < NR_XMITBUFF; i++) { |
293 | rtw_os_xmit_resource_free(padapter, pxmitbuf, free_sz: (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ), flag: true); |
294 | |
295 | pxmitbuf++; |
296 | } |
297 | |
298 | vfree(addr: pxmitpriv->pallocated_frame_buf); |
299 | vfree(addr: pxmitpriv->pallocated_xmitbuf); |
300 | |
301 | /* free xframe_ext queue, the same count as extbuf */ |
302 | pxmitframe = (struct xmit_frame *)pxmitpriv->xframe_ext; |
303 | if (pxmitframe) { |
304 | for (i = 0; i < NR_XMIT_EXTBUFF; i++) { |
305 | rtw_os_xmit_complete(padapter, pxframe: pxmitframe); |
306 | pxmitframe++; |
307 | } |
308 | } |
309 | |
310 | vfree(addr: pxmitpriv->xframe_ext_alloc_addr); |
311 | |
312 | /* free xmit extension buff */ |
313 | pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; |
314 | for (i = 0; i < NR_XMIT_EXTBUFF; i++) { |
315 | rtw_os_xmit_resource_free(padapter, pxmitbuf, free_sz: (MAX_XMIT_EXTBUF_SZ + XMITBUF_ALIGN_SZ), flag: true); |
316 | |
317 | pxmitbuf++; |
318 | } |
319 | |
320 | vfree(addr: pxmitpriv->pallocated_xmit_extbuf); |
321 | |
322 | for (i = 0; i < CMDBUF_MAX; i++) { |
323 | pxmitbuf = &pxmitpriv->pcmd_xmitbuf[i]; |
324 | if (pxmitbuf) |
325 | rtw_os_xmit_resource_free(padapter, pxmitbuf, MAX_CMDBUF_SZ+XMITBUF_ALIGN_SZ, flag: true); |
326 | } |
327 | |
328 | rtw_free_hwxmits(padapter); |
329 | |
330 | mutex_destroy(lock: &pxmitpriv->ack_tx_mutex); |
331 | } |
332 | |
333 | u8 query_ra_short_GI(struct sta_info *psta) |
334 | { |
335 | u8 sgi = false, sgi_20m = false, sgi_40m = false; |
336 | |
337 | sgi_20m = psta->htpriv.sgi_20m; |
338 | sgi_40m = psta->htpriv.sgi_40m; |
339 | |
340 | switch (psta->bw_mode) { |
341 | case CHANNEL_WIDTH_40: |
342 | sgi = sgi_40m; |
343 | break; |
344 | case CHANNEL_WIDTH_20: |
345 | default: |
346 | sgi = sgi_20m; |
347 | break; |
348 | } |
349 | |
350 | return sgi; |
351 | } |
352 | |
353 | static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame *pxmitframe) |
354 | { |
355 | u32 sz; |
356 | struct pkt_attrib *pattrib = &pxmitframe->attrib; |
357 | /* struct sta_info *psta = pattrib->psta; */ |
358 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
359 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
360 | |
361 | if (pattrib->nr_frags != 1) |
362 | sz = padapter->xmitpriv.frag_len; |
363 | else /* no frag */ |
364 | sz = pattrib->last_txcmdsz; |
365 | |
366 | /* (1) RTS_Threshold is compared to the MPDU, not MSDU. */ |
367 | /* (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. */ |
368 | /* Other fragments are protected by previous fragment. */ |
369 | /* So we only need to check the length of first fragment. */ |
370 | if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) { |
371 | if (sz > padapter->registrypriv.rts_thresh) { |
372 | pattrib->vcs_mode = RTS_CTS; |
373 | } else { |
374 | if (pattrib->rtsen) |
375 | pattrib->vcs_mode = RTS_CTS; |
376 | else if (pattrib->cts2self) |
377 | pattrib->vcs_mode = CTS_TO_SELF; |
378 | else |
379 | pattrib->vcs_mode = NONE_VCS; |
380 | } |
381 | } else { |
382 | while (true) { |
383 | /* IOT action */ |
384 | if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) && (pattrib->ampdu_en == true) && |
385 | (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { |
386 | pattrib->vcs_mode = CTS_TO_SELF; |
387 | break; |
388 | } |
389 | |
390 | /* check ERP protection */ |
391 | if (pattrib->rtsen || pattrib->cts2self) { |
392 | if (pattrib->rtsen) |
393 | pattrib->vcs_mode = RTS_CTS; |
394 | else if (pattrib->cts2self) |
395 | pattrib->vcs_mode = CTS_TO_SELF; |
396 | |
397 | break; |
398 | } |
399 | |
400 | /* check HT op mode */ |
401 | if (pattrib->ht_en) { |
402 | u8 HTOpMode = pmlmeinfo->HT_protection; |
403 | |
404 | if ((pmlmeext->cur_bwmode && (HTOpMode == 2 || HTOpMode == 3)) || |
405 | (!pmlmeext->cur_bwmode && HTOpMode == 3)) { |
406 | pattrib->vcs_mode = RTS_CTS; |
407 | break; |
408 | } |
409 | } |
410 | |
411 | /* check rts */ |
412 | if (sz > padapter->registrypriv.rts_thresh) { |
413 | pattrib->vcs_mode = RTS_CTS; |
414 | break; |
415 | } |
416 | |
417 | /* to do list: check MIMO power save condition. */ |
418 | |
419 | /* check AMPDU aggregation for TXOP */ |
420 | if (pattrib->ampdu_en == true) { |
421 | pattrib->vcs_mode = RTS_CTS; |
422 | break; |
423 | } |
424 | |
425 | pattrib->vcs_mode = NONE_VCS; |
426 | break; |
427 | } |
428 | } |
429 | |
430 | /* for debug : force driver control vrtl_carrier_sense. */ |
431 | if (padapter->driver_vcs_en == 1) |
432 | pattrib->vcs_mode = padapter->driver_vcs_type; |
433 | } |
434 | |
435 | static void update_attrib_phy_info(struct adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta) |
436 | { |
437 | struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv; |
438 | |
439 | pattrib->rtsen = psta->rtsen; |
440 | pattrib->cts2self = psta->cts2self; |
441 | |
442 | pattrib->mdata = 0; |
443 | pattrib->eosp = 0; |
444 | pattrib->triggered = 0; |
445 | pattrib->ampdu_spacing = 0; |
446 | |
447 | /* qos_en, ht_en, init rate, , bw, ch_offset, sgi */ |
448 | pattrib->qos_en = psta->qos_option; |
449 | |
450 | pattrib->raid = psta->raid; |
451 | |
452 | pattrib->bwmode = min(mlmeext->cur_bwmode, psta->bw_mode); |
453 | |
454 | pattrib->sgi = query_ra_short_GI(psta); |
455 | |
456 | pattrib->ldpc = psta->ldpc; |
457 | pattrib->stbc = psta->stbc; |
458 | |
459 | pattrib->ht_en = psta->htpriv.ht_option; |
460 | pattrib->ch_offset = psta->htpriv.ch_offset; |
461 | pattrib->ampdu_en = false; |
462 | |
463 | if (padapter->driver_ampdu_spacing != 0xFF) /* driver control AMPDU Density for peer sta's rx */ |
464 | pattrib->ampdu_spacing = padapter->driver_ampdu_spacing; |
465 | else |
466 | pattrib->ampdu_spacing = psta->htpriv.rx_ampdu_min_spacing; |
467 | |
468 | pattrib->retry_ctrl = false; |
469 | } |
470 | |
471 | static s32 update_attrib_sec_info(struct adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta) |
472 | { |
473 | signed int res = _SUCCESS; |
474 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
475 | struct security_priv *psecuritypriv = &padapter->securitypriv; |
476 | signed int bmcast = is_multicast_ether_addr(addr: pattrib->ra); |
477 | |
478 | memset(pattrib->dot118021x_UncstKey.skey, 0, 16); |
479 | memset(pattrib->dot11tkiptxmickey.skey, 0, 16); |
480 | pattrib->mac_id = psta->mac_id; |
481 | |
482 | if (psta->ieee8021x_blocked == true) { |
483 | pattrib->encrypt = 0; |
484 | |
485 | if ((pattrib->ether_type != 0x888e) && (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false)) { |
486 | res = _FAIL; |
487 | goto exit; |
488 | } |
489 | } else { |
490 | GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); |
491 | |
492 | switch (psecuritypriv->dot11AuthAlgrthm) { |
493 | case dot11AuthAlgrthm_Open: |
494 | case dot11AuthAlgrthm_Shared: |
495 | case dot11AuthAlgrthm_Auto: |
496 | pattrib->key_idx = (u8)psecuritypriv->dot11PrivacyKeyIndex; |
497 | break; |
498 | case dot11AuthAlgrthm_8021X: |
499 | if (bmcast) |
500 | pattrib->key_idx = (u8)psecuritypriv->dot118021XGrpKeyid; |
501 | else |
502 | pattrib->key_idx = 0; |
503 | break; |
504 | default: |
505 | pattrib->key_idx = 0; |
506 | break; |
507 | } |
508 | |
509 | /* For WPS 1.0 WEP, driver should not encrypt EAPOL Packet for WPS handshake. */ |
510 | if (((pattrib->encrypt == _WEP40_) || (pattrib->encrypt == _WEP104_)) && (pattrib->ether_type == 0x888e)) |
511 | pattrib->encrypt = _NO_PRIVACY_; |
512 | } |
513 | |
514 | switch (pattrib->encrypt) { |
515 | case _WEP40_: |
516 | case _WEP104_: |
517 | pattrib->iv_len = 4; |
518 | pattrib->icv_len = 4; |
519 | WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); |
520 | break; |
521 | |
522 | case _TKIP_: |
523 | pattrib->iv_len = 8; |
524 | pattrib->icv_len = 4; |
525 | |
526 | if (psecuritypriv->busetkipkey == _FAIL) { |
527 | res = _FAIL; |
528 | goto exit; |
529 | } |
530 | |
531 | if (bmcast) |
532 | TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); |
533 | else |
534 | TKIP_IV(pattrib->iv, psta->dot11txpn, 0); |
535 | |
536 | memcpy(pattrib->dot11tkiptxmickey.skey, psta->dot11tkiptxmickey.skey, 16); |
537 | |
538 | break; |
539 | |
540 | case _AES_: |
541 | |
542 | pattrib->iv_len = 8; |
543 | pattrib->icv_len = 8; |
544 | |
545 | if (bmcast) |
546 | AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); |
547 | else |
548 | AES_IV(pattrib->iv, psta->dot11txpn, 0); |
549 | |
550 | break; |
551 | |
552 | default: |
553 | pattrib->iv_len = 0; |
554 | pattrib->icv_len = 0; |
555 | break; |
556 | } |
557 | |
558 | if (pattrib->encrypt > 0) |
559 | memcpy(pattrib->dot118021x_UncstKey.skey, psta->dot118021x_UncstKey.skey, 16); |
560 | |
561 | if (pattrib->encrypt && |
562 | ((padapter->securitypriv.sw_encrypt) || (!psecuritypriv->hw_decrypted))) |
563 | pattrib->bswenc = true; |
564 | else |
565 | pattrib->bswenc = false; |
566 | |
567 | exit: |
568 | |
569 | return res; |
570 | } |
571 | |
572 | u8 qos_acm(u8 acm_mask, u8 priority) |
573 | { |
574 | switch (priority) { |
575 | case 0: |
576 | case 3: |
577 | if (acm_mask & BIT(1)) |
578 | priority = 1; |
579 | break; |
580 | case 1: |
581 | case 2: |
582 | break; |
583 | case 4: |
584 | case 5: |
585 | if (acm_mask & BIT(2)) |
586 | priority = 0; |
587 | break; |
588 | case 6: |
589 | case 7: |
590 | if (acm_mask & BIT(3)) |
591 | priority = 5; |
592 | break; |
593 | default: |
594 | break; |
595 | } |
596 | |
597 | return priority; |
598 | } |
599 | |
600 | static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) |
601 | { |
602 | struct ethhdr etherhdr; |
603 | struct iphdr ip_hdr; |
604 | s32 UserPriority = 0; |
605 | |
606 | _rtw_open_pktfile(pkt: ppktfile->pkt, pfile: ppktfile); |
607 | _rtw_pktfile_read(pfile: ppktfile, rmem: (unsigned char *)ðerhdr, ETH_HLEN); |
608 | |
609 | /* get UserPriority from IP hdr */ |
610 | if (pattrib->ether_type == 0x0800) { |
611 | _rtw_pktfile_read(pfile: ppktfile, rmem: (u8 *)&ip_hdr, rlen: sizeof(ip_hdr)); |
612 | UserPriority = ip_hdr.tos >> 5; |
613 | } |
614 | pattrib->priority = UserPriority; |
615 | pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; |
616 | pattrib->subtype = WIFI_QOS_DATA_TYPE; |
617 | } |
618 | |
619 | static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct pkt_attrib *pattrib) |
620 | { |
621 | struct pkt_file pktfile; |
622 | struct sta_info *psta = NULL; |
623 | struct ethhdr etherhdr; |
624 | |
625 | signed int bmcast; |
626 | struct sta_priv *pstapriv = &padapter->stapriv; |
627 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
628 | struct qos_priv *pqospriv = &pmlmepriv->qospriv; |
629 | signed int res = _SUCCESS; |
630 | |
631 | _rtw_open_pktfile(pkt, pfile: &pktfile); |
632 | _rtw_pktfile_read(pfile: &pktfile, rmem: (u8 *)ðerhdr, ETH_HLEN); |
633 | |
634 | pattrib->ether_type = ntohs(etherhdr.h_proto); |
635 | |
636 | memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); |
637 | memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); |
638 | |
639 | if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || |
640 | (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { |
641 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); |
642 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); |
643 | } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { |
644 | memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); |
645 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); |
646 | } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { |
647 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); |
648 | memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); |
649 | } |
650 | |
651 | pattrib->pktlen = pktfile.pkt_len; |
652 | |
653 | if (pattrib->ether_type == ETH_P_IP) { |
654 | /* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */ |
655 | /* to prevent DHCP protocol fail */ |
656 | |
657 | u8 tmp[24]; |
658 | |
659 | _rtw_pktfile_read(pfile: &pktfile, rmem: &tmp[0], rlen: 24); |
660 | |
661 | pattrib->dhcp_pkt = 0; |
662 | if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */ |
663 | if (pattrib->ether_type == ETH_P_IP) {/* IP header */ |
664 | if (((tmp[21] == 68) && (tmp[23] == 67)) || |
665 | ((tmp[21] == 67) && (tmp[23] == 68))) { |
666 | /* 68 : UDP BOOTP client */ |
667 | /* 67 : UDP BOOTP server */ |
668 | pattrib->dhcp_pkt = 1; |
669 | } |
670 | } |
671 | } |
672 | |
673 | /* for parsing ICMP pakcets */ |
674 | { |
675 | struct iphdr *piphdr = (struct iphdr *)tmp; |
676 | |
677 | pattrib->icmp_pkt = 0; |
678 | if (piphdr->protocol == 0x1) /* protocol type in ip header 0x1 is ICMP */ |
679 | pattrib->icmp_pkt = 1; |
680 | } |
681 | } else if (pattrib->ether_type == 0x888e) { |
682 | netdev_dbg(padapter->pnetdev, "send eapol packet\n" ); |
683 | } |
684 | |
685 | if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) |
686 | rtw_set_scan_deny(adapter: padapter, ms: 3000); |
687 | |
688 | /* If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */ |
689 | if (pattrib->icmp_pkt == 1) |
690 | rtw_lps_ctrl_wk_cmd(padapter, lps_ctrl_type: LPS_CTRL_LEAVE, enqueue: 1); |
691 | else if (pattrib->dhcp_pkt == 1) |
692 | rtw_lps_ctrl_wk_cmd(padapter, lps_ctrl_type: LPS_CTRL_SPECIAL_PACKET, enqueue: 1); |
693 | |
694 | bmcast = is_multicast_ether_addr(addr: pattrib->ra); |
695 | |
696 | /* get sta_info */ |
697 | if (bmcast) { |
698 | psta = rtw_get_bcmc_stainfo(padapter); |
699 | } else { |
700 | psta = rtw_get_stainfo(pstapriv, hwaddr: pattrib->ra); |
701 | if (!psta) { /* if we cannot get psta => drop the pkt */ |
702 | res = _FAIL; |
703 | goto exit; |
704 | } else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) && (!(psta->state & _FW_LINKED))) { |
705 | res = _FAIL; |
706 | goto exit; |
707 | } |
708 | } |
709 | |
710 | if (!psta) { |
711 | /* if we cannot get psta => drop the pkt */ |
712 | res = _FAIL; |
713 | goto exit; |
714 | } |
715 | |
716 | if (!(psta->state & _FW_LINKED)) |
717 | return _FAIL; |
718 | |
719 | /* TODO:_lock */ |
720 | if (update_attrib_sec_info(padapter, pattrib, psta) == _FAIL) { |
721 | res = _FAIL; |
722 | goto exit; |
723 | } |
724 | |
725 | update_attrib_phy_info(padapter, pattrib, psta); |
726 | |
727 | pattrib->psta = psta; |
728 | /* TODO:_unlock */ |
729 | |
730 | pattrib->pctrl = 0; |
731 | |
732 | pattrib->ack_policy = 0; |
733 | /* get ether_hdr_len */ |
734 | pattrib->pkt_hdrlen = ETH_HLEN;/* pattrib->ether_type == 0x8100) ? (14 + 4): 14; vlan tag */ |
735 | |
736 | pattrib->hdrlen = WLAN_HDR_A3_LEN; |
737 | pattrib->subtype = WIFI_DATA_TYPE; |
738 | pattrib->priority = 0; |
739 | |
740 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) { |
741 | if (pattrib->qos_en) |
742 | set_qos(ppktfile: &pktfile, pattrib); |
743 | } else { |
744 | if (pqospriv->qos_option) { |
745 | set_qos(ppktfile: &pktfile, pattrib); |
746 | |
747 | if (pmlmepriv->acm_mask != 0) |
748 | pattrib->priority = qos_acm(acm_mask: pmlmepriv->acm_mask, priority: pattrib->priority); |
749 | } |
750 | } |
751 | |
752 | /* pattrib->priority = 5; force to used VI queue, for testing */ |
753 | |
754 | exit: |
755 | return res; |
756 | } |
757 | |
758 | static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitframe) |
759 | { |
760 | signed int curfragnum, length; |
761 | u8 *pframe, *payload, mic[8]; |
762 | struct mic_data micdata; |
763 | struct pkt_attrib *pattrib = &pxmitframe->attrib; |
764 | struct security_priv *psecuritypriv = &padapter->securitypriv; |
765 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
766 | u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; |
767 | u8 hw_hdr_offset = 0; |
768 | signed int bmcst = is_multicast_ether_addr(addr: pattrib->ra); |
769 | |
770 | hw_hdr_offset = TXDESC_OFFSET; |
771 | |
772 | if (pattrib->encrypt == _TKIP_) { |
773 | /* encode mic code */ |
774 | { |
775 | u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; |
776 | |
777 | pframe = pxmitframe->buf_addr + hw_hdr_offset; |
778 | |
779 | if (bmcst) { |
780 | if (!memcmp(p: psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, q: null_key, size: 16)) |
781 | return _FAIL; |
782 | /* start to calculate the mic code */ |
783 | rtw_secmicsetkey(pmicdata: &micdata, key: psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey); |
784 | } else { |
785 | if (!memcmp(p: &pattrib->dot11tkiptxmickey.skey[0], q: null_key, size: 16)) |
786 | return _FAIL; |
787 | /* start to calculate the mic code */ |
788 | rtw_secmicsetkey(pmicdata: &micdata, key: &pattrib->dot11tkiptxmickey.skey[0]); |
789 | } |
790 | |
791 | if (pframe[1]&1) { /* ToDS == 1 */ |
792 | rtw_secmicappend(pmicdata: &micdata, src: &pframe[16], nBytes: 6); /* DA */ |
793 | if (pframe[1]&2) /* From Ds == 1 */ |
794 | rtw_secmicappend(pmicdata: &micdata, src: &pframe[24], nBytes: 6); |
795 | else |
796 | rtw_secmicappend(pmicdata: &micdata, src: &pframe[10], nBytes: 6); |
797 | } else { /* ToDS == 0 */ |
798 | rtw_secmicappend(pmicdata: &micdata, src: &pframe[4], nBytes: 6); /* DA */ |
799 | if (pframe[1]&2) /* From Ds == 1 */ |
800 | rtw_secmicappend(pmicdata: &micdata, src: &pframe[16], nBytes: 6); |
801 | else |
802 | rtw_secmicappend(pmicdata: &micdata, src: &pframe[10], nBytes: 6); |
803 | } |
804 | |
805 | if (pattrib->qos_en) |
806 | priority[0] = (u8)pxmitframe->attrib.priority; |
807 | |
808 | rtw_secmicappend(pmicdata: &micdata, src: &priority[0], nBytes: 4); |
809 | |
810 | payload = pframe; |
811 | |
812 | for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { |
813 | payload = (u8 *)round_up((SIZE_PTR)(payload), 4); |
814 | payload = payload+pattrib->hdrlen+pattrib->iv_len; |
815 | |
816 | if ((curfragnum+1) == pattrib->nr_frags) { |
817 | length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0); |
818 | rtw_secmicappend(pmicdata: &micdata, src: payload, nBytes: length); |
819 | payload = payload+length; |
820 | } else { |
821 | length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0); |
822 | rtw_secmicappend(pmicdata: &micdata, src: payload, nBytes: length); |
823 | payload = payload+length+pattrib->icv_len; |
824 | } |
825 | } |
826 | rtw_secgetmic(pmicdata: &micdata, dst: &mic[0]); |
827 | /* add mic code and add the mic code length in last_txcmdsz */ |
828 | |
829 | memcpy(payload, &mic[0], 8); |
830 | pattrib->last_txcmdsz += 8; |
831 | } |
832 | } |
833 | return _SUCCESS; |
834 | } |
835 | |
836 | static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmitframe) |
837 | { |
838 | struct pkt_attrib *pattrib = &pxmitframe->attrib; |
839 | |
840 | if (pattrib->bswenc) { |
841 | switch (pattrib->encrypt) { |
842 | case _WEP40_: |
843 | case _WEP104_: |
844 | rtw_wep_encrypt(padapter, pxmitframe: (u8 *)pxmitframe); |
845 | break; |
846 | case _TKIP_: |
847 | rtw_tkip_encrypt(padapter, pxmitframe: (u8 *)pxmitframe); |
848 | break; |
849 | case _AES_: |
850 | rtw_aes_encrypt(padapter, pxmitframe: (u8 *)pxmitframe); |
851 | break; |
852 | default: |
853 | break; |
854 | } |
855 | } |
856 | |
857 | return _SUCCESS; |
858 | } |
859 | |
860 | s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattrib) |
861 | { |
862 | u16 *qc; |
863 | |
864 | struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr; |
865 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
866 | struct qos_priv *pqospriv = &pmlmepriv->qospriv; |
867 | u8 qos_option = false; |
868 | signed int res = _SUCCESS; |
869 | __le16 *fctrl = &pwlanhdr->frame_control; |
870 | |
871 | memset(hdr, 0, WLANHDR_OFFSET); |
872 | |
873 | SetFrameSubType(fctrl, pattrib->subtype); |
874 | |
875 | if (pattrib->subtype & WIFI_DATA_TYPE) { |
876 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { |
877 | /* to_ds = 1, fr_ds = 0; */ |
878 | |
879 | { |
880 | /* 1.Data transfer to AP */ |
881 | /* 2.Arp pkt will relayed by AP */ |
882 | SetToDs(fctrl); |
883 | memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); |
884 | memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); |
885 | memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); |
886 | } |
887 | |
888 | if (pqospriv->qos_option) |
889 | qos_option = true; |
890 | } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { |
891 | /* to_ds = 0, fr_ds = 1; */ |
892 | SetFrDs(fctrl); |
893 | memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); |
894 | memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN); |
895 | memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN); |
896 | |
897 | if (pattrib->qos_en) |
898 | qos_option = true; |
899 | } else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || |
900 | (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { |
901 | memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); |
902 | memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); |
903 | memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); |
904 | |
905 | if (pattrib->qos_en) |
906 | qos_option = true; |
907 | } else { |
908 | res = _FAIL; |
909 | goto exit; |
910 | } |
911 | |
912 | if (pattrib->mdata) |
913 | SetMData(fctrl); |
914 | |
915 | if (pattrib->encrypt) |
916 | SetPrivacy(fctrl); |
917 | |
918 | if (qos_option) { |
919 | qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); |
920 | |
921 | if (pattrib->priority) |
922 | SetPriority(qc, pattrib->priority); |
923 | |
924 | SetEOSP(qc, pattrib->eosp); |
925 | |
926 | SetAckpolicy(qc, pattrib->ack_policy); |
927 | } |
928 | |
929 | /* TODO: fill HT Control Field */ |
930 | |
931 | /* Update Seq Num will be handled by f/w */ |
932 | { |
933 | struct sta_info *psta; |
934 | |
935 | psta = rtw_get_stainfo(pstapriv: &padapter->stapriv, hwaddr: pattrib->ra); |
936 | if (pattrib->psta != psta) |
937 | return _FAIL; |
938 | |
939 | if (!psta) |
940 | return _FAIL; |
941 | |
942 | if (!(psta->state & _FW_LINKED)) |
943 | return _FAIL; |
944 | |
945 | if (psta) { |
946 | psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; |
947 | psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; |
948 | pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority]; |
949 | |
950 | SetSeqNum(hdr, pattrib->seqnum); |
951 | |
952 | /* check if enable ampdu */ |
953 | if (pattrib->ht_en && psta->htpriv.ampdu_enable) |
954 | if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) |
955 | pattrib->ampdu_en = true; |
956 | |
957 | /* re-check if enable ampdu by BA_starting_seqctrl */ |
958 | if (pattrib->ampdu_en == true) { |
959 | u16 tx_seq; |
960 | |
961 | tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f]; |
962 | |
963 | /* check BA_starting_seqctrl */ |
964 | if (SN_LESS(pattrib->seqnum, tx_seq)) { |
965 | pattrib->ampdu_en = false;/* AGG BK */ |
966 | } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) { |
967 | psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff; |
968 | |
969 | pattrib->ampdu_en = true;/* AGG EN */ |
970 | } else { |
971 | psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff; |
972 | pattrib->ampdu_en = true;/* AGG EN */ |
973 | } |
974 | } |
975 | } |
976 | } |
977 | } else { |
978 | } |
979 | |
980 | exit: |
981 | return res; |
982 | } |
983 | |
984 | s32 rtw_txframes_pending(struct adapter *padapter) |
985 | { |
986 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
987 | |
988 | return ((!list_empty(head: &pxmitpriv->be_pending.queue)) || |
989 | (!list_empty(head: &pxmitpriv->bk_pending.queue)) || |
990 | (!list_empty(head: &pxmitpriv->vi_pending.queue)) || |
991 | (!list_empty(head: &pxmitpriv->vo_pending.queue))); |
992 | } |
993 | |
994 | /* |
995 | * Calculate wlan 802.11 packet MAX size from pkt_attrib |
996 | * This function doesn't consider fragment case |
997 | */ |
998 | u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib) |
999 | { |
1000 | u32 len = 0; |
1001 | |
1002 | len = pattrib->hdrlen + pattrib->iv_len; /* WLAN Header and IV */ |
1003 | len += SNAP_SIZE + sizeof(u16); /* LLC */ |
1004 | len += pattrib->pktlen; |
1005 | if (pattrib->encrypt == _TKIP_) |
1006 | len += 8; /* MIC */ |
1007 | len += ((pattrib->bswenc) ? pattrib->icv_len : 0); /* ICV */ |
1008 | |
1009 | return len; |
1010 | } |
1011 | |
1012 | /* |
1013 | * This sub-routine will perform all the following: |
1014 | * 1. remove 802.3 header. |
1015 | * 2. create wlan_header, based on the info in pxmitframe |
1016 | * 3. append sta's iv/ext-iv |
1017 | * 4. append LLC |
1018 | * 5. move frag chunk from pframe to pxmitframe->mem |
1019 | * 6. apply sw-encrypt, if necessary. |
1020 | */ |
1021 | s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe) |
1022 | { |
1023 | struct pkt_file pktfile; |
1024 | |
1025 | s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; |
1026 | |
1027 | SIZE_PTR addr; |
1028 | |
1029 | u8 *pframe, *mem_start; |
1030 | u8 hw_hdr_offset; |
1031 | |
1032 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
1033 | |
1034 | struct pkt_attrib *pattrib = &pxmitframe->attrib; |
1035 | |
1036 | u8 *pbuf_start; |
1037 | |
1038 | s32 bmcst = is_multicast_ether_addr(addr: pattrib->ra); |
1039 | s32 res = _SUCCESS; |
1040 | |
1041 | if (!pxmitframe->buf_addr) |
1042 | return _FAIL; |
1043 | |
1044 | pbuf_start = pxmitframe->buf_addr; |
1045 | |
1046 | hw_hdr_offset = TXDESC_OFFSET; |
1047 | mem_start = pbuf_start + hw_hdr_offset; |
1048 | |
1049 | if (rtw_make_wlanhdr(padapter, hdr: mem_start, pattrib) == _FAIL) { |
1050 | res = _FAIL; |
1051 | goto exit; |
1052 | } |
1053 | |
1054 | _rtw_open_pktfile(pkt, pfile: &pktfile); |
1055 | _rtw_pktfile_read(pfile: &pktfile, NULL, rlen: pattrib->pkt_hdrlen); |
1056 | |
1057 | frg_inx = 0; |
1058 | frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */ |
1059 | |
1060 | while (1) { |
1061 | llc_sz = 0; |
1062 | |
1063 | mpdu_len = frg_len; |
1064 | |
1065 | pframe = mem_start; |
1066 | |
1067 | SetMFrag(mem_start); |
1068 | |
1069 | pframe += pattrib->hdrlen; |
1070 | mpdu_len -= pattrib->hdrlen; |
1071 | |
1072 | /* adding icv, if necessary... */ |
1073 | if (pattrib->iv_len) { |
1074 | memcpy(pframe, pattrib->iv, pattrib->iv_len); |
1075 | |
1076 | pframe += pattrib->iv_len; |
1077 | |
1078 | mpdu_len -= pattrib->iv_len; |
1079 | } |
1080 | |
1081 | if (frg_inx == 0) { |
1082 | llc_sz = rtw_put_snap(data: pframe, h_proto: pattrib->ether_type); |
1083 | pframe += llc_sz; |
1084 | mpdu_len -= llc_sz; |
1085 | } |
1086 | |
1087 | if ((pattrib->icv_len > 0) && (pattrib->bswenc)) |
1088 | mpdu_len -= pattrib->icv_len; |
1089 | |
1090 | if (bmcst) { |
1091 | /* don't do fragment to broadcast/multicast packets */ |
1092 | mem_sz = _rtw_pktfile_read(pfile: &pktfile, rmem: pframe, rlen: pattrib->pktlen); |
1093 | } else { |
1094 | mem_sz = _rtw_pktfile_read(pfile: &pktfile, rmem: pframe, rlen: mpdu_len); |
1095 | } |
1096 | |
1097 | pframe += mem_sz; |
1098 | |
1099 | if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { |
1100 | memcpy(pframe, pattrib->icv, pattrib->icv_len); |
1101 | pframe += pattrib->icv_len; |
1102 | } |
1103 | |
1104 | frg_inx++; |
1105 | |
1106 | if (bmcst || (rtw_endofpktfile(pfile: &pktfile) == true)) { |
1107 | pattrib->nr_frags = frg_inx; |
1108 | |
1109 | pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1) ? llc_sz:0) + |
1110 | ((pattrib->bswenc) ? pattrib->icv_len : 0) + mem_sz; |
1111 | |
1112 | ClearMFrag(mem_start); |
1113 | |
1114 | break; |
1115 | } |
1116 | |
1117 | addr = (SIZE_PTR)(pframe); |
1118 | |
1119 | mem_start = (unsigned char *)round_up(addr, 4) + hw_hdr_offset; |
1120 | memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen); |
1121 | } |
1122 | |
1123 | if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) { |
1124 | res = _FAIL; |
1125 | goto exit; |
1126 | } |
1127 | |
1128 | xmitframe_swencrypt(padapter, pxmitframe); |
1129 | |
1130 | if (bmcst == false) |
1131 | update_attrib_vcs_info(padapter, pxmitframe); |
1132 | else |
1133 | pattrib->vcs_mode = NONE_VCS; |
1134 | |
1135 | exit: |
1136 | return res; |
1137 | } |
1138 | |
1139 | /* broadcast or multicast management pkt use BIP, unicast management pkt use CCMP encryption */ |
1140 | s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe) |
1141 | { |
1142 | u8 *pframe, *mem_start = NULL, *tmp_buf = NULL; |
1143 | u8 subtype; |
1144 | struct sta_info *psta = NULL; |
1145 | struct pkt_attrib *pattrib = &pxmitframe->attrib; |
1146 | s32 bmcst = is_multicast_ether_addr(addr: pattrib->ra); |
1147 | u8 *BIP_AAD = NULL; |
1148 | u8 *MGMT_body = NULL; |
1149 | |
1150 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1151 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
1152 | struct ieee80211_hdr *pwlanhdr; |
1153 | u8 MME[_MME_IE_LENGTH_]; |
1154 | u32 ori_len; |
1155 | |
1156 | mem_start = pframe = (u8 *)(pxmitframe->buf_addr) + TXDESC_OFFSET; |
1157 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
1158 | |
1159 | ori_len = BIP_AAD_SIZE+pattrib->pktlen; |
1160 | tmp_buf = BIP_AAD = rtw_zmalloc(ori_len); |
1161 | subtype = GetFrameSubType(pframe); /* bit(7)~bit(2) */ |
1162 | |
1163 | if (!BIP_AAD) |
1164 | return _FAIL; |
1165 | |
1166 | spin_lock_bh(lock: &padapter->security_key_mutex); |
1167 | |
1168 | /* only support station mode */ |
1169 | if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE) || !check_fwstate(pmlmepriv, _FW_LINKED)) |
1170 | goto xmitframe_coalesce_success; |
1171 | |
1172 | /* IGTK key is not install, it may not support 802.11w */ |
1173 | if (!padapter->securitypriv.binstallBIPkey) |
1174 | goto xmitframe_coalesce_success; |
1175 | |
1176 | /* station mode doesn't need TX BIP, just ready the code */ |
1177 | if (bmcst) { |
1178 | int frame_body_len; |
1179 | u8 mic[16]; |
1180 | |
1181 | memset(MME, 0, 18); |
1182 | |
1183 | /* other types doesn't need the BIP */ |
1184 | if (GetFrameSubType(pframe) != WIFI_DEAUTH && GetFrameSubType(pframe) != WIFI_DISASSOC) |
1185 | goto xmitframe_coalesce_fail; |
1186 | |
1187 | MGMT_body = pframe + sizeof(struct ieee80211_hdr_3addr); |
1188 | pframe += pattrib->pktlen; |
1189 | |
1190 | /* octent 0 and 1 is key index , BIP keyid is 4 or 5, LSB only need octent 0 */ |
1191 | MME[0] = padapter->securitypriv.dot11wBIPKeyid; |
1192 | /* copy packet number */ |
1193 | memcpy(&MME[2], &pmlmeext->mgnt_80211w_IPN, 6); |
1194 | /* increase the packet number */ |
1195 | pmlmeext->mgnt_80211w_IPN++; |
1196 | |
1197 | /* add MME IE with MIC all zero, MME string doesn't include element id and length */ |
1198 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_MMIE, len: 16, |
1199 | source: MME, frlen: &pattrib->pktlen); |
1200 | pattrib->last_txcmdsz = pattrib->pktlen; |
1201 | /* total frame length - header length */ |
1202 | frame_body_len = pattrib->pktlen - sizeof(struct ieee80211_hdr_3addr); |
1203 | |
1204 | /* conscruct AAD, copy frame control field */ |
1205 | memcpy(BIP_AAD, &pwlanhdr->frame_control, 2); |
1206 | ClearRetry(BIP_AAD); |
1207 | ClearPwrMgt(BIP_AAD); |
1208 | ClearMData(BIP_AAD); |
1209 | /* conscruct AAD, copy address 1 to address 3 */ |
1210 | memcpy(BIP_AAD+2, pwlanhdr->addr1, 18); |
1211 | /* copy management fram body */ |
1212 | memcpy(BIP_AAD+BIP_AAD_SIZE, MGMT_body, frame_body_len); |
1213 | /* calculate mic */ |
1214 | if (omac1_aes_128(key: padapter->securitypriv.dot11wBIPKey[padapter->securitypriv.dot11wBIPKeyid].skey |
1215 | , data: BIP_AAD, BIP_AAD_SIZE+frame_body_len, mac: mic)) |
1216 | goto xmitframe_coalesce_fail; |
1217 | |
1218 | /* copy right BIP mic value, total is 128bits, we use the 0~63 bits */ |
1219 | memcpy(pframe-8, mic, 8); |
1220 | } else { /* unicast mgmt frame TX */ |
1221 | /* start to encrypt mgmt frame */ |
1222 | if (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC || |
1223 | subtype == WIFI_REASSOCREQ || subtype == WIFI_ACTION) { |
1224 | if (pattrib->psta) |
1225 | psta = pattrib->psta; |
1226 | else |
1227 | psta = rtw_get_stainfo(pstapriv: &padapter->stapriv, hwaddr: pattrib->ra); |
1228 | |
1229 | if (!psta) |
1230 | goto xmitframe_coalesce_fail; |
1231 | |
1232 | if (!(psta->state & _FW_LINKED) || !pxmitframe->buf_addr) |
1233 | goto xmitframe_coalesce_fail; |
1234 | |
1235 | /* according 802.11-2012 standard, these five types are not robust types */ |
1236 | if (subtype == WIFI_ACTION && |
1237 | (pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_PUBLIC || |
1238 | pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_HT || |
1239 | pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_UNPROTECTED_WNM || |
1240 | pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_SELF_PROTECTED || |
1241 | pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_P2P)) |
1242 | goto xmitframe_coalesce_fail; |
1243 | /* before encrypt dump the management packet content */ |
1244 | if (pattrib->encrypt > 0) |
1245 | memcpy(pattrib->dot118021x_UncstKey.skey, psta->dot118021x_UncstKey.skey, 16); |
1246 | /* bakeup original management packet */ |
1247 | memcpy(tmp_buf, pframe, pattrib->pktlen); |
1248 | /* move to data portion */ |
1249 | pframe += pattrib->hdrlen; |
1250 | |
1251 | /* 802.11w unicast management packet must be _AES_ */ |
1252 | pattrib->iv_len = 8; |
1253 | /* it's MIC of AES */ |
1254 | pattrib->icv_len = 8; |
1255 | |
1256 | switch (pattrib->encrypt) { |
1257 | case _AES_: |
1258 | /* set AES IV header */ |
1259 | AES_IV(pattrib->iv, psta->dot11wtxpn, 0); |
1260 | break; |
1261 | default: |
1262 | goto xmitframe_coalesce_fail; |
1263 | } |
1264 | /* insert iv header into management frame */ |
1265 | memcpy(pframe, pattrib->iv, pattrib->iv_len); |
1266 | pframe += pattrib->iv_len; |
1267 | /* copy mgmt data portion after CCMP header */ |
1268 | memcpy(pframe, tmp_buf+pattrib->hdrlen, pattrib->pktlen-pattrib->hdrlen); |
1269 | /* move pframe to end of mgmt pkt */ |
1270 | pframe += pattrib->pktlen-pattrib->hdrlen; |
1271 | /* add 8 bytes CCMP IV header to length */ |
1272 | pattrib->pktlen += pattrib->iv_len; |
1273 | if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { |
1274 | memcpy(pframe, pattrib->icv, pattrib->icv_len); |
1275 | pframe += pattrib->icv_len; |
1276 | } |
1277 | /* add 8 bytes MIC */ |
1278 | pattrib->pktlen += pattrib->icv_len; |
1279 | /* set final tx command size */ |
1280 | pattrib->last_txcmdsz = pattrib->pktlen; |
1281 | |
1282 | /* set protected bit must be beofre SW encrypt */ |
1283 | SetPrivacy(mem_start); |
1284 | /* software encrypt */ |
1285 | xmitframe_swencrypt(padapter, pxmitframe); |
1286 | } |
1287 | } |
1288 | |
1289 | xmitframe_coalesce_success: |
1290 | spin_unlock_bh(lock: &padapter->security_key_mutex); |
1291 | kfree(objp: BIP_AAD); |
1292 | return _SUCCESS; |
1293 | |
1294 | xmitframe_coalesce_fail: |
1295 | spin_unlock_bh(lock: &padapter->security_key_mutex); |
1296 | kfree(objp: BIP_AAD); |
1297 | return _FAIL; |
1298 | } |
1299 | |
1300 | /* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header |
1301 | * IEEE LLC/SNAP header contains 8 octets |
1302 | * First 3 octets comprise the LLC portion |
1303 | * SNAP portion, 5 octets, is divided into two fields: |
1304 | *Organizationally Unique Identifier(OUI), 3 octets, |
1305 | *type, defined by that organization, 2 octets. |
1306 | */ |
1307 | s32 rtw_put_snap(u8 *data, u16 h_proto) |
1308 | { |
1309 | struct ieee80211_snap_hdr *snap; |
1310 | u8 *oui; |
1311 | |
1312 | snap = (struct ieee80211_snap_hdr *)data; |
1313 | snap->dsap = 0xaa; |
1314 | snap->ssap = 0xaa; |
1315 | snap->ctrl = 0x03; |
1316 | |
1317 | if (h_proto == 0x8137 || h_proto == 0x80f3) |
1318 | oui = P802_1H_OUI; |
1319 | else |
1320 | oui = RFC1042_OUI; |
1321 | |
1322 | snap->oui[0] = oui[0]; |
1323 | snap->oui[1] = oui[1]; |
1324 | snap->oui[2] = oui[2]; |
1325 | |
1326 | *(__be16 *)(data + SNAP_SIZE) = htons(h_proto); |
1327 | |
1328 | return SNAP_SIZE + sizeof(u16); |
1329 | } |
1330 | |
1331 | void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len) |
1332 | { |
1333 | uint protection; |
1334 | u8 *perp; |
1335 | signed int erp_len; |
1336 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
1337 | struct registry_priv *pregistrypriv = &padapter->registrypriv; |
1338 | |
1339 | switch (pxmitpriv->vcs_setting) { |
1340 | case DISABLE_VCS: |
1341 | pxmitpriv->vcs = NONE_VCS; |
1342 | break; |
1343 | |
1344 | case ENABLE_VCS: |
1345 | break; |
1346 | |
1347 | case AUTO_VCS: |
1348 | default: |
1349 | perp = rtw_get_ie(pbuf: ie, index: WLAN_EID_ERP_INFO, len: &erp_len, limit: ie_len); |
1350 | if (!perp) { |
1351 | pxmitpriv->vcs = NONE_VCS; |
1352 | } else { |
1353 | protection = (*(perp + 2)) & BIT(1); |
1354 | if (protection) { |
1355 | if (pregistrypriv->vcs_type == RTS_CTS) |
1356 | pxmitpriv->vcs = RTS_CTS; |
1357 | else |
1358 | pxmitpriv->vcs = CTS_TO_SELF; |
1359 | } else { |
1360 | pxmitpriv->vcs = NONE_VCS; |
1361 | } |
1362 | } |
1363 | |
1364 | break; |
1365 | } |
1366 | } |
1367 | |
1368 | void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz) |
1369 | { |
1370 | struct sta_info *psta = NULL; |
1371 | struct stainfo_stats *pstats = NULL; |
1372 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
1373 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
1374 | u8 pkt_num = 1; |
1375 | |
1376 | if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) { |
1377 | pkt_num = pxmitframe->agg_num; |
1378 | |
1379 | pmlmepriv->LinkDetectInfo.NumTxOkInPeriod += pkt_num; |
1380 | |
1381 | pxmitpriv->tx_pkts += pkt_num; |
1382 | |
1383 | pxmitpriv->tx_bytes += sz; |
1384 | |
1385 | psta = pxmitframe->attrib.psta; |
1386 | if (psta) { |
1387 | pstats = &psta->sta_stats; |
1388 | |
1389 | pstats->tx_pkts += pkt_num; |
1390 | |
1391 | pstats->tx_bytes += sz; |
1392 | } |
1393 | } |
1394 | } |
1395 | |
1396 | static struct xmit_buf *__rtw_alloc_cmd_xmitbuf(struct xmit_priv *pxmitpriv, |
1397 | enum cmdbuf_type buf_type) |
1398 | { |
1399 | struct xmit_buf *pxmitbuf = NULL; |
1400 | |
1401 | pxmitbuf = &pxmitpriv->pcmd_xmitbuf[buf_type]; |
1402 | if (pxmitbuf) { |
1403 | pxmitbuf->priv_data = NULL; |
1404 | |
1405 | pxmitbuf->len = 0; |
1406 | pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; |
1407 | pxmitbuf->agg_num = 0; |
1408 | pxmitbuf->pg_num = 0; |
1409 | |
1410 | if (pxmitbuf->sctx) |
1411 | rtw_sctx_done_err(sctx: &pxmitbuf->sctx, status: RTW_SCTX_DONE_BUF_ALLOC); |
1412 | } |
1413 | |
1414 | return pxmitbuf; |
1415 | } |
1416 | |
1417 | struct xmit_frame *__rtw_alloc_cmdxmitframe(struct xmit_priv *pxmitpriv, |
1418 | enum cmdbuf_type buf_type) |
1419 | { |
1420 | struct xmit_frame *pcmdframe; |
1421 | struct xmit_buf *pxmitbuf; |
1422 | |
1423 | pcmdframe = rtw_alloc_xmitframe(pxmitpriv); |
1424 | if (!pcmdframe) |
1425 | return NULL; |
1426 | |
1427 | pxmitbuf = __rtw_alloc_cmd_xmitbuf(pxmitpriv, buf_type); |
1428 | if (!pxmitbuf) { |
1429 | rtw_free_xmitframe(pxmitpriv, pxmitframe: pcmdframe); |
1430 | return NULL; |
1431 | } |
1432 | |
1433 | pcmdframe->frame_tag = MGNT_FRAMETAG; |
1434 | |
1435 | pcmdframe->pxmitbuf = pxmitbuf; |
1436 | |
1437 | pcmdframe->buf_addr = pxmitbuf->pbuf; |
1438 | |
1439 | pxmitbuf->priv_data = pcmdframe; |
1440 | |
1441 | return pcmdframe; |
1442 | } |
1443 | |
1444 | struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) |
1445 | { |
1446 | unsigned long irqL; |
1447 | struct xmit_buf *pxmitbuf = NULL; |
1448 | struct list_head *plist, *phead; |
1449 | struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; |
1450 | |
1451 | spin_lock_irqsave(&pfree_queue->lock, irqL); |
1452 | |
1453 | if (list_empty(head: &pfree_queue->queue)) { |
1454 | pxmitbuf = NULL; |
1455 | } else { |
1456 | phead = get_list_head(queue: pfree_queue); |
1457 | |
1458 | plist = get_next(list: phead); |
1459 | |
1460 | pxmitbuf = container_of(plist, struct xmit_buf, list); |
1461 | |
1462 | list_del_init(entry: &pxmitbuf->list); |
1463 | } |
1464 | |
1465 | if (pxmitbuf) { |
1466 | pxmitpriv->free_xmit_extbuf_cnt--; |
1467 | |
1468 | pxmitbuf->priv_data = NULL; |
1469 | |
1470 | pxmitbuf->len = 0; |
1471 | pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; |
1472 | pxmitbuf->agg_num = 1; |
1473 | |
1474 | if (pxmitbuf->sctx) |
1475 | rtw_sctx_done_err(sctx: &pxmitbuf->sctx, status: RTW_SCTX_DONE_BUF_ALLOC); |
1476 | } |
1477 | |
1478 | spin_unlock_irqrestore(lock: &pfree_queue->lock, flags: irqL); |
1479 | |
1480 | return pxmitbuf; |
1481 | } |
1482 | |
1483 | s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) |
1484 | { |
1485 | unsigned long irqL; |
1486 | struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; |
1487 | |
1488 | if (!pxmitbuf) |
1489 | return _FAIL; |
1490 | |
1491 | spin_lock_irqsave(&pfree_queue->lock, irqL); |
1492 | |
1493 | list_del_init(entry: &pxmitbuf->list); |
1494 | |
1495 | list_add_tail(new: &pxmitbuf->list, head: get_list_head(queue: pfree_queue)); |
1496 | pxmitpriv->free_xmit_extbuf_cnt++; |
1497 | |
1498 | spin_unlock_irqrestore(lock: &pfree_queue->lock, flags: irqL); |
1499 | |
1500 | return _SUCCESS; |
1501 | } |
1502 | |
1503 | struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) |
1504 | { |
1505 | unsigned long irqL; |
1506 | struct xmit_buf *pxmitbuf = NULL; |
1507 | struct list_head *plist, *phead; |
1508 | struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; |
1509 | |
1510 | spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); |
1511 | |
1512 | if (list_empty(head: &pfree_xmitbuf_queue->queue)) { |
1513 | pxmitbuf = NULL; |
1514 | } else { |
1515 | phead = get_list_head(queue: pfree_xmitbuf_queue); |
1516 | |
1517 | plist = get_next(list: phead); |
1518 | |
1519 | pxmitbuf = container_of(plist, struct xmit_buf, list); |
1520 | |
1521 | list_del_init(entry: &pxmitbuf->list); |
1522 | } |
1523 | |
1524 | if (pxmitbuf) { |
1525 | pxmitpriv->free_xmitbuf_cnt--; |
1526 | |
1527 | pxmitbuf->priv_data = NULL; |
1528 | |
1529 | pxmitbuf->len = 0; |
1530 | pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; |
1531 | pxmitbuf->agg_num = 0; |
1532 | pxmitbuf->pg_num = 0; |
1533 | |
1534 | if (pxmitbuf->sctx) |
1535 | rtw_sctx_done_err(sctx: &pxmitbuf->sctx, status: RTW_SCTX_DONE_BUF_ALLOC); |
1536 | } |
1537 | |
1538 | spin_unlock_irqrestore(lock: &pfree_xmitbuf_queue->lock, flags: irqL); |
1539 | |
1540 | return pxmitbuf; |
1541 | } |
1542 | |
1543 | s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) |
1544 | { |
1545 | unsigned long irqL; |
1546 | struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; |
1547 | |
1548 | if (!pxmitbuf) |
1549 | return _FAIL; |
1550 | |
1551 | if (pxmitbuf->sctx) |
1552 | rtw_sctx_done_err(sctx: &pxmitbuf->sctx, status: RTW_SCTX_DONE_BUF_FREE); |
1553 | |
1554 | if (pxmitbuf->buf_tag == XMITBUF_CMD) { |
1555 | } else if (pxmitbuf->buf_tag == XMITBUF_MGNT) { |
1556 | rtw_free_xmitbuf_ext(pxmitpriv, pxmitbuf); |
1557 | } else { |
1558 | spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); |
1559 | |
1560 | list_del_init(entry: &pxmitbuf->list); |
1561 | |
1562 | list_add_tail(new: &pxmitbuf->list, |
1563 | head: get_list_head(queue: pfree_xmitbuf_queue)); |
1564 | |
1565 | pxmitpriv->free_xmitbuf_cnt++; |
1566 | spin_unlock_irqrestore(lock: &pfree_xmitbuf_queue->lock, flags: irqL); |
1567 | } |
1568 | return _SUCCESS; |
1569 | } |
1570 | |
1571 | static void rtw_init_xmitframe(struct xmit_frame *pxframe) |
1572 | { |
1573 | if (pxframe) { /* default value setting */ |
1574 | pxframe->buf_addr = NULL; |
1575 | pxframe->pxmitbuf = NULL; |
1576 | |
1577 | memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib)); |
1578 | |
1579 | pxframe->frame_tag = DATA_FRAMETAG; |
1580 | |
1581 | pxframe->pg_num = 1; |
1582 | pxframe->agg_num = 1; |
1583 | pxframe->ack_report = 0; |
1584 | } |
1585 | } |
1586 | |
1587 | /* |
1588 | * Calling context: |
1589 | * 1. OS_TXENTRY |
1590 | * 2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) |
1591 | * |
1592 | * If we turn on USE_RXTHREAD, then, no need for critical section. |
1593 | * Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... |
1594 | * |
1595 | * Must be very, very cautious... |
1596 | */ |
1597 | struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pfree_xmit_queue) */ |
1598 | { |
1599 | /* |
1600 | * Please remember to use all the osdep_service api, |
1601 | * and lock/unlock or _enter/_exit critical to protect |
1602 | * pfree_xmit_queue |
1603 | */ |
1604 | |
1605 | struct xmit_frame *pxframe = NULL; |
1606 | struct list_head *plist, *phead; |
1607 | struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; |
1608 | |
1609 | spin_lock_bh(lock: &pfree_xmit_queue->lock); |
1610 | |
1611 | if (list_empty(head: &pfree_xmit_queue->queue)) { |
1612 | pxframe = NULL; |
1613 | } else { |
1614 | phead = get_list_head(queue: pfree_xmit_queue); |
1615 | |
1616 | plist = get_next(list: phead); |
1617 | |
1618 | pxframe = container_of(plist, struct xmit_frame, list); |
1619 | |
1620 | list_del_init(entry: &pxframe->list); |
1621 | pxmitpriv->free_xmitframe_cnt--; |
1622 | } |
1623 | |
1624 | spin_unlock_bh(lock: &pfree_xmit_queue->lock); |
1625 | |
1626 | rtw_init_xmitframe(pxframe); |
1627 | return pxframe; |
1628 | } |
1629 | |
1630 | struct xmit_frame *rtw_alloc_xmitframe_ext(struct xmit_priv *pxmitpriv) |
1631 | { |
1632 | struct xmit_frame *pxframe = NULL; |
1633 | struct list_head *plist, *phead; |
1634 | struct __queue *queue = &pxmitpriv->free_xframe_ext_queue; |
1635 | |
1636 | spin_lock_bh(lock: &queue->lock); |
1637 | |
1638 | if (list_empty(head: &queue->queue)) { |
1639 | pxframe = NULL; |
1640 | } else { |
1641 | phead = get_list_head(queue); |
1642 | plist = get_next(list: phead); |
1643 | pxframe = container_of(plist, struct xmit_frame, list); |
1644 | |
1645 | list_del_init(entry: &pxframe->list); |
1646 | pxmitpriv->free_xframe_ext_cnt--; |
1647 | } |
1648 | |
1649 | spin_unlock_bh(lock: &queue->lock); |
1650 | |
1651 | rtw_init_xmitframe(pxframe); |
1652 | |
1653 | return pxframe; |
1654 | } |
1655 | |
1656 | struct xmit_frame *rtw_alloc_xmitframe_once(struct xmit_priv *pxmitpriv) |
1657 | { |
1658 | struct xmit_frame *pxframe = NULL; |
1659 | u8 *alloc_addr; |
1660 | |
1661 | alloc_addr = rtw_zmalloc(sizeof(struct xmit_frame) + 4); |
1662 | |
1663 | if (!alloc_addr) |
1664 | goto exit; |
1665 | |
1666 | pxframe = (struct xmit_frame *)N_BYTE_ALIGMENT((SIZE_PTR)(alloc_addr), 4); |
1667 | pxframe->alloc_addr = alloc_addr; |
1668 | |
1669 | pxframe->padapter = pxmitpriv->adapter; |
1670 | pxframe->frame_tag = NULL_FRAMETAG; |
1671 | |
1672 | pxframe->pkt = NULL; |
1673 | |
1674 | pxframe->buf_addr = NULL; |
1675 | pxframe->pxmitbuf = NULL; |
1676 | |
1677 | rtw_init_xmitframe(pxframe); |
1678 | |
1679 | exit: |
1680 | return pxframe; |
1681 | } |
1682 | |
1683 | s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe) |
1684 | { |
1685 | struct __queue *queue = NULL; |
1686 | struct adapter *padapter = pxmitpriv->adapter; |
1687 | struct sk_buff *pndis_pkt = NULL; |
1688 | |
1689 | if (!pxmitframe) |
1690 | goto exit; |
1691 | |
1692 | if (pxmitframe->pkt) { |
1693 | pndis_pkt = pxmitframe->pkt; |
1694 | pxmitframe->pkt = NULL; |
1695 | } |
1696 | |
1697 | if (pxmitframe->alloc_addr) { |
1698 | kfree(objp: pxmitframe->alloc_addr); |
1699 | goto check_pkt_complete; |
1700 | } |
1701 | |
1702 | if (pxmitframe->ext_tag == 0) |
1703 | queue = &pxmitpriv->free_xmit_queue; |
1704 | else if (pxmitframe->ext_tag == 1) |
1705 | queue = &pxmitpriv->free_xframe_ext_queue; |
1706 | else { |
1707 | } |
1708 | |
1709 | spin_lock_bh(lock: &queue->lock); |
1710 | |
1711 | list_del_init(entry: &pxmitframe->list); |
1712 | list_add_tail(new: &pxmitframe->list, head: get_list_head(queue)); |
1713 | if (pxmitframe->ext_tag == 0) |
1714 | pxmitpriv->free_xmitframe_cnt++; |
1715 | else if (pxmitframe->ext_tag == 1) |
1716 | pxmitpriv->free_xframe_ext_cnt++; |
1717 | |
1718 | spin_unlock_bh(lock: &queue->lock); |
1719 | |
1720 | check_pkt_complete: |
1721 | |
1722 | if (pndis_pkt) |
1723 | rtw_os_pkt_complete(padapter, pkt: pndis_pkt); |
1724 | |
1725 | exit: |
1726 | return _SUCCESS; |
1727 | } |
1728 | |
1729 | void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue) |
1730 | { |
1731 | struct list_head *plist, *phead, *tmp; |
1732 | struct xmit_frame *pxmitframe; |
1733 | |
1734 | spin_lock_bh(lock: &pframequeue->lock); |
1735 | |
1736 | phead = get_list_head(queue: pframequeue); |
1737 | list_for_each_safe(plist, tmp, phead) { |
1738 | pxmitframe = list_entry(plist, struct xmit_frame, list); |
1739 | |
1740 | rtw_free_xmitframe(pxmitpriv, pxmitframe); |
1741 | } |
1742 | spin_unlock_bh(lock: &pframequeue->lock); |
1743 | } |
1744 | |
1745 | s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe) |
1746 | { |
1747 | if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) |
1748 | return _FAIL; |
1749 | |
1750 | return _SUCCESS; |
1751 | } |
1752 | |
1753 | struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, signed int up, u8 *ac) |
1754 | { |
1755 | struct tx_servq *ptxservq = NULL; |
1756 | |
1757 | switch (up) { |
1758 | case 1: |
1759 | case 2: |
1760 | ptxservq = &psta->sta_xmitpriv.bk_q; |
1761 | *(ac) = 3; |
1762 | break; |
1763 | |
1764 | case 4: |
1765 | case 5: |
1766 | ptxservq = &psta->sta_xmitpriv.vi_q; |
1767 | *(ac) = 1; |
1768 | break; |
1769 | |
1770 | case 6: |
1771 | case 7: |
1772 | ptxservq = &psta->sta_xmitpriv.vo_q; |
1773 | *(ac) = 0; |
1774 | break; |
1775 | |
1776 | case 0: |
1777 | case 3: |
1778 | default: |
1779 | ptxservq = &psta->sta_xmitpriv.be_q; |
1780 | *(ac) = 2; |
1781 | break; |
1782 | } |
1783 | |
1784 | return ptxservq; |
1785 | } |
1786 | |
1787 | /* |
1788 | * Will enqueue pxmitframe to the proper queue, |
1789 | * and indicate it to xx_pending list..... |
1790 | */ |
1791 | s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe) |
1792 | { |
1793 | u8 ac_index; |
1794 | struct sta_info *psta; |
1795 | struct tx_servq *ptxservq; |
1796 | struct pkt_attrib *pattrib = &pxmitframe->attrib; |
1797 | struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; |
1798 | signed int res = _SUCCESS; |
1799 | |
1800 | psta = rtw_get_stainfo(pstapriv: &padapter->stapriv, hwaddr: pattrib->ra); |
1801 | if (pattrib->psta != psta) |
1802 | return _FAIL; |
1803 | |
1804 | if (!psta) { |
1805 | res = _FAIL; |
1806 | goto exit; |
1807 | } |
1808 | |
1809 | if (!(psta->state & _FW_LINKED)) |
1810 | return _FAIL; |
1811 | |
1812 | ptxservq = rtw_get_sta_pending(padapter, psta, up: pattrib->priority, ac: (u8 *)(&ac_index)); |
1813 | |
1814 | if (list_empty(head: &ptxservq->tx_pending)) |
1815 | list_add_tail(new: &ptxservq->tx_pending, head: get_list_head(queue: phwxmits[ac_index].sta_queue)); |
1816 | |
1817 | list_add_tail(new: &pxmitframe->list, head: get_list_head(queue: &ptxservq->sta_pending)); |
1818 | ptxservq->qcnt++; |
1819 | phwxmits[ac_index].accnt++; |
1820 | |
1821 | exit: |
1822 | |
1823 | return res; |
1824 | } |
1825 | |
1826 | s32 rtw_alloc_hwxmits(struct adapter *padapter) |
1827 | { |
1828 | struct hw_xmit *hwxmits; |
1829 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
1830 | |
1831 | pxmitpriv->hwxmit_entry = HWXMIT_ENTRY; |
1832 | |
1833 | pxmitpriv->hwxmits = NULL; |
1834 | |
1835 | pxmitpriv->hwxmits = rtw_zmalloc(sizeof(struct hw_xmit) * pxmitpriv->hwxmit_entry); |
1836 | |
1837 | if (!pxmitpriv->hwxmits) |
1838 | return _FAIL; |
1839 | |
1840 | hwxmits = pxmitpriv->hwxmits; |
1841 | |
1842 | if (pxmitpriv->hwxmit_entry == 5) { |
1843 | hwxmits[0] .sta_queue = &pxmitpriv->bm_pending; |
1844 | |
1845 | hwxmits[1] .sta_queue = &pxmitpriv->vo_pending; |
1846 | |
1847 | hwxmits[2] .sta_queue = &pxmitpriv->vi_pending; |
1848 | |
1849 | hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; |
1850 | |
1851 | hwxmits[4] .sta_queue = &pxmitpriv->be_pending; |
1852 | } else if (pxmitpriv->hwxmit_entry == 4) { |
1853 | hwxmits[0] .sta_queue = &pxmitpriv->vo_pending; |
1854 | |
1855 | hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; |
1856 | |
1857 | hwxmits[2] .sta_queue = &pxmitpriv->be_pending; |
1858 | |
1859 | hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; |
1860 | } else { |
1861 | } |
1862 | |
1863 | return _SUCCESS; |
1864 | } |
1865 | |
1866 | void rtw_free_hwxmits(struct adapter *padapter) |
1867 | { |
1868 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
1869 | |
1870 | kfree(objp: pxmitpriv->hwxmits); |
1871 | } |
1872 | |
1873 | void rtw_init_hwxmits(struct hw_xmit *phwxmit, signed int entry) |
1874 | { |
1875 | signed int i; |
1876 | |
1877 | for (i = 0; i < entry; i++, phwxmit++) |
1878 | phwxmit->accnt = 0; |
1879 | } |
1880 | |
1881 | u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe) |
1882 | { |
1883 | u32 addr; |
1884 | struct pkt_attrib *pattrib = &pxmitframe->attrib; |
1885 | |
1886 | switch (pattrib->qsel) { |
1887 | case 0: |
1888 | case 3: |
1889 | addr = BE_QUEUE_INX; |
1890 | break; |
1891 | case 1: |
1892 | case 2: |
1893 | addr = BK_QUEUE_INX; |
1894 | break; |
1895 | case 4: |
1896 | case 5: |
1897 | addr = VI_QUEUE_INX; |
1898 | break; |
1899 | case 6: |
1900 | case 7: |
1901 | addr = VO_QUEUE_INX; |
1902 | break; |
1903 | case 0x10: |
1904 | addr = BCN_QUEUE_INX; |
1905 | break; |
1906 | case 0x11:/* BC/MC in PS (HIQ) */ |
1907 | addr = HIGH_QUEUE_INX; |
1908 | break; |
1909 | case 0x12: |
1910 | default: |
1911 | addr = MGT_QUEUE_INX; |
1912 | break; |
1913 | } |
1914 | |
1915 | return addr; |
1916 | } |
1917 | |
1918 | static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib) |
1919 | { |
1920 | u8 qsel; |
1921 | |
1922 | qsel = pattrib->priority; |
1923 | |
1924 | pattrib->qsel = qsel; |
1925 | } |
1926 | |
1927 | /* |
1928 | * The main transmit(tx) entry |
1929 | * |
1930 | * Return |
1931 | *1 enqueue |
1932 | *0 success, hardware will handle this xmit frame(packet) |
1933 | *<0 fail |
1934 | */ |
1935 | s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt) |
1936 | { |
1937 | static unsigned long start; |
1938 | static u32 drop_cnt; |
1939 | |
1940 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
1941 | struct xmit_frame *pxmitframe = NULL; |
1942 | |
1943 | s32 res; |
1944 | |
1945 | if (start == 0) |
1946 | start = jiffies; |
1947 | |
1948 | pxmitframe = rtw_alloc_xmitframe(pxmitpriv); |
1949 | |
1950 | if (jiffies_to_msecs(j: jiffies - start) > 2000) { |
1951 | start = jiffies; |
1952 | drop_cnt = 0; |
1953 | } |
1954 | |
1955 | if (!pxmitframe) { |
1956 | drop_cnt++; |
1957 | return -1; |
1958 | } |
1959 | |
1960 | res = update_attrib(padapter, pkt: *ppkt, pattrib: &pxmitframe->attrib); |
1961 | |
1962 | if (res == _FAIL) { |
1963 | rtw_free_xmitframe(pxmitpriv, pxmitframe); |
1964 | return -1; |
1965 | } |
1966 | pxmitframe->pkt = *ppkt; |
1967 | |
1968 | do_queue_select(padapter, pattrib: &pxmitframe->attrib); |
1969 | |
1970 | spin_lock_bh(lock: &pxmitpriv->lock); |
1971 | if (xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe) == true) { |
1972 | spin_unlock_bh(lock: &pxmitpriv->lock); |
1973 | return 1; |
1974 | } |
1975 | spin_unlock_bh(lock: &pxmitpriv->lock); |
1976 | |
1977 | /* pre_xmitframe */ |
1978 | if (rtw_hal_xmit(padapter, pxmitframe) == false) |
1979 | return 1; |
1980 | |
1981 | return 0; |
1982 | } |
1983 | |
1984 | #define RTW_HIQ_FILTER_ALLOW_ALL 0 |
1985 | #define RTW_HIQ_FILTER_ALLOW_SPECIAL 1 |
1986 | #define RTW_HIQ_FILTER_DENY_ALL 2 |
1987 | |
1988 | inline bool xmitframe_hiq_filter(struct xmit_frame *xmitframe) |
1989 | { |
1990 | bool allow = false; |
1991 | struct adapter *adapter = xmitframe->padapter; |
1992 | struct registry_priv *registry = &adapter->registrypriv; |
1993 | |
1994 | if (registry->hiq_filter == RTW_HIQ_FILTER_ALLOW_SPECIAL) { |
1995 | struct pkt_attrib *attrib = &xmitframe->attrib; |
1996 | |
1997 | if (attrib->ether_type == 0x0806 || |
1998 | attrib->ether_type == 0x888e || |
1999 | attrib->dhcp_pkt |
2000 | ) |
2001 | allow = true; |
2002 | |
2003 | } else if (registry->hiq_filter == RTW_HIQ_FILTER_ALLOW_ALL) |
2004 | allow = true; |
2005 | else if (registry->hiq_filter == RTW_HIQ_FILTER_DENY_ALL) { |
2006 | } else |
2007 | rtw_warn_on(1); |
2008 | |
2009 | return allow; |
2010 | } |
2011 | |
2012 | signed int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe) |
2013 | { |
2014 | signed int ret = false; |
2015 | struct sta_info *psta = NULL; |
2016 | struct sta_priv *pstapriv = &padapter->stapriv; |
2017 | struct pkt_attrib *pattrib = &pxmitframe->attrib; |
2018 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
2019 | signed int bmcst = is_multicast_ether_addr(addr: pattrib->ra); |
2020 | bool update_tim = false; |
2021 | |
2022 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == false) |
2023 | return ret; |
2024 | psta = rtw_get_stainfo(pstapriv: &padapter->stapriv, hwaddr: pattrib->ra); |
2025 | if (pattrib->psta != psta) |
2026 | return false; |
2027 | |
2028 | if (!psta) |
2029 | return false; |
2030 | |
2031 | if (!(psta->state & _FW_LINKED)) |
2032 | return false; |
2033 | |
2034 | if (pattrib->triggered == 1) { |
2035 | if (bmcst && xmitframe_hiq_filter(xmitframe: pxmitframe)) |
2036 | pattrib->qsel = 0x11;/* HIQ */ |
2037 | |
2038 | return ret; |
2039 | } |
2040 | |
2041 | if (bmcst) { |
2042 | spin_lock_bh(lock: &psta->sleep_q.lock); |
2043 | |
2044 | if (pstapriv->sta_dz_bitmap) { /* if anyone sta is in ps mode */ |
2045 | /* pattrib->qsel = 0x11;HIQ */ |
2046 | |
2047 | list_del_init(entry: &pxmitframe->list); |
2048 | |
2049 | list_add_tail(new: &pxmitframe->list, head: get_list_head(queue: &psta->sleep_q)); |
2050 | |
2051 | psta->sleepq_len++; |
2052 | |
2053 | if (!(pstapriv->tim_bitmap & BIT(0))) |
2054 | update_tim = true; |
2055 | |
2056 | pstapriv->tim_bitmap |= BIT(0); |
2057 | pstapriv->sta_dz_bitmap |= BIT(0); |
2058 | |
2059 | if (update_tim) |
2060 | update_beacon(padapter, ie_id: WLAN_EID_TIM, NULL, tx: true); |
2061 | else |
2062 | chk_bmc_sleepq_cmd(padapter); |
2063 | |
2064 | ret = true; |
2065 | } |
2066 | |
2067 | spin_unlock_bh(lock: &psta->sleep_q.lock); |
2068 | |
2069 | return ret; |
2070 | } |
2071 | |
2072 | spin_lock_bh(lock: &psta->sleep_q.lock); |
2073 | |
2074 | if (psta->state&WIFI_SLEEP_STATE) { |
2075 | u8 wmmps_ac = 0; |
2076 | |
2077 | if (pstapriv->sta_dz_bitmap & BIT(psta->aid)) { |
2078 | list_del_init(entry: &pxmitframe->list); |
2079 | |
2080 | list_add_tail(new: &pxmitframe->list, head: get_list_head(queue: &psta->sleep_q)); |
2081 | |
2082 | psta->sleepq_len++; |
2083 | |
2084 | switch (pattrib->priority) { |
2085 | case 1: |
2086 | case 2: |
2087 | wmmps_ac = psta->uapsd_bk&BIT(0); |
2088 | break; |
2089 | case 4: |
2090 | case 5: |
2091 | wmmps_ac = psta->uapsd_vi&BIT(0); |
2092 | break; |
2093 | case 6: |
2094 | case 7: |
2095 | wmmps_ac = psta->uapsd_vo&BIT(0); |
2096 | break; |
2097 | case 0: |
2098 | case 3: |
2099 | default: |
2100 | wmmps_ac = psta->uapsd_be&BIT(0); |
2101 | break; |
2102 | } |
2103 | |
2104 | if (wmmps_ac) |
2105 | psta->sleepq_ac_len++; |
2106 | |
2107 | if (((psta->has_legacy_ac) && (!wmmps_ac)) || ((!psta->has_legacy_ac) && (wmmps_ac))) { |
2108 | if (!(pstapriv->tim_bitmap & BIT(psta->aid))) |
2109 | update_tim = true; |
2110 | |
2111 | pstapriv->tim_bitmap |= BIT(psta->aid); |
2112 | |
2113 | if (update_tim) |
2114 | /* update BCN for TIM IE */ |
2115 | update_beacon(padapter, ie_id: WLAN_EID_TIM, NULL, tx: true); |
2116 | } |
2117 | |
2118 | ret = true; |
2119 | } |
2120 | } |
2121 | |
2122 | spin_unlock_bh(lock: &psta->sleep_q.lock); |
2123 | |
2124 | return ret; |
2125 | } |
2126 | |
2127 | static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct __queue *pframequeue) |
2128 | { |
2129 | signed int ret; |
2130 | struct list_head *plist, *phead, *tmp; |
2131 | u8 ac_index; |
2132 | struct tx_servq *ptxservq; |
2133 | struct pkt_attrib *pattrib; |
2134 | struct xmit_frame *pxmitframe; |
2135 | struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; |
2136 | |
2137 | phead = get_list_head(queue: pframequeue); |
2138 | list_for_each_safe(plist, tmp, phead) { |
2139 | pxmitframe = list_entry(plist, struct xmit_frame, list); |
2140 | |
2141 | pattrib = &pxmitframe->attrib; |
2142 | |
2143 | pattrib->triggered = 0; |
2144 | |
2145 | ret = xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe); |
2146 | |
2147 | if (true == ret) { |
2148 | ptxservq = rtw_get_sta_pending(padapter, psta, up: pattrib->priority, ac: (u8 *)(&ac_index)); |
2149 | |
2150 | ptxservq->qcnt--; |
2151 | phwxmits[ac_index].accnt--; |
2152 | } else { |
2153 | } |
2154 | } |
2155 | } |
2156 | |
2157 | void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta) |
2158 | { |
2159 | struct sta_info *psta_bmc; |
2160 | struct sta_xmit_priv *pstaxmitpriv; |
2161 | struct sta_priv *pstapriv = &padapter->stapriv; |
2162 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
2163 | |
2164 | pstaxmitpriv = &psta->sta_xmitpriv; |
2165 | |
2166 | /* for BC/MC Frames */ |
2167 | psta_bmc = rtw_get_bcmc_stainfo(padapter); |
2168 | |
2169 | spin_lock_bh(lock: &pxmitpriv->lock); |
2170 | |
2171 | psta->state |= WIFI_SLEEP_STATE; |
2172 | |
2173 | pstapriv->sta_dz_bitmap |= BIT(psta->aid); |
2174 | |
2175 | dequeue_xmitframes_to_sleeping_queue(padapter, psta, pframequeue: &pstaxmitpriv->vo_q.sta_pending); |
2176 | list_del_init(entry: &pstaxmitpriv->vo_q.tx_pending); |
2177 | |
2178 | dequeue_xmitframes_to_sleeping_queue(padapter, psta, pframequeue: &pstaxmitpriv->vi_q.sta_pending); |
2179 | list_del_init(entry: &pstaxmitpriv->vi_q.tx_pending); |
2180 | |
2181 | dequeue_xmitframes_to_sleeping_queue(padapter, psta, pframequeue: &pstaxmitpriv->be_q.sta_pending); |
2182 | list_del_init(entry: &pstaxmitpriv->be_q.tx_pending); |
2183 | |
2184 | dequeue_xmitframes_to_sleeping_queue(padapter, psta, pframequeue: &pstaxmitpriv->bk_q.sta_pending); |
2185 | list_del_init(entry: &pstaxmitpriv->bk_q.tx_pending); |
2186 | |
2187 | /* for BC/MC Frames */ |
2188 | pstaxmitpriv = &psta_bmc->sta_xmitpriv; |
2189 | dequeue_xmitframes_to_sleeping_queue(padapter, psta: psta_bmc, pframequeue: &pstaxmitpriv->be_q.sta_pending); |
2190 | list_del_init(entry: &pstaxmitpriv->be_q.tx_pending); |
2191 | |
2192 | spin_unlock_bh(lock: &pxmitpriv->lock); |
2193 | } |
2194 | |
2195 | void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta) |
2196 | { |
2197 | u8 update_mask = 0, wmmps_ac = 0; |
2198 | struct sta_info *psta_bmc; |
2199 | struct list_head *xmitframe_plist, *xmitframe_phead, *tmp; |
2200 | struct xmit_frame *pxmitframe = NULL; |
2201 | struct sta_priv *pstapriv = &padapter->stapriv; |
2202 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
2203 | |
2204 | psta_bmc = rtw_get_bcmc_stainfo(padapter); |
2205 | |
2206 | spin_lock_bh(lock: &pxmitpriv->lock); |
2207 | |
2208 | xmitframe_phead = get_list_head(queue: &psta->sleep_q); |
2209 | list_for_each_safe(xmitframe_plist, tmp, xmitframe_phead) { |
2210 | pxmitframe = list_entry(xmitframe_plist, struct xmit_frame, |
2211 | list); |
2212 | |
2213 | list_del_init(entry: &pxmitframe->list); |
2214 | |
2215 | switch (pxmitframe->attrib.priority) { |
2216 | case 1: |
2217 | case 2: |
2218 | wmmps_ac = psta->uapsd_bk&BIT(1); |
2219 | break; |
2220 | case 4: |
2221 | case 5: |
2222 | wmmps_ac = psta->uapsd_vi&BIT(1); |
2223 | break; |
2224 | case 6: |
2225 | case 7: |
2226 | wmmps_ac = psta->uapsd_vo&BIT(1); |
2227 | break; |
2228 | case 0: |
2229 | case 3: |
2230 | default: |
2231 | wmmps_ac = psta->uapsd_be&BIT(1); |
2232 | break; |
2233 | } |
2234 | |
2235 | psta->sleepq_len--; |
2236 | if (psta->sleepq_len > 0) |
2237 | pxmitframe->attrib.mdata = 1; |
2238 | else |
2239 | pxmitframe->attrib.mdata = 0; |
2240 | |
2241 | if (wmmps_ac) { |
2242 | psta->sleepq_ac_len--; |
2243 | if (psta->sleepq_ac_len > 0) { |
2244 | pxmitframe->attrib.mdata = 1; |
2245 | pxmitframe->attrib.eosp = 0; |
2246 | } else { |
2247 | pxmitframe->attrib.mdata = 0; |
2248 | pxmitframe->attrib.eosp = 1; |
2249 | } |
2250 | } |
2251 | |
2252 | pxmitframe->attrib.triggered = 1; |
2253 | |
2254 | rtw_hal_xmitframe_enqueue(padapter, pxmitframe); |
2255 | } |
2256 | |
2257 | if (psta->sleepq_len == 0) { |
2258 | if (pstapriv->tim_bitmap & BIT(psta->aid)) |
2259 | update_mask = BIT(0); |
2260 | |
2261 | pstapriv->tim_bitmap &= ~BIT(psta->aid); |
2262 | |
2263 | if (psta->state&WIFI_SLEEP_STATE) |
2264 | psta->state ^= WIFI_SLEEP_STATE; |
2265 | |
2266 | if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { |
2267 | psta->expire_to = pstapriv->expire_to; |
2268 | psta->state ^= WIFI_STA_ALIVE_CHK_STATE; |
2269 | } |
2270 | |
2271 | pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); |
2272 | } |
2273 | |
2274 | /* for BC/MC Frames */ |
2275 | if (!psta_bmc) |
2276 | goto _exit; |
2277 | |
2278 | if ((pstapriv->sta_dz_bitmap&0xfffe) == 0x0) { /* no any sta in ps mode */ |
2279 | xmitframe_phead = get_list_head(queue: &psta_bmc->sleep_q); |
2280 | list_for_each_safe(xmitframe_plist, tmp, xmitframe_phead) { |
2281 | pxmitframe = list_entry(xmitframe_plist, |
2282 | struct xmit_frame, list); |
2283 | |
2284 | list_del_init(entry: &pxmitframe->list); |
2285 | |
2286 | psta_bmc->sleepq_len--; |
2287 | if (psta_bmc->sleepq_len > 0) |
2288 | pxmitframe->attrib.mdata = 1; |
2289 | else |
2290 | pxmitframe->attrib.mdata = 0; |
2291 | |
2292 | pxmitframe->attrib.triggered = 1; |
2293 | rtw_hal_xmitframe_enqueue(padapter, pxmitframe); |
2294 | } |
2295 | |
2296 | if (psta_bmc->sleepq_len == 0) { |
2297 | if (pstapriv->tim_bitmap & BIT(0)) |
2298 | update_mask |= BIT(1); |
2299 | |
2300 | pstapriv->tim_bitmap &= ~BIT(0); |
2301 | pstapriv->sta_dz_bitmap &= ~BIT(0); |
2302 | } |
2303 | } |
2304 | |
2305 | _exit: |
2306 | |
2307 | spin_unlock_bh(lock: &pxmitpriv->lock); |
2308 | |
2309 | if (update_mask) |
2310 | update_beacon(padapter, ie_id: WLAN_EID_TIM, NULL, tx: true); |
2311 | } |
2312 | |
2313 | void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta) |
2314 | { |
2315 | u8 wmmps_ac = 0; |
2316 | struct list_head *xmitframe_plist, *xmitframe_phead, *tmp; |
2317 | struct xmit_frame *pxmitframe = NULL; |
2318 | struct sta_priv *pstapriv = &padapter->stapriv; |
2319 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
2320 | |
2321 | spin_lock_bh(lock: &pxmitpriv->lock); |
2322 | |
2323 | xmitframe_phead = get_list_head(queue: &psta->sleep_q); |
2324 | list_for_each_safe(xmitframe_plist, tmp, xmitframe_phead) { |
2325 | pxmitframe = list_entry(xmitframe_plist, struct xmit_frame, |
2326 | list); |
2327 | |
2328 | switch (pxmitframe->attrib.priority) { |
2329 | case 1: |
2330 | case 2: |
2331 | wmmps_ac = psta->uapsd_bk&BIT(1); |
2332 | break; |
2333 | case 4: |
2334 | case 5: |
2335 | wmmps_ac = psta->uapsd_vi&BIT(1); |
2336 | break; |
2337 | case 6: |
2338 | case 7: |
2339 | wmmps_ac = psta->uapsd_vo&BIT(1); |
2340 | break; |
2341 | case 0: |
2342 | case 3: |
2343 | default: |
2344 | wmmps_ac = psta->uapsd_be&BIT(1); |
2345 | break; |
2346 | } |
2347 | |
2348 | if (!wmmps_ac) |
2349 | continue; |
2350 | |
2351 | list_del_init(entry: &pxmitframe->list); |
2352 | |
2353 | psta->sleepq_len--; |
2354 | psta->sleepq_ac_len--; |
2355 | |
2356 | if (psta->sleepq_ac_len > 0) { |
2357 | pxmitframe->attrib.mdata = 1; |
2358 | pxmitframe->attrib.eosp = 0; |
2359 | } else { |
2360 | pxmitframe->attrib.mdata = 0; |
2361 | pxmitframe->attrib.eosp = 1; |
2362 | } |
2363 | |
2364 | pxmitframe->attrib.triggered = 1; |
2365 | rtw_hal_xmitframe_enqueue(padapter, pxmitframe); |
2366 | |
2367 | if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && (wmmps_ac)) { |
2368 | pstapriv->tim_bitmap &= ~BIT(psta->aid); |
2369 | |
2370 | update_beacon(padapter, ie_id: WLAN_EID_TIM, NULL, tx: true); |
2371 | } |
2372 | } |
2373 | |
2374 | spin_unlock_bh(lock: &pxmitpriv->lock); |
2375 | } |
2376 | |
2377 | void enqueue_pending_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) |
2378 | { |
2379 | struct __queue *pqueue; |
2380 | struct adapter *pri_adapter = pxmitpriv->adapter; |
2381 | |
2382 | pqueue = &pxmitpriv->pending_xmitbuf_queue; |
2383 | |
2384 | spin_lock_bh(lock: &pqueue->lock); |
2385 | list_del_init(entry: &pxmitbuf->list); |
2386 | list_add_tail(new: &pxmitbuf->list, head: get_list_head(queue: pqueue)); |
2387 | spin_unlock_bh(lock: &pqueue->lock); |
2388 | |
2389 | complete(&pri_adapter->xmitpriv.xmit_comp); |
2390 | } |
2391 | |
2392 | void enqueue_pending_xmitbuf_to_head(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) |
2393 | { |
2394 | struct __queue *pqueue; |
2395 | |
2396 | pqueue = &pxmitpriv->pending_xmitbuf_queue; |
2397 | |
2398 | spin_lock_bh(lock: &pqueue->lock); |
2399 | list_del_init(entry: &pxmitbuf->list); |
2400 | list_add(new: &pxmitbuf->list, head: get_list_head(queue: pqueue)); |
2401 | spin_unlock_bh(lock: &pqueue->lock); |
2402 | } |
2403 | |
2404 | struct xmit_buf *dequeue_pending_xmitbuf(struct xmit_priv *pxmitpriv) |
2405 | { |
2406 | struct xmit_buf *pxmitbuf; |
2407 | struct __queue *pqueue; |
2408 | |
2409 | pxmitbuf = NULL; |
2410 | pqueue = &pxmitpriv->pending_xmitbuf_queue; |
2411 | |
2412 | spin_lock_bh(lock: &pqueue->lock); |
2413 | |
2414 | if (!list_empty(head: &pqueue->queue)) { |
2415 | struct list_head *plist, *phead; |
2416 | |
2417 | phead = get_list_head(queue: pqueue); |
2418 | plist = get_next(list: phead); |
2419 | pxmitbuf = container_of(plist, struct xmit_buf, list); |
2420 | list_del_init(entry: &pxmitbuf->list); |
2421 | } |
2422 | |
2423 | spin_unlock_bh(lock: &pqueue->lock); |
2424 | |
2425 | return pxmitbuf; |
2426 | } |
2427 | |
2428 | struct xmit_buf *dequeue_pending_xmitbuf_under_survey(struct xmit_priv *pxmitpriv) |
2429 | { |
2430 | struct xmit_buf *pxmitbuf; |
2431 | struct __queue *pqueue; |
2432 | |
2433 | pxmitbuf = NULL; |
2434 | pqueue = &pxmitpriv->pending_xmitbuf_queue; |
2435 | |
2436 | spin_lock_bh(lock: &pqueue->lock); |
2437 | |
2438 | if (!list_empty(head: &pqueue->queue)) { |
2439 | struct list_head *plist, *phead; |
2440 | u8 type; |
2441 | |
2442 | phead = get_list_head(queue: pqueue); |
2443 | plist = phead; |
2444 | do { |
2445 | plist = get_next(list: plist); |
2446 | if (plist == phead) |
2447 | break; |
2448 | |
2449 | pxmitbuf = container_of(plist, struct xmit_buf, list); |
2450 | |
2451 | type = GetFrameSubType(pxmitbuf->pbuf + TXDESC_OFFSET); |
2452 | |
2453 | if ((type == WIFI_PROBEREQ) || |
2454 | (type == WIFI_DATA_NULL) || |
2455 | (type == WIFI_QOS_DATA_NULL)) { |
2456 | list_del_init(entry: &pxmitbuf->list); |
2457 | break; |
2458 | } |
2459 | pxmitbuf = NULL; |
2460 | } while (1); |
2461 | } |
2462 | |
2463 | spin_unlock_bh(lock: &pqueue->lock); |
2464 | |
2465 | return pxmitbuf; |
2466 | } |
2467 | |
2468 | signed int check_pending_xmitbuf(struct xmit_priv *pxmitpriv) |
2469 | { |
2470 | struct __queue *pqueue; |
2471 | signed int ret = false; |
2472 | |
2473 | pqueue = &pxmitpriv->pending_xmitbuf_queue; |
2474 | |
2475 | spin_lock_bh(lock: &pqueue->lock); |
2476 | |
2477 | if (!list_empty(head: &pqueue->queue)) |
2478 | ret = true; |
2479 | |
2480 | spin_unlock_bh(lock: &pqueue->lock); |
2481 | |
2482 | return ret; |
2483 | } |
2484 | |
2485 | int rtw_xmit_thread(void *context) |
2486 | { |
2487 | s32 err; |
2488 | struct adapter *padapter; |
2489 | |
2490 | err = _SUCCESS; |
2491 | padapter = context; |
2492 | |
2493 | thread_enter(name: "RTW_XMIT_THREAD" ); |
2494 | |
2495 | do { |
2496 | err = rtw_hal_xmit_thread_handler(padapter); |
2497 | flush_signals_thread(); |
2498 | } while (err == _SUCCESS); |
2499 | |
2500 | complete(&padapter->xmitpriv.terminate_xmitthread_comp); |
2501 | |
2502 | return 0; |
2503 | } |
2504 | |
2505 | void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms) |
2506 | { |
2507 | sctx->timeout_ms = timeout_ms; |
2508 | sctx->submit_time = jiffies; |
2509 | init_completion(x: &sctx->done); |
2510 | sctx->status = RTW_SCTX_SUBMITTED; |
2511 | } |
2512 | |
2513 | int rtw_sctx_wait(struct submit_ctx *sctx) |
2514 | { |
2515 | int ret = _FAIL; |
2516 | unsigned long expire; |
2517 | int status = 0; |
2518 | |
2519 | expire = sctx->timeout_ms ? msecs_to_jiffies(m: sctx->timeout_ms) : MAX_SCHEDULE_TIMEOUT; |
2520 | if (!wait_for_completion_timeout(x: &sctx->done, timeout: expire)) |
2521 | /* timeout, do something?? */ |
2522 | status = RTW_SCTX_DONE_TIMEOUT; |
2523 | else |
2524 | status = sctx->status; |
2525 | |
2526 | if (status == RTW_SCTX_DONE_SUCCESS) |
2527 | ret = _SUCCESS; |
2528 | |
2529 | return ret; |
2530 | } |
2531 | |
2532 | void rtw_sctx_done_err(struct submit_ctx **sctx, int status) |
2533 | { |
2534 | if (*sctx) { |
2535 | (*sctx)->status = status; |
2536 | complete(&((*sctx)->done)); |
2537 | *sctx = NULL; |
2538 | } |
2539 | } |
2540 | |
2541 | void rtw_sctx_done(struct submit_ctx **sctx) |
2542 | { |
2543 | rtw_sctx_done_err(sctx, status: RTW_SCTX_DONE_SUCCESS); |
2544 | } |
2545 | |
2546 | int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms) |
2547 | { |
2548 | struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; |
2549 | |
2550 | pack_tx_ops->submit_time = jiffies; |
2551 | pack_tx_ops->timeout_ms = timeout_ms; |
2552 | pack_tx_ops->status = RTW_SCTX_SUBMITTED; |
2553 | |
2554 | return rtw_sctx_wait(sctx: pack_tx_ops); |
2555 | } |
2556 | |
2557 | void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status) |
2558 | { |
2559 | struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; |
2560 | |
2561 | if (pxmitpriv->ack_tx) |
2562 | rtw_sctx_done_err(sctx: &pack_tx_ops, status); |
2563 | } |
2564 | |