Commit | Line | Data |
---|---|---|
71e9bd3f | 1 | // SPDX-License-Identifier: GPL-2.0 |
d6846af6 LF |
2 | /****************************************************************************** |
3 | * | |
4 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. | |
5 | * | |
d6846af6 LF |
6 | ******************************************************************************/ |
7 | #define _RTW_XMIT_C_ | |
8 | ||
9 | #include <osdep_service.h> | |
10 | #include <drv_types.h> | |
0a0796eb | 11 | #include <mon.h> |
d6846af6 LF |
12 | #include <wifi.h> |
13 | #include <osdep_intf.h> | |
d249db9e | 14 | #include <linux/vmalloc.h> |
d6846af6 LF |
15 | |
16 | static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; | |
17 | static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; | |
18 | ||
19 | static void _init_txservq(struct tx_servq *ptxservq) | |
20 | { | |
aa3f5ccb | 21 | INIT_LIST_HEAD(&ptxservq->tx_pending); |
d6846af6 LF |
22 | _rtw_init_queue(&ptxservq->sta_pending); |
23 | ptxservq->qcnt = 0; | |
d6846af6 LF |
24 | } |
25 | ||
6da0bda8 | 26 | void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) |
d6846af6 | 27 | { |
7be921a2 | 28 | memset((unsigned char *)psta_xmitpriv, 0, sizeof(struct sta_xmit_priv)); |
f214e521 | 29 | spin_lock_init(&psta_xmitpriv->lock); |
d6846af6 LF |
30 | _init_txservq(&psta_xmitpriv->be_q); |
31 | _init_txservq(&psta_xmitpriv->bk_q); | |
32 | _init_txservq(&psta_xmitpriv->vi_q); | |
33 | _init_txservq(&psta_xmitpriv->vo_q); | |
aa3f5ccb | 34 | INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz); |
35 | INIT_LIST_HEAD(&psta_xmitpriv->apsd); | |
d6846af6 LF |
36 | } |
37 | ||
6da0bda8 | 38 | s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) |
d6846af6 LF |
39 | { |
40 | int i; | |
41 | struct xmit_buf *pxmitbuf; | |
42 | struct xmit_frame *pxframe; | |
6da0bda8 | 43 | int res = _SUCCESS; |
d6846af6 LF |
44 | u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; |
45 | u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; | |
46 | ||
1665c8fd MK |
47 | /* |
48 | * We don't need to memset padapter->XXX to zero because adapter is | |
49 | * allocated by alloc_etherdev_mq, which eventually calls kvzalloc. | |
50 | */ | |
d6846af6 | 51 | |
f214e521 | 52 | spin_lock_init(&pxmitpriv->lock); |
d6846af6 LF |
53 | |
54 | /* | |
ee53f6dd SF |
55 | * Please insert all the queue initializaiton using _rtw_init_queue below |
56 | */ | |
d6846af6 LF |
57 | |
58 | pxmitpriv->adapter = padapter; | |
59 | ||
60 | _rtw_init_queue(&pxmitpriv->be_pending); | |
61 | _rtw_init_queue(&pxmitpriv->bk_pending); | |
62 | _rtw_init_queue(&pxmitpriv->vi_pending); | |
63 | _rtw_init_queue(&pxmitpriv->vo_pending); | |
64 | _rtw_init_queue(&pxmitpriv->bm_pending); | |
65 | ||
66 | _rtw_init_queue(&pxmitpriv->free_xmit_queue); | |
67 | ||
68 | /* | |
ee53f6dd SF |
69 | * Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME, |
70 | * and initialize free_xmit_frame below. | |
71 | * Please also apply free_txobj to link_up all the xmit_frames... | |
72 | */ | |
d6846af6 | 73 | |
2397c6e0 | 74 | pxmitpriv->pallocated_frame_buf = vzalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4); |
d6846af6 | 75 | |
c39f4bb9 | 76 | if (!pxmitpriv->pallocated_frame_buf) { |
d6846af6 LF |
77 | pxmitpriv->pxmit_frame_buf = NULL; |
78 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_frame fail!\n")); | |
79 | res = _FAIL; | |
80 | goto exit; | |
81 | } | |
fb113408 | 82 | pxmitpriv->pxmit_frame_buf = PTR_ALIGN(pxmitpriv->pallocated_frame_buf, 4); |
d6846af6 LF |
83 | |
84 | pxframe = (struct xmit_frame *)pxmitpriv->pxmit_frame_buf; | |
85 | ||
86 | for (i = 0; i < NR_XMITFRAME; i++) { | |
ceefaace | 87 | INIT_LIST_HEAD(&pxframe->list); |
d6846af6 LF |
88 | |
89 | pxframe->padapter = padapter; | |
90 | pxframe->frame_tag = NULL_FRAMETAG; | |
91 | ||
92 | pxframe->pkt = NULL; | |
93 | ||
94 | pxframe->buf_addr = NULL; | |
95 | pxframe->pxmitbuf = NULL; | |
96 | ||
ceefaace | 97 | list_add_tail(&pxframe->list, &pxmitpriv->free_xmit_queue.queue); |
d6846af6 LF |
98 | |
99 | pxframe++; | |
100 | } | |
101 | ||
102 | pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME; | |
103 | ||
104 | pxmitpriv->frag_len = MAX_FRAG_THRESHOLD; | |
105 | ||
106 | /* init xmit_buf */ | |
107 | _rtw_init_queue(&pxmitpriv->free_xmitbuf_queue); | |
108 | _rtw_init_queue(&pxmitpriv->pending_xmitbuf_queue); | |
109 | ||
2397c6e0 | 110 | pxmitpriv->pallocated_xmitbuf = vzalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4); |
d6846af6 | 111 | |
c39f4bb9 | 112 | if (!pxmitpriv->pallocated_xmitbuf) { |
d6846af6 LF |
113 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_buf fail!\n")); |
114 | res = _FAIL; | |
115 | goto exit; | |
116 | } | |
117 | ||
fb113408 | 118 | pxmitpriv->pxmitbuf = PTR_ALIGN(pxmitpriv->pallocated_xmitbuf, 4); |
d6846af6 LF |
119 | |
120 | pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; | |
121 | ||
122 | for (i = 0; i < NR_XMITBUFF; i++) { | |
aa3f5ccb | 123 | INIT_LIST_HEAD(&pxmitbuf->list); |
d6846af6 LF |
124 | |
125 | pxmitbuf->priv_data = NULL; | |
126 | pxmitbuf->padapter = padapter; | |
127 | pxmitbuf->ext_tag = false; | |
128 | ||
129 | /* Tx buf allocation may fail sometimes, so sleep and retry. */ | |
69b2e08a | 130 | res = rtw_os_xmit_resource_alloc(pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ)); |
d6846af6 | 131 | if (res == _FAIL) { |
0da46e6b | 132 | msleep(10); |
69b2e08a | 133 | res = rtw_os_xmit_resource_alloc(pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ)); |
dc0283c7 | 134 | if (res == _FAIL) |
d6846af6 | 135 | goto exit; |
d6846af6 LF |
136 | } |
137 | ||
138 | pxmitbuf->flags = XMIT_VO_QUEUE; | |
139 | ||
ceefaace | 140 | list_add_tail(&pxmitbuf->list, &pxmitpriv->free_xmitbuf_queue.queue); |
d6846af6 LF |
141 | pxmitbuf++; |
142 | } | |
143 | ||
144 | pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; | |
145 | ||
146 | /* Init xmit extension buff */ | |
147 | _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue); | |
148 | ||
2397c6e0 | 149 | pxmitpriv->pallocated_xmit_extbuf = vzalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4); |
d6846af6 | 150 | |
c39f4bb9 | 151 | if (!pxmitpriv->pallocated_xmit_extbuf) { |
d6846af6 LF |
152 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n")); |
153 | res = _FAIL; | |
154 | goto exit; | |
155 | } | |
156 | ||
fb113408 | 157 | pxmitpriv->pxmit_extbuf = PTR_ALIGN(pxmitpriv->pallocated_xmit_extbuf, 4); |
d6846af6 LF |
158 | |
159 | pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; | |
160 | ||
161 | for (i = 0; i < num_xmit_extbuf; i++) { | |
aa3f5ccb | 162 | INIT_LIST_HEAD(&pxmitbuf->list); |
d6846af6 LF |
163 | |
164 | pxmitbuf->priv_data = NULL; | |
165 | pxmitbuf->padapter = padapter; | |
166 | pxmitbuf->ext_tag = true; | |
167 | ||
69b2e08a | 168 | res = rtw_os_xmit_resource_alloc(pxmitbuf, max_xmit_extbuf_size + XMITBUF_ALIGN_SZ); |
d6846af6 LF |
169 | if (res == _FAIL) { |
170 | res = _FAIL; | |
171 | goto exit; | |
172 | } | |
173 | ||
ceefaace | 174 | list_add_tail(&pxmitbuf->list, &pxmitpriv->free_xmit_extbuf_queue.queue); |
d6846af6 LF |
175 | pxmitbuf++; |
176 | } | |
177 | ||
178 | pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf; | |
179 | ||
7671ce0d AP |
180 | res = rtw_alloc_hwxmits(padapter); |
181 | if (res == _FAIL) | |
182 | goto exit; | |
d6846af6 LF |
183 | rtw_init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); |
184 | ||
185 | for (i = 0; i < 4; i++) | |
186 | pxmitpriv->wmm_para_seq[i] = i; | |
187 | ||
188 | pxmitpriv->txirp_cnt = 1; | |
189 | ||
d6846af6 LF |
190 | /* per AC pending irp */ |
191 | pxmitpriv->beq_cnt = 0; | |
192 | pxmitpriv->bkq_cnt = 0; | |
193 | pxmitpriv->viq_cnt = 0; | |
194 | pxmitpriv->voq_cnt = 0; | |
195 | ||
196 | pxmitpriv->ack_tx = false; | |
2ca4ab53 | 197 | mutex_init(&pxmitpriv->ack_tx_mutex); |
d6846af6 LF |
198 | rtw_sctx_init(&pxmitpriv->ack_tx_ops, 0); |
199 | ||
200 | rtw_hal_init_xmit_priv(padapter); | |
201 | ||
202 | exit: | |
d6846af6 LF |
203 | return res; |
204 | } | |
205 | ||
7be921a2 | 206 | void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv) |
d6846af6 LF |
207 | { |
208 | int i; | |
209 | struct adapter *padapter = pxmitpriv->adapter; | |
210 | struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitpriv->pxmit_frame_buf; | |
211 | struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; | |
d6846af6 LF |
212 | u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; |
213 | ||
c39f4bb9 | 214 | if (!pxmitpriv->pxmit_frame_buf) |
f578b5d3 | 215 | return; |
d6846af6 LF |
216 | |
217 | for (i = 0; i < NR_XMITFRAME; i++) { | |
218 | rtw_os_xmit_complete(padapter, pxmitframe); | |
219 | ||
220 | pxmitframe++; | |
221 | } | |
222 | ||
223 | for (i = 0; i < NR_XMITBUFF; i++) { | |
5cd38797 | 224 | rtw_os_xmit_resource_free(pxmitbuf); |
d6846af6 LF |
225 | pxmitbuf++; |
226 | } | |
227 | ||
da04bf74 BG |
228 | vfree(pxmitpriv->pallocated_frame_buf); |
229 | vfree(pxmitpriv->pallocated_xmitbuf); | |
d6846af6 LF |
230 | |
231 | /* free xmit extension buff */ | |
d6846af6 LF |
232 | pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; |
233 | for (i = 0; i < num_xmit_extbuf; i++) { | |
5cd38797 | 234 | rtw_os_xmit_resource_free(pxmitbuf); |
d6846af6 LF |
235 | pxmitbuf++; |
236 | } | |
237 | ||
f17331eb | 238 | vfree(pxmitpriv->pallocated_xmit_extbuf); |
d6846af6 LF |
239 | |
240 | rtw_free_hwxmits(padapter); | |
241 | ||
4b33d52a | 242 | mutex_destroy(&pxmitpriv->ack_tx_mutex); |
d6846af6 LF |
243 | } |
244 | ||
245 | static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame *pxmitframe) | |
246 | { | |
247 | u32 sz; | |
248 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
249 | struct sta_info *psta = pattrib->psta; | |
ceefaace JSB |
250 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
251 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; | |
d6846af6 LF |
252 | |
253 | if (pattrib->nr_frags != 1) | |
254 | sz = padapter->xmitpriv.frag_len; | |
255 | else /* no frag */ | |
256 | sz = pattrib->last_txcmdsz; | |
257 | ||
909495c8 MS |
258 | /* (1) RTS_Threshold is compared to the MPDU, not MSDU. |
259 | * (2) If there are more than one frag in this MSDU, | |
260 | * only the first frag uses protection frame. | |
261 | * Other fragments are protected by previous fragment. | |
262 | * So we only need to check the length of first fragment. | |
263 | */ | |
d6846af6 LF |
264 | if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) { |
265 | if (sz > padapter->registrypriv.rts_thresh) { | |
266 | pattrib->vcs_mode = RTS_CTS; | |
267 | } else { | |
268 | if (psta->rtsen) | |
269 | pattrib->vcs_mode = RTS_CTS; | |
270 | else if (psta->cts2self) | |
271 | pattrib->vcs_mode = CTS_TO_SELF; | |
272 | else | |
273 | pattrib->vcs_mode = NONE_VCS; | |
274 | } | |
275 | } else { | |
276 | while (true) { | |
277 | /* IOT action */ | |
278 | if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) && pattrib->ampdu_en && | |
279 | (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { | |
280 | pattrib->vcs_mode = CTS_TO_SELF; | |
281 | break; | |
282 | } | |
283 | ||
284 | /* check ERP protection */ | |
285 | if (psta->rtsen || psta->cts2self) { | |
286 | if (psta->rtsen) | |
287 | pattrib->vcs_mode = RTS_CTS; | |
288 | else if (psta->cts2self) | |
289 | pattrib->vcs_mode = CTS_TO_SELF; | |
290 | ||
291 | break; | |
292 | } | |
293 | ||
294 | /* check HT op mode */ | |
295 | if (pattrib->ht_en) { | |
296 | u8 htopmode = pmlmeinfo->HT_protection; | |
7d2af82c | 297 | |
d6846af6 LF |
298 | if ((pmlmeext->cur_bwmode && (htopmode == 2 || htopmode == 3)) || |
299 | (!pmlmeext->cur_bwmode && htopmode == 3)) { | |
300 | pattrib->vcs_mode = RTS_CTS; | |
301 | break; | |
302 | } | |
303 | } | |
304 | ||
305 | /* check rts */ | |
306 | if (sz > padapter->registrypriv.rts_thresh) { | |
307 | pattrib->vcs_mode = RTS_CTS; | |
308 | break; | |
309 | } | |
310 | ||
311 | /* to do list: check MIMO power save condition. */ | |
312 | ||
313 | /* check AMPDU aggregation for TXOP */ | |
314 | if (pattrib->ampdu_en) { | |
315 | pattrib->vcs_mode = RTS_CTS; | |
316 | break; | |
317 | } | |
318 | ||
319 | pattrib->vcs_mode = NONE_VCS; | |
320 | break; | |
321 | } | |
322 | } | |
323 | } | |
324 | ||
325 | static void update_attrib_phy_info(struct pkt_attrib *pattrib, struct sta_info *psta) | |
326 | { | |
d6846af6 LF |
327 | pattrib->mdata = 0; |
328 | pattrib->eosp = 0; | |
329 | pattrib->triggered = 0; | |
330 | ||
331 | /* qos_en, ht_en, init rate, , bw, ch_offset, sgi */ | |
332 | pattrib->qos_en = psta->qos_option; | |
333 | ||
334 | pattrib->raid = psta->raid; | |
335 | pattrib->ht_en = psta->htpriv.ht_option; | |
336 | pattrib->bwmode = psta->htpriv.bwmode; | |
337 | pattrib->ch_offset = psta->htpriv.ch_offset; | |
338 | pattrib->sgi = psta->htpriv.sgi; | |
339 | pattrib->ampdu_en = false; | |
340 | pattrib->retry_ctrl = false; | |
341 | } | |
342 | ||
85255891 | 343 | u8 qos_acm(u8 acm_mask, u8 priority) |
d6846af6 | 344 | { |
85255891 | 345 | u8 change_priority = priority; |
d6846af6 LF |
346 | |
347 | switch (priority) { | |
348 | case 0: | |
349 | case 3: | |
350 | if (acm_mask & BIT(1)) | |
351 | change_priority = 1; | |
352 | break; | |
353 | case 1: | |
354 | case 2: | |
355 | break; | |
356 | case 4: | |
357 | case 5: | |
358 | if (acm_mask & BIT(2)) | |
359 | change_priority = 0; | |
360 | break; | |
361 | case 6: | |
362 | case 7: | |
363 | if (acm_mask & BIT(3)) | |
364 | change_priority = 5; | |
365 | break; | |
366 | default: | |
cac04b1f MS |
367 | DBG_88E("%s(): invalid pattrib->priority: %d!!!\n", |
368 | __func__, priority); | |
d6846af6 LF |
369 | break; |
370 | } | |
371 | ||
372 | return change_priority; | |
373 | } | |
374 | ||
97212e2b | 375 | static void set_qos(struct sk_buff *skb, struct pkt_attrib *pattrib) |
d6846af6 | 376 | { |
d6846af6 | 377 | if (pattrib->ether_type == 0x0800) { |
97212e2b IS |
378 | struct iphdr ip_hdr; |
379 | ||
380 | skb_copy_bits(skb, ETH_HLEN, &ip_hdr, sizeof(ip_hdr)); | |
381 | pattrib->priority = ip_hdr.tos >> 5; | |
7b170bac | 382 | } else if (pattrib->ether_type == ETH_P_PAE) { |
909495c8 MS |
383 | /* When priority processing of data frames is supported, |
384 | * a STA's SME should send EAPOL-Key frames at the highest | |
385 | * priority. | |
386 | */ | |
97212e2b IS |
387 | pattrib->priority = 7; |
388 | } else { | |
389 | pattrib->priority = 0; | |
d6846af6 LF |
390 | } |
391 | ||
d6846af6 LF |
392 | pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; |
393 | pattrib->subtype = WIFI_QOS_DATA_TYPE; | |
394 | } | |
395 | ||
396 | static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct pkt_attrib *pattrib) | |
397 | { | |
d6846af6 LF |
398 | struct sta_info *psta = NULL; |
399 | struct ethhdr etherhdr; | |
400 | ||
2bd827a8 | 401 | bool mcast; |
d6846af6 LF |
402 | struct sta_priv *pstapriv = &padapter->stapriv; |
403 | struct security_priv *psecuritypriv = &padapter->securitypriv; | |
404 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
405 | struct qos_priv *pqospriv = &pmlmepriv->qospriv; | |
406 | int res = _SUCCESS; | |
407 | ||
ebb2a79d | 408 | skb_copy_bits(pkt, 0, ðerhdr, ETH_HLEN); |
d6846af6 LF |
409 | |
410 | pattrib->ether_type = ntohs(etherhdr.h_proto); | |
411 | ||
412 | memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); | |
413 | memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); | |
414 | ||
415 | pattrib->pctrl = 0; | |
416 | ||
417 | if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || | |
418 | check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { | |
419 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); | |
420 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); | |
421 | } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { | |
422 | memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); | |
423 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); | |
424 | } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { | |
425 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); | |
426 | memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); | |
427 | } | |
428 | ||
ebb2a79d | 429 | pattrib->pktlen = pkt->len - ETH_HLEN; |
d6846af6 | 430 | |
7d7be350 | 431 | if (pattrib->ether_type == ETH_P_IP) { |
909495c8 MS |
432 | /* The following is for DHCP and ARP packet, we use |
433 | * cck1M to tx these packets and let LPS awake some | |
434 | * time to prevent DHCP protocol fail. | |
435 | */ | |
d6846af6 | 436 | u8 tmp[24]; |
7d2af82c | 437 | |
ebb2a79d IS |
438 | skb_copy_bits(pkt, ETH_HLEN, tmp, 24); |
439 | ||
d6846af6 | 440 | pattrib->dhcp_pkt = 0; |
ebb2a79d | 441 | if (pkt->len > ETH_HLEN + 24 + 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */ |
7d7be350 | 442 | if (pattrib->ether_type == ETH_P_IP) {/* IP header */ |
d6846af6 LF |
443 | if (((tmp[21] == 68) && (tmp[23] == 67)) || |
444 | ((tmp[21] == 67) && (tmp[23] == 68))) { | |
445 | /* 68 : UDP BOOTP client */ | |
446 | /* 67 : UDP BOOTP server */ | |
819fa2a0 | 447 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====================== %s: get DHCP Packet\n", __func__)); |
d6846af6 LF |
448 | /* Use low rate to send DHCP packet. */ |
449 | pattrib->dhcp_pkt = 1; | |
450 | } | |
451 | } | |
452 | } | |
7b170bac | 453 | } else if (pattrib->ether_type == ETH_P_PAE) { |
d6846af6 LF |
454 | DBG_88E_LEVEL(_drv_info_, "send eapol packet\n"); |
455 | } | |
456 | ||
7b170bac | 457 | if ((pattrib->ether_type == ETH_P_PAE) || (pattrib->dhcp_pkt == 1)) |
d6846af6 LF |
458 | rtw_set_scan_deny(padapter, 3000); |
459 | ||
460 | /* If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */ | |
7b170bac | 461 | if ((pattrib->ether_type == ETH_P_ARP) || (pattrib->ether_type == ETH_P_PAE) || (pattrib->dhcp_pkt == 1)) |
d6846af6 LF |
462 | rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SPECIAL_PACKET, 1); |
463 | ||
2bd827a8 | 464 | mcast = is_multicast_ether_addr(pattrib->ra); |
d6846af6 LF |
465 | |
466 | /* get sta_info */ | |
2bd827a8 | 467 | if (mcast) { |
d6846af6 LF |
468 | psta = rtw_get_bcmc_stainfo(padapter); |
469 | } else { | |
470 | psta = rtw_get_stainfo(pstapriv, pattrib->ra); | |
7de2258b | 471 | if (!psta) { /* if we cannot get psta => drrp the pkt */ |
d6846af6 LF |
472 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra: %pM\n", (pattrib->ra))); |
473 | res = _FAIL; | |
474 | goto exit; | |
3f95106e MS |
475 | } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) && |
476 | !(psta->state & _FW_LINKED)) { | |
d6846af6 LF |
477 | res = _FAIL; |
478 | goto exit; | |
479 | } | |
480 | } | |
481 | ||
482 | if (psta) { | |
483 | pattrib->mac_id = psta->mac_id; | |
484 | /* DBG_88E("%s ==> mac_id(%d)\n", __func__, pattrib->mac_id); */ | |
485 | pattrib->psta = psta; | |
486 | } else { | |
487 | /* if we cannot get psta => drop the pkt */ | |
488 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:%pM\n", (pattrib->ra))); | |
489 | res = _FAIL; | |
490 | goto exit; | |
491 | } | |
492 | ||
493 | pattrib->ack_policy = 0; | |
d6846af6 LF |
494 | |
495 | pattrib->hdrlen = WLAN_HDR_A3_LEN; | |
496 | pattrib->subtype = WIFI_DATA_TYPE; | |
497 | pattrib->priority = 0; | |
498 | ||
a66ecb24 MS |
499 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE | |
500 | WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) { | |
d6846af6 | 501 | if (psta->qos_option) |
ebb2a79d | 502 | set_qos(pkt, pattrib); |
d6846af6 LF |
503 | } else { |
504 | if (pqospriv->qos_option) { | |
ebb2a79d | 505 | set_qos(pkt, pattrib); |
d6846af6 LF |
506 | |
507 | if (pmlmepriv->acm_mask != 0) | |
508 | pattrib->priority = qos_acm(pmlmepriv->acm_mask, pattrib->priority); | |
509 | } | |
510 | } | |
511 | ||
512 | if (psta->ieee8021x_blocked) { | |
513 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\n psta->ieee8021x_blocked == true\n")); | |
514 | ||
515 | pattrib->encrypt = 0; | |
516 | ||
80c96e08 | 517 | if (pattrib->ether_type != ETH_P_PAE) { |
7b170bac | 518 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\npsta->ieee8021x_blocked == true, pattrib->ether_type(%.4x) != ETH_P_PAE\n", pattrib->ether_type)); |
d6846af6 LF |
519 | res = _FAIL; |
520 | goto exit; | |
521 | } | |
522 | } else { | |
2bd827a8 | 523 | GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, mcast); |
d6846af6 LF |
524 | |
525 | switch (psecuritypriv->dot11AuthAlgrthm) { | |
526 | case dot11AuthAlgrthm_Open: | |
527 | case dot11AuthAlgrthm_Shared: | |
528 | case dot11AuthAlgrthm_Auto: | |
529 | pattrib->key_idx = (u8)psecuritypriv->dot11PrivacyKeyIndex; | |
530 | break; | |
531 | case dot11AuthAlgrthm_8021X: | |
2bd827a8 | 532 | if (mcast) |
d6846af6 LF |
533 | pattrib->key_idx = (u8)psecuritypriv->dot118021XGrpKeyid; |
534 | else | |
535 | pattrib->key_idx = 0; | |
536 | break; | |
537 | default: | |
538 | pattrib->key_idx = 0; | |
539 | break; | |
540 | } | |
541 | } | |
542 | ||
543 | switch (pattrib->encrypt) { | |
544 | case _WEP40_: | |
545 | case _WEP104_: | |
546 | pattrib->iv_len = 4; | |
547 | pattrib->icv_len = 4; | |
548 | break; | |
549 | case _TKIP_: | |
550 | pattrib->iv_len = 8; | |
551 | pattrib->icv_len = 4; | |
552 | ||
553 | if (padapter->securitypriv.busetkipkey == _FAIL) { | |
554 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, | |
555 | ("\npadapter->securitypriv.busetkipkey(%d) == _FAIL drop packet\n", | |
556 | padapter->securitypriv.busetkipkey)); | |
557 | res = _FAIL; | |
558 | goto exit; | |
559 | } | |
560 | break; | |
561 | case _AES_: | |
562 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("pattrib->encrypt=%d (_AES_)\n", pattrib->encrypt)); | |
563 | pattrib->iv_len = 8; | |
564 | pattrib->icv_len = 8; | |
565 | break; | |
566 | default: | |
567 | pattrib->iv_len = 0; | |
568 | pattrib->icv_len = 0; | |
569 | break; | |
570 | } | |
571 | ||
572 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, | |
819fa2a0 | 573 | ("%s: encrypt=%d\n", __func__, pattrib->encrypt)); |
d6846af6 | 574 | |
1375baa9 | 575 | if (pattrib->encrypt && !psecuritypriv->hw_decrypted) { |
d6846af6 LF |
576 | pattrib->bswenc = true; |
577 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, | |
819fa2a0 | 578 | ("%s: encrypt=%d bswenc = true\n", __func__, |
1375baa9 | 579 | pattrib->encrypt)); |
d6846af6 LF |
580 | } else { |
581 | pattrib->bswenc = false; | |
819fa2a0 | 582 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s: bswenc = false\n", __func__)); |
d6846af6 LF |
583 | } |
584 | ||
d6846af6 LF |
585 | update_attrib_phy_info(pattrib, psta); |
586 | ||
587 | exit: | |
d6846af6 LF |
588 | return res; |
589 | } | |
590 | ||
591 | static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitframe) | |
592 | { | |
593 | int curfragnum, length; | |
594 | u8 *pframe, *payload, mic[8]; | |
595 | struct mic_data micdata; | |
596 | struct sta_info *stainfo; | |
597 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
598 | struct security_priv *psecuritypriv = &padapter->securitypriv; | |
599 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
79ebad32 | 600 | u8 priority[4] = {}; |
d6846af6 | 601 | u8 hw_hdr_offset = 0; |
d6846af6 LF |
602 | |
603 | if (pattrib->psta) | |
604 | stainfo = pattrib->psta; | |
605 | else | |
6d9b0f00 | 606 | stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]); |
d6846af6 | 607 | |
74772fcf | 608 | hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ); |
d6846af6 | 609 | |
1330c795 | 610 | if (pattrib->encrypt == _TKIP_) { |
d6846af6 | 611 | /* encode mic code */ |
7de2258b | 612 | if (stainfo) { |
79ebad32 | 613 | u8 null_key[16] = {}; |
d6846af6 LF |
614 | |
615 | pframe = pxmitframe->buf_addr + hw_hdr_offset; | |
616 | ||
2bd827a8 | 617 | if (is_multicast_ether_addr(pattrib->ra)) { |
f42f52aa | 618 | if (!memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16)) |
d6846af6 LF |
619 | return _FAIL; |
620 | /* start to calculate the mic code */ | |
621 | rtw_secmicsetkey(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey); | |
622 | } else { | |
1330c795 | 623 | if (!memcmp(&stainfo->dot11tkiptxmickey.skey[0], null_key, 16)) |
d6846af6 | 624 | return _FAIL; |
d6846af6 LF |
625 | /* start to calculate the mic code */ |
626 | rtw_secmicsetkey(&micdata, &stainfo->dot11tkiptxmickey.skey[0]); | |
627 | } | |
628 | ||
a66ecb24 | 629 | if (pframe[1] & 1) { /* ToDS == 1 */ |
d6846af6 | 630 | rtw_secmicappend(&micdata, &pframe[16], 6); /* DA */ |
a66ecb24 | 631 | if (pframe[1] & 2) /* From Ds == 1 */ |
d6846af6 LF |
632 | rtw_secmicappend(&micdata, &pframe[24], 6); |
633 | else | |
8126c7c1 | 634 | rtw_secmicappend(&micdata, &pframe[10], 6); |
d6846af6 LF |
635 | } else { /* ToDS == 0 */ |
636 | rtw_secmicappend(&micdata, &pframe[4], 6); /* DA */ | |
a66ecb24 | 637 | if (pframe[1] & 2) /* From Ds == 1 */ |
d6846af6 LF |
638 | rtw_secmicappend(&micdata, &pframe[16], 6); |
639 | else | |
640 | rtw_secmicappend(&micdata, &pframe[10], 6); | |
641 | } | |
642 | ||
643 | if (pattrib->qos_en) | |
644 | priority[0] = (u8)pxmitframe->attrib.priority; | |
645 | ||
646 | rtw_secmicappend(&micdata, &priority[0], 4); | |
647 | ||
648 | payload = pframe; | |
649 | ||
650 | for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { | |
7be921a2 | 651 | payload = (u8 *)round_up((size_t)(payload), 4); |
d6846af6 LF |
652 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, |
653 | ("=== curfragnum=%d, pframe = 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x,!!!\n", | |
a66ecb24 MS |
654 | curfragnum, *payload, *(payload + 1), |
655 | *(payload + 2), *(payload + 3), | |
656 | *(payload + 4), *(payload + 5), | |
657 | *(payload + 6), *(payload + 7))); | |
d6846af6 | 658 | |
a66ecb24 | 659 | payload += pattrib->hdrlen + pattrib->iv_len; |
d6846af6 LF |
660 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, |
661 | ("curfragnum=%d pattrib->hdrlen=%d pattrib->iv_len=%d", | |
662 | curfragnum, pattrib->hdrlen, pattrib->iv_len)); | |
a66ecb24 MS |
663 | if (curfragnum + 1 == pattrib->nr_frags) { |
664 | length = pattrib->last_txcmdsz - | |
665 | pattrib->hdrlen - | |
666 | pattrib->iv_len - | |
667 | ((pattrib->bswenc) ? | |
668 | pattrib->icv_len : 0); | |
d6846af6 | 669 | rtw_secmicappend(&micdata, payload, length); |
a66ecb24 | 670 | payload += length; |
d6846af6 | 671 | } else { |
a66ecb24 MS |
672 | length = pxmitpriv->frag_len - |
673 | pattrib->hdrlen - | |
674 | pattrib->iv_len - | |
675 | ((pattrib->bswenc) ? | |
676 | pattrib->icv_len : 0); | |
d6846af6 | 677 | rtw_secmicappend(&micdata, payload, length); |
a66ecb24 | 678 | payload += length + pattrib->icv_len; |
d6846af6 LF |
679 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("curfragnum=%d length=%d pattrib->icv_len=%d", curfragnum, length, pattrib->icv_len)); |
680 | } | |
681 | } | |
ceefaace | 682 | rtw_secgetmic(&micdata, &mic[0]); |
819fa2a0 SMR |
683 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: before add mic code!!!\n", __func__)); |
684 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: pattrib->last_txcmdsz=%d!!!\n", __func__, pattrib->last_txcmdsz)); | |
685 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: mic[0]=0x%.2x , mic[1]=0x%.2x , mic[2]= 0x%.2x, mic[3]=0x%.2x\n\ | |
d6846af6 | 686 | mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x , mic[7]= 0x%.2x !!!!\n", |
819fa2a0 | 687 | __func__, mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7])); |
d6846af6 LF |
688 | /* add mic code and add the mic code length in last_txcmdsz */ |
689 | ||
ceefaace | 690 | memcpy(payload, &mic[0], 8); |
d6846af6 LF |
691 | pattrib->last_txcmdsz += 8; |
692 | ||
693 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("\n ======== last pkt ========\n")); | |
a66ecb24 MS |
694 | payload -= pattrib->last_txcmdsz + 8; |
695 | for (curfragnum = 0; curfragnum < pattrib->last_txcmdsz; curfragnum += 8) | |
67c4b441 JSB |
696 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, |
697 | (" %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x ", | |
698 | *(payload + curfragnum), *(payload + curfragnum + 1), | |
699 | *(payload + curfragnum + 2), *(payload + curfragnum + 3), | |
700 | *(payload + curfragnum + 4), *(payload + curfragnum + 5), | |
701 | *(payload + curfragnum + 6), *(payload + curfragnum + 7))); | |
d6846af6 | 702 | } else { |
819fa2a0 | 703 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: rtw_get_stainfo==NULL!!!\n", __func__)); |
d6846af6 LF |
704 | } |
705 | } | |
706 | ||
d6846af6 LF |
707 | return _SUCCESS; |
708 | } | |
709 | ||
710 | static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmitframe) | |
711 | { | |
712 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
713 | ||
d6846af6 | 714 | if (pattrib->bswenc) { |
819fa2a0 | 715 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### %s\n", __func__)); |
d6846af6 LF |
716 | switch (pattrib->encrypt) { |
717 | case _WEP40_: | |
718 | case _WEP104_: | |
01713f0d | 719 | rtw_wep_encrypt(padapter, pxmitframe); |
d6846af6 LF |
720 | break; |
721 | case _TKIP_: | |
01713f0d | 722 | rtw_tkip_encrypt(padapter, pxmitframe); |
d6846af6 LF |
723 | break; |
724 | case _AES_: | |
01713f0d | 725 | rtw_aes_encrypt(padapter, pxmitframe); |
d6846af6 LF |
726 | break; |
727 | default: | |
728 | break; | |
729 | } | |
730 | } else { | |
731 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, ("### xmitframe_hwencrypt\n")); | |
732 | } | |
733 | ||
d6846af6 LF |
734 | return _SUCCESS; |
735 | } | |
736 | ||
7be921a2 | 737 | s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattrib) |
d6846af6 LF |
738 | { |
739 | u16 *qc; | |
740 | ||
d87f574d | 741 | struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr; |
d6846af6 LF |
742 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
743 | struct qos_priv *pqospriv = &pmlmepriv->qospriv; | |
744 | u8 qos_option = false; | |
745 | ||
746 | int res = _SUCCESS; | |
d87f574d | 747 | __le16 *fctrl = &pwlanhdr->frame_control; |
d6846af6 LF |
748 | |
749 | struct sta_info *psta; | |
750 | ||
d6846af6 LF |
751 | if (pattrib->psta) { |
752 | psta = pattrib->psta; | |
753 | } else { | |
2bd827a8 | 754 | if (is_multicast_ether_addr(pattrib->ra)) |
d6846af6 | 755 | psta = rtw_get_bcmc_stainfo(padapter); |
dc0283c7 | 756 | else |
d6846af6 | 757 | psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); |
d6846af6 LF |
758 | } |
759 | ||
1ce39848 | 760 | memset(hdr, 0, WLANHDR_OFFSET); |
d6846af6 LF |
761 | |
762 | SetFrameSubType(fctrl, pattrib->subtype); | |
763 | ||
764 | if (pattrib->subtype & WIFI_DATA_TYPE) { | |
3f95106e | 765 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { |
d6846af6 LF |
766 | /* to_ds = 1, fr_ds = 0; */ |
767 | /* Data transfer to AP */ | |
768 | SetToDs(fctrl); | |
769 | memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); | |
770 | memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); | |
771 | memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); | |
772 | ||
773 | if (pqospriv->qos_option) | |
774 | qos_option = true; | |
775 | } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { | |
776 | /* to_ds = 0, fr_ds = 1; */ | |
777 | SetFrDs(fctrl); | |
778 | memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); | |
779 | memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN); | |
780 | memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN); | |
781 | ||
22824194 | 782 | if (psta && psta->qos_option) |
d6846af6 LF |
783 | qos_option = true; |
784 | } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || | |
785 | check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { | |
786 | memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); | |
787 | memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); | |
788 | memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); | |
789 | ||
22824194 | 790 | if (psta && psta->qos_option) |
d6846af6 LF |
791 | qos_option = true; |
792 | } else { | |
793 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv))); | |
794 | res = _FAIL; | |
795 | goto exit; | |
796 | } | |
797 | ||
798 | if (pattrib->mdata) | |
799 | SetMData(fctrl); | |
800 | ||
801 | if (pattrib->encrypt) | |
802 | SetPrivacy(fctrl); | |
803 | ||
804 | if (qos_option) { | |
805 | qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); | |
806 | ||
807 | if (pattrib->priority) | |
808 | SetPriority(qc, pattrib->priority); | |
809 | ||
810 | SetEOSP(qc, pattrib->eosp); | |
811 | ||
812 | SetAckpolicy(qc, pattrib->ack_policy); | |
813 | } | |
814 | ||
815 | /* TODO: fill HT Control Field */ | |
816 | ||
817 | /* Update Seq Num will be handled by f/w */ | |
818 | if (psta) { | |
819 | psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; | |
820 | psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; | |
821 | ||
822 | pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority]; | |
823 | ||
824 | SetSeqNum(hdr, pattrib->seqnum); | |
825 | ||
826 | /* check if enable ampdu */ | |
827 | if (pattrib->ht_en && psta->htpriv.ampdu_enable) { | |
828 | if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) | |
4e0fa71c | 829 | pattrib->ampdu_en = true; |
d6846af6 LF |
830 | } |
831 | ||
832 | /* re-check if enable ampdu by BA_starting_seqctrl */ | |
833 | if (pattrib->ampdu_en) { | |
834 | u16 tx_seq; | |
835 | ||
836 | tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f]; | |
837 | ||
838 | /* check BA_starting_seqctrl */ | |
839 | if (SN_LESS(pattrib->seqnum, tx_seq)) { | |
840 | pattrib->ampdu_en = false;/* AGG BK */ | |
841 | } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) { | |
a66ecb24 | 842 | psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq + 1) & 0xfff; |
d6846af6 LF |
843 | |
844 | pattrib->ampdu_en = true;/* AGG EN */ | |
845 | } else { | |
a66ecb24 | 846 | psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum + 1) & 0xfff; |
d6846af6 LF |
847 | pattrib->ampdu_en = true;/* AGG EN */ |
848 | } | |
849 | } | |
850 | } | |
851 | } | |
852 | exit: | |
853 | ||
d6846af6 LF |
854 | return res; |
855 | } | |
856 | ||
857 | s32 rtw_txframes_pending(struct adapter *padapter) | |
858 | { | |
859 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
860 | ||
f7091bc6 | 861 | return (!list_empty(&pxmitpriv->be_pending.queue) || |
f996f374 MS |
862 | !list_empty(&pxmitpriv->bk_pending.queue) || |
863 | !list_empty(&pxmitpriv->vi_pending.queue) || | |
864 | !list_empty(&pxmitpriv->vo_pending.queue)); | |
d6846af6 LF |
865 | } |
866 | ||
867 | s32 rtw_txframes_sta_ac_pending(struct adapter *padapter, struct pkt_attrib *pattrib) | |
868 | { | |
869 | struct sta_info *psta; | |
870 | struct tx_servq *ptxservq; | |
871 | int priority = pattrib->priority; | |
872 | ||
873 | psta = pattrib->psta; | |
874 | ||
875 | switch (priority) { | |
876 | case 1: | |
877 | case 2: | |
ceefaace | 878 | ptxservq = &psta->sta_xmitpriv.bk_q; |
d6846af6 LF |
879 | break; |
880 | case 4: | |
881 | case 5: | |
ceefaace | 882 | ptxservq = &psta->sta_xmitpriv.vi_q; |
d6846af6 LF |
883 | break; |
884 | case 6: | |
885 | case 7: | |
ceefaace | 886 | ptxservq = &psta->sta_xmitpriv.vo_q; |
d6846af6 LF |
887 | break; |
888 | case 0: | |
889 | case 3: | |
890 | default: | |
ceefaace | 891 | ptxservq = &psta->sta_xmitpriv.be_q; |
d6846af6 LF |
892 | break; |
893 | } | |
894 | ||
895 | return ptxservq->qcnt; | |
896 | } | |
897 | ||
d6846af6 | 898 | /* |
ee53f6dd SF |
899 | * |
900 | * This sub-routine will perform all the following: | |
901 | * | |
902 | * 1. remove 802.3 header. | |
903 | * 2. create wlan_header, based on the info in pxmitframe | |
904 | * 3. append sta's iv/ext-iv | |
905 | * 4. append LLC | |
906 | * 5. move frag chunk from pframe to pxmitframe->mem | |
907 | * 6. apply sw-encrypt, if necessary. | |
908 | * | |
909 | */ | |
d6846af6 LF |
910 | s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe) |
911 | { | |
d6846af6 LF |
912 | s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; |
913 | size_t addr; | |
914 | u8 *pframe, *mem_start; | |
915 | u8 hw_hdr_offset; | |
916 | struct sta_info *psta; | |
917 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
918 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
919 | u8 *pbuf_start; | |
2bd827a8 | 920 | bool mcast = is_multicast_ether_addr(pattrib->ra); |
d6846af6 | 921 | s32 res = _SUCCESS; |
659c8734 | 922 | size_t remainder = pkt->len - ETH_HLEN; |
d6846af6 LF |
923 | |
924 | psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); | |
925 | ||
7de2258b | 926 | if (!psta) |
d6846af6 LF |
927 | return _FAIL; |
928 | ||
c39f4bb9 | 929 | if (!pxmitframe->buf_addr) { |
d6846af6 LF |
930 | DBG_88E("==> %s buf_addr == NULL\n", __func__); |
931 | return _FAIL; | |
932 | } | |
933 | ||
934 | pbuf_start = pxmitframe->buf_addr; | |
935 | ||
936 | hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ); | |
937 | ||
938 | mem_start = pbuf_start + hw_hdr_offset; | |
939 | ||
940 | if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) { | |
819fa2a0 SMR |
941 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: rtw_make_wlanhdr fail; drop pkt\n", __func__)); |
942 | DBG_88E("%s: rtw_make_wlanhdr fail; drop pkt\n", __func__); | |
d6846af6 LF |
943 | res = _FAIL; |
944 | goto exit; | |
945 | } | |
946 | ||
d6846af6 LF |
947 | frg_inx = 0; |
948 | frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */ | |
949 | ||
950 | while (1) { | |
951 | llc_sz = 0; | |
952 | ||
953 | mpdu_len = frg_len; | |
954 | ||
955 | pframe = mem_start; | |
956 | ||
957 | SetMFrag(mem_start); | |
958 | ||
959 | pframe += pattrib->hdrlen; | |
960 | mpdu_len -= pattrib->hdrlen; | |
961 | ||
962 | /* adding icv, if necessary... */ | |
963 | if (pattrib->iv_len) { | |
d48037f9 | 964 | switch (pattrib->encrypt) { |
4e0fa71c MB |
965 | case _WEP40_: |
966 | case _WEP104_: | |
967 | WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); | |
968 | break; | |
969 | case _TKIP_: | |
2bd827a8 | 970 | if (mcast) |
4e0fa71c MB |
971 | TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); |
972 | else | |
973 | TKIP_IV(pattrib->iv, psta->dot11txpn, 0); | |
974 | break; | |
975 | case _AES_: | |
2bd827a8 | 976 | if (mcast) |
4e0fa71c MB |
977 | AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); |
978 | else | |
979 | AES_IV(pattrib->iv, psta->dot11txpn, 0); | |
980 | break; | |
d6846af6 LF |
981 | } |
982 | ||
983 | memcpy(pframe, pattrib->iv, pattrib->iv_len); | |
984 | ||
985 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, | |
819fa2a0 | 986 | ("%s: keyid=%d pattrib->iv[3]=%.2x pframe=%.2x %.2x %.2x %.2x\n", |
a66ecb24 MS |
987 | __func__, |
988 | padapter->securitypriv.dot11PrivacyKeyIndex, | |
989 | pattrib->iv[3], *pframe, *(pframe + 1), | |
990 | *(pframe + 2), *(pframe + 3))); | |
d6846af6 LF |
991 | |
992 | pframe += pattrib->iv_len; | |
993 | ||
994 | mpdu_len -= pattrib->iv_len; | |
995 | } | |
996 | ||
997 | if (frg_inx == 0) { | |
998 | llc_sz = rtw_put_snap(pframe, pattrib->ether_type); | |
999 | pframe += llc_sz; | |
1000 | mpdu_len -= llc_sz; | |
1001 | } | |
1002 | ||
dc0283c7 | 1003 | if ((pattrib->icv_len > 0) && (pattrib->bswenc)) |
d6846af6 | 1004 | mpdu_len -= pattrib->icv_len; |
d6846af6 | 1005 | |
2bd827a8 | 1006 | mem_sz = min_t(size_t, mcast ? pattrib->pktlen : mpdu_len, remainder); |
659c8734 IS |
1007 | skb_copy_bits(pkt, pkt->len - remainder, pframe, mem_sz); |
1008 | remainder -= mem_sz; | |
d6846af6 LF |
1009 | |
1010 | pframe += mem_sz; | |
1011 | ||
1012 | if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { | |
1013 | memcpy(pframe, pattrib->icv, pattrib->icv_len); | |
1014 | pframe += pattrib->icv_len; | |
1015 | } | |
1016 | ||
1017 | frg_inx++; | |
1018 | ||
2bd827a8 | 1019 | if (mcast || remainder == 0) { |
d6846af6 LF |
1020 | pattrib->nr_frags = frg_inx; |
1021 | ||
1022 | pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1) ? llc_sz : 0) + | |
1023 | ((pattrib->bswenc) ? pattrib->icv_len : 0) + mem_sz; | |
1024 | ||
1025 | ClearMFrag(mem_start); | |
1026 | ||
1027 | break; | |
d6846af6 LF |
1028 | } |
1029 | ||
0b4d1d0d MS |
1030 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__)); |
1031 | ||
d6846af6 LF |
1032 | addr = (size_t)(pframe); |
1033 | ||
7be921a2 | 1034 | mem_start = (unsigned char *)round_up(addr, 4) + hw_hdr_offset; |
d6846af6 LF |
1035 | memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen); |
1036 | } | |
1037 | ||
0a0796eb JS |
1038 | /* Frame is about to be encrypted. Forward it to the monitor first. */ |
1039 | rtl88eu_mon_xmit_hook(padapter->pmondev, pxmitframe, frg_len); | |
1040 | ||
d6846af6 LF |
1041 | if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) { |
1042 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n")); | |
1043 | DBG_88E("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"); | |
1044 | res = _FAIL; | |
1045 | goto exit; | |
1046 | } | |
1047 | ||
1048 | xmitframe_swencrypt(padapter, pxmitframe); | |
1049 | ||
2bd827a8 | 1050 | if (!mcast) |
d6846af6 LF |
1051 | update_attrib_vcs_info(padapter, pxmitframe); |
1052 | else | |
1053 | pattrib->vcs_mode = NONE_VCS; | |
1054 | ||
1055 | exit: | |
d6846af6 LF |
1056 | return res; |
1057 | } | |
1058 | ||
1059 | /* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header | |
1060 | * IEEE LLC/SNAP header contains 8 octets | |
1061 | * First 3 octets comprise the LLC portion | |
1062 | * SNAP portion, 5 octets, is divided into two fields: | |
1063 | * Organizationally Unique Identifier(OUI), 3 octets, | |
1064 | * type, defined by that organization, 2 octets. | |
1065 | */ | |
1066 | s32 rtw_put_snap(u8 *data, u16 h_proto) | |
1067 | { | |
1068 | struct ieee80211_snap_hdr *snap; | |
1069 | u8 *oui; | |
1070 | ||
d6846af6 LF |
1071 | snap = (struct ieee80211_snap_hdr *)data; |
1072 | snap->dsap = 0xaa; | |
1073 | snap->ssap = 0xaa; | |
1074 | snap->ctrl = 0x03; | |
1075 | ||
1076 | if (h_proto == 0x8137 || h_proto == 0x80f3) | |
1077 | oui = P802_1H_OUI; | |
1078 | else | |
1079 | oui = RFC1042_OUI; | |
1080 | ||
1081 | snap->oui[0] = oui[0]; | |
1082 | snap->oui[1] = oui[1]; | |
1083 | snap->oui[2] = oui[2]; | |
1084 | ||
1085 | *(__be16 *)(data + SNAP_SIZE) = htons(h_proto); | |
1086 | ||
d6846af6 LF |
1087 | return SNAP_SIZE + sizeof(u16); |
1088 | } | |
1089 | ||
1090 | void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len) | |
1091 | { | |
af27bea4 | 1092 | uint protection, erp_len; |
d6846af6 | 1093 | u8 *perp; |
d6846af6 LF |
1094 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
1095 | struct registry_priv *pregistrypriv = &padapter->registrypriv; | |
1096 | ||
d6846af6 LF |
1097 | switch (pxmitpriv->vcs_setting) { |
1098 | case DISABLE_VCS: | |
1099 | pxmitpriv->vcs = NONE_VCS; | |
1100 | break; | |
1101 | case ENABLE_VCS: | |
1102 | break; | |
1103 | case AUTO_VCS: | |
1104 | default: | |
75f1df26 | 1105 | perp = rtw_get_ie(ie, WLAN_EID_ERP_INFO, &erp_len, ie_len); |
7de2258b | 1106 | if (!perp) { |
d6846af6 LF |
1107 | pxmitpriv->vcs = NONE_VCS; |
1108 | } else { | |
1109 | protection = (*(perp + 2)) & BIT(1); | |
1110 | if (protection) { | |
1111 | if (pregistrypriv->vcs_type == RTS_CTS) | |
1112 | pxmitpriv->vcs = RTS_CTS; | |
1113 | else | |
1114 | pxmitpriv->vcs = CTS_TO_SELF; | |
1115 | } else { | |
1116 | pxmitpriv->vcs = NONE_VCS; | |
1117 | } | |
1118 | } | |
1119 | break; | |
1120 | } | |
d6846af6 LF |
1121 | } |
1122 | ||
1123 | void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz) | |
1124 | { | |
1125 | struct sta_info *psta = NULL; | |
1126 | struct stainfo_stats *pstats = NULL; | |
1127 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
1128 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
1129 | ||
a66ecb24 | 1130 | if ((pxmitframe->frame_tag & 0x0f) == DATA_FRAMETAG) { |
d6846af6 LF |
1131 | pxmitpriv->tx_bytes += sz; |
1132 | pmlmepriv->LinkDetectInfo.NumTxOkInPeriod += pxmitframe->agg_num; | |
1133 | ||
1134 | psta = pxmitframe->attrib.psta; | |
1135 | if (psta) { | |
1136 | pstats = &psta->sta_stats; | |
1137 | pstats->tx_pkts += pxmitframe->agg_num; | |
1138 | pstats->tx_bytes += sz; | |
1139 | } | |
1140 | } | |
1141 | } | |
1142 | ||
1143 | struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) | |
1144 | { | |
1145 | unsigned long irql; | |
b9f1c275 | 1146 | struct xmit_buf *pxmitbuf; |
d6846af6 LF |
1147 | struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; |
1148 | ||
f937886b | 1149 | spin_lock_irqsave(&pfree_queue->lock, irql); |
b9f1c275 GT |
1150 | pxmitbuf = list_first_entry_or_null(&pfree_queue->queue, |
1151 | struct xmit_buf, list); | |
1152 | if (pxmitbuf) { | |
1153 | list_del_init(&pxmitbuf->list); | |
d6846af6 | 1154 | pxmitpriv->free_xmit_extbuf_cnt--; |
d6846af6 | 1155 | pxmitbuf->priv_data = NULL; |
d6846af6 LF |
1156 | if (pxmitbuf->sctx) { |
1157 | DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__); | |
1158 | rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); | |
1159 | } | |
1160 | } | |
597794f5 | 1161 | spin_unlock_irqrestore(&pfree_queue->lock, irql); |
d6846af6 | 1162 | |
d6846af6 LF |
1163 | return pxmitbuf; |
1164 | } | |
1165 | ||
1166 | s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) | |
1167 | { | |
1168 | unsigned long irql; | |
1169 | struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; | |
1170 | ||
7de2258b | 1171 | if (!pxmitbuf) |
d6846af6 LF |
1172 | return _FAIL; |
1173 | ||
f937886b | 1174 | spin_lock_irqsave(&pfree_queue->lock, irql); |
d6846af6 | 1175 | |
8d5bdece | 1176 | list_del_init(&pxmitbuf->list); |
d6846af6 | 1177 | |
ceefaace | 1178 | list_add_tail(&pxmitbuf->list, get_list_head(pfree_queue)); |
d6846af6 LF |
1179 | pxmitpriv->free_xmit_extbuf_cnt++; |
1180 | ||
597794f5 | 1181 | spin_unlock_irqrestore(&pfree_queue->lock, irql); |
d6846af6 | 1182 | |
d6846af6 LF |
1183 | return _SUCCESS; |
1184 | } | |
1185 | ||
1186 | struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) | |
1187 | { | |
1188 | unsigned long irql; | |
b9f1c275 | 1189 | struct xmit_buf *pxmitbuf; |
d6846af6 LF |
1190 | struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; |
1191 | ||
f937886b | 1192 | spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irql); |
b9f1c275 GT |
1193 | pxmitbuf = list_first_entry_or_null(&pfree_xmitbuf_queue->queue, |
1194 | struct xmit_buf, list); | |
1195 | if (pxmitbuf) { | |
1196 | list_del_init(&pxmitbuf->list); | |
d6846af6 LF |
1197 | pxmitpriv->free_xmitbuf_cnt--; |
1198 | pxmitbuf->priv_data = NULL; | |
1199 | if (pxmitbuf->sctx) { | |
1200 | DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__); | |
1201 | rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); | |
1202 | } | |
1203 | } | |
597794f5 | 1204 | spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irql); |
d6846af6 | 1205 | |
d6846af6 LF |
1206 | return pxmitbuf; |
1207 | } | |
1208 | ||
1209 | s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) | |
1210 | { | |
1211 | unsigned long irql; | |
1212 | struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; | |
1213 | ||
7de2258b | 1214 | if (!pxmitbuf) |
d6846af6 LF |
1215 | return _FAIL; |
1216 | ||
1217 | if (pxmitbuf->sctx) { | |
1218 | DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__); | |
1219 | rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE); | |
1220 | } | |
1221 | ||
1222 | if (pxmitbuf->ext_tag) { | |
1223 | rtw_free_xmitbuf_ext(pxmitpriv, pxmitbuf); | |
1224 | } else { | |
f937886b | 1225 | spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irql); |
d6846af6 | 1226 | |
8d5bdece | 1227 | list_del_init(&pxmitbuf->list); |
d6846af6 | 1228 | |
ceefaace | 1229 | list_add_tail(&pxmitbuf->list, get_list_head(pfree_xmitbuf_queue)); |
d6846af6 LF |
1230 | |
1231 | pxmitpriv->free_xmitbuf_cnt++; | |
597794f5 | 1232 | spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irql); |
d6846af6 LF |
1233 | } |
1234 | ||
d6846af6 LF |
1235 | return _SUCCESS; |
1236 | } | |
1237 | ||
1238 | /* | |
ee53f6dd SF |
1239 | * Calling context: |
1240 | * 1. OS_TXENTRY | |
1241 | * 2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) | |
1242 | * | |
1243 | * If we turn on USE_RXTHREAD, then, no need for critical section. | |
1244 | * Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... | |
1245 | * | |
b79f45e2 | 1246 | * Must be very, very cautious... |
ee53f6dd SF |
1247 | * |
1248 | */ | |
d6846af6 | 1249 | |
b9f1c275 GT |
1250 | struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv) |
1251 | /* _queue *pfree_xmit_queue) */ | |
d6846af6 LF |
1252 | { |
1253 | /* | |
ee53f6dd SF |
1254 | * Please remember to use all the osdep_service api, |
1255 | * and lock/unlock or _enter/_exit critical to protect | |
1256 | * pfree_xmit_queue | |
1257 | */ | |
b9f1c275 | 1258 | struct xmit_frame *pxframe; |
d6846af6 LF |
1259 | struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; |
1260 | ||
7057dcb3 | 1261 | spin_lock_bh(&pfree_xmit_queue->lock); |
b9f1c275 GT |
1262 | pxframe = list_first_entry_or_null(&pfree_xmit_queue->queue, |
1263 | struct xmit_frame, list); | |
1264 | if (!pxframe) { | |
1265 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, | |
1266 | ("rtw_alloc_xmitframe:%d\n", | |
1267 | pxmitpriv->free_xmitframe_cnt)); | |
d6846af6 | 1268 | } else { |
b9f1c275 | 1269 | list_del_init(&pxframe->list); |
d6846af6 | 1270 | |
b9f1c275 | 1271 | /* default value setting */ |
d6846af6 LF |
1272 | pxmitpriv->free_xmitframe_cnt--; |
1273 | ||
b9f1c275 GT |
1274 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, |
1275 | ("rtw_alloc_xmitframe():free_xmitframe_cnt=%d\n", | |
1276 | pxmitpriv->free_xmitframe_cnt)); | |
d6846af6 LF |
1277 | |
1278 | pxframe->buf_addr = NULL; | |
1279 | pxframe->pxmitbuf = NULL; | |
1280 | ||
1ce39848 | 1281 | memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib)); |
d6846af6 LF |
1282 | |
1283 | pxframe->frame_tag = DATA_FRAMETAG; | |
1284 | ||
1285 | pxframe->pkt = NULL; | |
1286 | pxframe->pkt_offset = 1;/* default use pkt_offset to fill tx desc */ | |
1287 | ||
1288 | pxframe->agg_num = 1; | |
1289 | pxframe->ack_report = 0; | |
1290 | } | |
e02bcf61 | 1291 | spin_unlock_bh(&pfree_xmit_queue->lock); |
d6846af6 | 1292 | |
d6846af6 LF |
1293 | return pxframe; |
1294 | } | |
1295 | ||
1296 | s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe) | |
1297 | { | |
d6846af6 LF |
1298 | struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; |
1299 | struct adapter *padapter = pxmitpriv->adapter; | |
1300 | struct sk_buff *pndis_pkt = NULL; | |
1301 | ||
7de2258b | 1302 | if (!pxmitframe) { |
819fa2a0 | 1303 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== %s:pxmitframe == NULL!!!!!!!!!!\n", __func__)); |
d6846af6 LF |
1304 | goto exit; |
1305 | } | |
1306 | ||
7057dcb3 | 1307 | spin_lock_bh(&pfree_xmit_queue->lock); |
d6846af6 | 1308 | |
8d5bdece | 1309 | list_del_init(&pxmitframe->list); |
d6846af6 LF |
1310 | |
1311 | if (pxmitframe->pkt) { | |
1312 | pndis_pkt = pxmitframe->pkt; | |
1313 | pxmitframe->pkt = NULL; | |
1314 | } | |
1315 | ||
ae6787ad | 1316 | list_add_tail(&pxmitframe->list, get_list_head(pfree_xmit_queue)); |
d6846af6 LF |
1317 | |
1318 | pxmitpriv->free_xmitframe_cnt++; | |
819fa2a0 | 1319 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("%s:free_xmitframe_cnt=%d\n", __func__, pxmitpriv->free_xmitframe_cnt)); |
d6846af6 | 1320 | |
e02bcf61 | 1321 | spin_unlock_bh(&pfree_xmit_queue->lock); |
d6846af6 LF |
1322 | |
1323 | if (pndis_pkt) | |
1324 | rtw_os_pkt_complete(padapter, pndis_pkt); | |
1325 | ||
1326 | exit: | |
d6846af6 LF |
1327 | return _SUCCESS; |
1328 | } | |
1329 | ||
1330 | void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue) | |
1331 | { | |
af39f935 MK |
1332 | struct list_head *phead; |
1333 | struct xmit_frame *pxmitframe, *temp; | |
d6846af6 | 1334 | |
ceefaace | 1335 | spin_lock_bh(&pframequeue->lock); |
d6846af6 LF |
1336 | |
1337 | phead = get_list_head(pframequeue); | |
af39f935 | 1338 | list_for_each_entry_safe(pxmitframe, temp, phead, list) |
d6846af6 | 1339 | rtw_free_xmitframe(pxmitpriv, pxmitframe); |
af39f935 | 1340 | |
ceefaace | 1341 | spin_unlock_bh(&pframequeue->lock); |
d6846af6 LF |
1342 | } |
1343 | ||
1344 | s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe) | |
1345 | { | |
1346 | if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) { | |
1347 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, | |
819fa2a0 | 1348 | ("%s: drop xmit pkt for classifier fail\n", __func__)); |
d6846af6 LF |
1349 | return _FAIL; |
1350 | } | |
1351 | ||
1352 | return _SUCCESS; | |
1353 | } | |
1354 | ||
1355 | static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit, struct tx_servq *ptxservq, struct __queue *pframe_queue) | |
1356 | { | |
1357 | struct list_head *xmitframe_plist, *xmitframe_phead; | |
1358 | struct xmit_frame *pxmitframe = NULL; | |
1359 | ||
1360 | xmitframe_phead = get_list_head(pframe_queue); | |
c44e5e39 | 1361 | xmitframe_plist = xmitframe_phead->next; |
d6846af6 | 1362 | |
84660700 | 1363 | if (xmitframe_phead != xmitframe_plist) { |
bea88100 | 1364 | pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); |
d6846af6 | 1365 | |
c44e5e39 | 1366 | xmitframe_plist = xmitframe_plist->next; |
d6846af6 | 1367 | |
8d5bdece | 1368 | list_del_init(&pxmitframe->list); |
d6846af6 LF |
1369 | |
1370 | ptxservq->qcnt--; | |
d6846af6 | 1371 | } |
d6846af6 LF |
1372 | return pxmitframe; |
1373 | } | |
1374 | ||
1375 | struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i, int entry) | |
1376 | { | |
d6846af6 LF |
1377 | struct list_head *sta_plist, *sta_phead; |
1378 | struct hw_xmit *phwxmit; | |
1379 | struct tx_servq *ptxservq = NULL; | |
1380 | struct __queue *pframe_queue = NULL; | |
1381 | struct xmit_frame *pxmitframe = NULL; | |
1382 | struct adapter *padapter = pxmitpriv->adapter; | |
1383 | struct registry_priv *pregpriv = &padapter->registrypriv; | |
1384 | int i, inx[4]; | |
1385 | ||
d6846af6 LF |
1386 | inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; |
1387 | ||
1388 | if (pregpriv->wifi_spec == 1) { | |
1389 | int j; | |
1390 | ||
1391 | for (j = 0; j < 4; j++) | |
1392 | inx[j] = pxmitpriv->wmm_para_seq[j]; | |
1393 | } | |
1394 | ||
7057dcb3 | 1395 | spin_lock_bh(&pxmitpriv->lock); |
d6846af6 LF |
1396 | |
1397 | for (i = 0; i < entry; i++) { | |
1398 | phwxmit = phwxmit_i + inx[i]; | |
1399 | ||
1400 | sta_phead = get_list_head(phwxmit->sta_queue); | |
23017c88 GR |
1401 | list_for_each(sta_plist, sta_phead) { |
1402 | ptxservq = list_entry(sta_plist, struct tx_servq, | |
1403 | tx_pending); | |
d6846af6 LF |
1404 | |
1405 | pframe_queue = &ptxservq->sta_pending; | |
1406 | ||
1407 | pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue); | |
1408 | ||
1409 | if (pxmitframe) { | |
1410 | phwxmit->accnt--; | |
1411 | ||
1412 | /* Remove sta node when there are no pending packets. */ | |
f7091bc6 | 1413 | if (list_empty(&pframe_queue->queue)) /* must be done after get_next and before break */ |
8d5bdece | 1414 | list_del_init(&ptxservq->tx_pending); |
d6846af6 LF |
1415 | goto exit; |
1416 | } | |
d6846af6 LF |
1417 | } |
1418 | } | |
1419 | exit: | |
e02bcf61 | 1420 | spin_unlock_bh(&pxmitpriv->lock); |
d6846af6 LF |
1421 | return pxmitframe; |
1422 | } | |
1423 | ||
d7c25200 MS |
1424 | struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, |
1425 | struct sta_info *psta, int up, u8 *ac) | |
d6846af6 LF |
1426 | { |
1427 | struct tx_servq *ptxservq; | |
1428 | ||
d6846af6 LF |
1429 | switch (up) { |
1430 | case 1: | |
1431 | case 2: | |
ceefaace | 1432 | ptxservq = &psta->sta_xmitpriv.bk_q; |
d6846af6 | 1433 | *(ac) = 3; |
d7c25200 MS |
1434 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, |
1435 | ("%s : BK\n", __func__)); | |
d6846af6 LF |
1436 | break; |
1437 | case 4: | |
1438 | case 5: | |
ceefaace | 1439 | ptxservq = &psta->sta_xmitpriv.vi_q; |
d6846af6 | 1440 | *(ac) = 1; |
d7c25200 MS |
1441 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, |
1442 | ("%s : VI\n", __func__)); | |
d6846af6 LF |
1443 | break; |
1444 | case 6: | |
1445 | case 7: | |
ceefaace | 1446 | ptxservq = &psta->sta_xmitpriv.vo_q; |
d6846af6 | 1447 | *(ac) = 0; |
d7c25200 MS |
1448 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, |
1449 | ("%s : VO\n", __func__)); | |
d6846af6 LF |
1450 | break; |
1451 | case 0: | |
1452 | case 3: | |
1453 | default: | |
ceefaace | 1454 | ptxservq = &psta->sta_xmitpriv.be_q; |
d6846af6 | 1455 | *(ac) = 2; |
d7c25200 MS |
1456 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, |
1457 | ("%s : BE\n", __func__)); | |
d6846af6 LF |
1458 | break; |
1459 | } | |
1460 | ||
d6846af6 LF |
1461 | return ptxservq; |
1462 | } | |
1463 | ||
1464 | /* | |
1465 | * Will enqueue pxmitframe to the proper queue, | |
1466 | * and indicate it to xx_pending list..... | |
1467 | */ | |
1468 | s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe) | |
1469 | { | |
d6846af6 LF |
1470 | u8 ac_index; |
1471 | struct sta_info *psta; | |
1472 | struct tx_servq *ptxservq; | |
1473 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
1474 | struct sta_priv *pstapriv = &padapter->stapriv; | |
1475 | struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; | |
1476 | int res = _SUCCESS; | |
1477 | ||
dc0283c7 | 1478 | if (pattrib->psta) |
d6846af6 | 1479 | psta = pattrib->psta; |
dc0283c7 | 1480 | else |
d6846af6 | 1481 | psta = rtw_get_stainfo(pstapriv, pattrib->ra); |
d6846af6 | 1482 | |
7de2258b | 1483 | if (!psta) { |
d6846af6 | 1484 | res = _FAIL; |
819fa2a0 SMR |
1485 | DBG_88E("%s: psta == NULL\n", __func__); |
1486 | RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: psta == NULL\n", __func__)); | |
d6846af6 LF |
1487 | goto exit; |
1488 | } | |
1489 | ||
1490 | ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); | |
1491 | ||
9c4b0e70 | 1492 | if (list_empty(&ptxservq->tx_pending)) |
ae6787ad | 1493 | list_add_tail(&ptxservq->tx_pending, get_list_head(phwxmits[ac_index].sta_queue)); |
d6846af6 | 1494 | |
ae6787ad | 1495 | list_add_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending)); |
d6846af6 LF |
1496 | ptxservq->qcnt++; |
1497 | phwxmits[ac_index].accnt++; | |
1498 | exit: | |
d6846af6 LF |
1499 | return res; |
1500 | } | |
1501 | ||
7671ce0d | 1502 | s32 rtw_alloc_hwxmits(struct adapter *padapter) |
d6846af6 LF |
1503 | { |
1504 | struct hw_xmit *hwxmits; | |
1505 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
1506 | ||
1507 | pxmitpriv->hwxmit_entry = HWXMIT_ENTRY; | |
1508 | ||
0507a1e5 NSN |
1509 | pxmitpriv->hwxmits = kcalloc(pxmitpriv->hwxmit_entry, |
1510 | sizeof(struct hw_xmit), GFP_KERNEL); | |
7671ce0d AP |
1511 | if (!pxmitpriv->hwxmits) |
1512 | return _FAIL; | |
d6846af6 LF |
1513 | |
1514 | hwxmits = pxmitpriv->hwxmits; | |
1515 | ||
c181be7f MS |
1516 | hwxmits[0] .sta_queue = &pxmitpriv->vo_pending; |
1517 | hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; | |
1518 | hwxmits[2] .sta_queue = &pxmitpriv->be_pending; | |
1519 | hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; | |
7671ce0d | 1520 | return _SUCCESS; |
d6846af6 LF |
1521 | } |
1522 | ||
1523 | void rtw_free_hwxmits(struct adapter *padapter) | |
1524 | { | |
1525 | struct hw_xmit *hwxmits; | |
1526 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
1527 | ||
1528 | hwxmits = pxmitpriv->hwxmits; | |
1529 | kfree(hwxmits); | |
1530 | } | |
1531 | ||
1532 | void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry) | |
1533 | { | |
1534 | int i; | |
7d2af82c | 1535 | |
d6846af6 LF |
1536 | for (i = 0; i < entry; i++, phwxmit++) |
1537 | phwxmit->accnt = 0; | |
d6846af6 LF |
1538 | } |
1539 | ||
d6846af6 LF |
1540 | u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe) |
1541 | { | |
1542 | u32 addr; | |
1543 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
1544 | ||
1545 | switch (pattrib->qsel) { | |
1546 | case 0: | |
1547 | case 3: | |
1548 | addr = BE_QUEUE_INX; | |
1549 | break; | |
1550 | case 1: | |
1551 | case 2: | |
1552 | addr = BK_QUEUE_INX; | |
1553 | break; | |
1554 | case 4: | |
1555 | case 5: | |
1556 | addr = VI_QUEUE_INX; | |
1557 | break; | |
1558 | case 6: | |
1559 | case 7: | |
1560 | addr = VO_QUEUE_INX; | |
1561 | break; | |
1562 | case 0x10: | |
1563 | addr = BCN_QUEUE_INX; | |
1564 | break; | |
1565 | case 0x11:/* BC/MC in PS (HIQ) */ | |
1566 | addr = HIGH_QUEUE_INX; | |
1567 | break; | |
1568 | case 0x12: | |
1569 | default: | |
1570 | addr = MGT_QUEUE_INX; | |
1571 | break; | |
1572 | } | |
1573 | ||
1574 | return addr; | |
1575 | } | |
1576 | ||
d6846af6 LF |
1577 | /* |
1578 | * The main transmit(tx) entry | |
1579 | * | |
1580 | * Return | |
1581 | * 1 enqueue | |
1582 | * 0 success, hardware will handle this xmit frame(packet) | |
1583 | * <0 fail | |
1584 | */ | |
1585 | s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt) | |
1586 | { | |
d6846af6 LF |
1587 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
1588 | struct xmit_frame *pxmitframe = NULL; | |
d6846af6 LF |
1589 | s32 res; |
1590 | ||
1591 | pxmitframe = rtw_alloc_xmitframe(pxmitpriv); | |
7de2258b | 1592 | if (!pxmitframe) { |
819fa2a0 | 1593 | RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: no more pxmitframe\n", __func__)); |
d6846af6 LF |
1594 | DBG_88E("DBG_TX_DROP_FRAME %s no more pxmitframe\n", __func__); |
1595 | return -1; | |
1596 | } | |
1597 | ||
d6846af6 LF |
1598 | res = update_attrib(padapter, *ppkt, &pxmitframe->attrib); |
1599 | ||
1600 | if (res == _FAIL) { | |
819fa2a0 | 1601 | RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: update attrib fail\n", __func__)); |
d6846af6 LF |
1602 | rtw_free_xmitframe(pxmitpriv, pxmitframe); |
1603 | return -1; | |
1604 | } | |
1605 | pxmitframe->pkt = *ppkt; | |
1606 | ||
236b3d87 | 1607 | led_control_8188eu(padapter, LED_CTL_TX); |
d6846af6 | 1608 | |
3929667e | 1609 | pxmitframe->attrib.qsel = pxmitframe->attrib.priority; |
d6846af6 LF |
1610 | |
1611 | #ifdef CONFIG_88EU_AP_MODE | |
7057dcb3 | 1612 | spin_lock_bh(&pxmitpriv->lock); |
d6846af6 | 1613 | if (xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe)) { |
e02bcf61 | 1614 | spin_unlock_bh(&pxmitpriv->lock); |
d6846af6 LF |
1615 | return 1; |
1616 | } | |
e02bcf61 | 1617 | spin_unlock_bh(&pxmitpriv->lock); |
d6846af6 LF |
1618 | #endif |
1619 | ||
bbf2f71e | 1620 | if (!rtw_hal_xmit(padapter, pxmitframe)) |
d6846af6 LF |
1621 | return 1; |
1622 | ||
1623 | return 0; | |
1624 | } | |
1625 | ||
1626 | #if defined(CONFIG_88EU_AP_MODE) | |
1627 | ||
1628 | int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe) | |
1629 | { | |
d6846af6 LF |
1630 | int ret = false; |
1631 | struct sta_info *psta = NULL; | |
1632 | struct sta_priv *pstapriv = &padapter->stapriv; | |
1633 | struct pkt_attrib *pattrib = &pxmitframe->attrib; | |
1634 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
2bd827a8 | 1635 | bool mcast = is_multicast_ether_addr(pattrib->ra); |
d6846af6 | 1636 | |
bbf2f71e | 1637 | if (!check_fwstate(pmlmepriv, WIFI_AP_STATE)) |
4e0fa71c | 1638 | return ret; |
d6846af6 LF |
1639 | |
1640 | if (pattrib->psta) | |
1641 | psta = pattrib->psta; | |
1642 | else | |
1643 | psta = rtw_get_stainfo(pstapriv, pattrib->ra); | |
1644 | ||
7de2258b | 1645 | if (!psta) |
d6846af6 LF |
1646 | return ret; |
1647 | ||
1648 | if (pattrib->triggered == 1) { | |
2bd827a8 | 1649 | if (mcast) |
d6846af6 LF |
1650 | pattrib->qsel = 0x11;/* HIQ */ |
1651 | return ret; | |
1652 | } | |
1653 | ||
2bd827a8 | 1654 | if (mcast) { |
7057dcb3 | 1655 | spin_lock_bh(&psta->sleep_q.lock); |
d6846af6 LF |
1656 | |
1657 | if (pstapriv->sta_dz_bitmap) {/* if any one sta is in ps mode */ | |
8d5bdece | 1658 | list_del_init(&pxmitframe->list); |
d6846af6 | 1659 | |
ae6787ad | 1660 | list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); |
d6846af6 LF |
1661 | |
1662 | psta->sleepq_len++; | |
1663 | ||
1664 | pstapriv->tim_bitmap |= BIT(0);/* */ | |
1665 | pstapriv->sta_dz_bitmap |= BIT(0); | |
1666 | ||
75f1df26 | 1667 | update_beacon(padapter, WLAN_EID_TIM, NULL, false);/* tx bc/mc packets after update bcn */ |
d6846af6 LF |
1668 | |
1669 | ret = true; | |
1670 | } | |
1671 | ||
e02bcf61 | 1672 | spin_unlock_bh(&psta->sleep_q.lock); |
d6846af6 LF |
1673 | |
1674 | return ret; | |
1675 | } | |
1676 | ||
7057dcb3 | 1677 | spin_lock_bh(&psta->sleep_q.lock); |
d6846af6 | 1678 | |
a66ecb24 | 1679 | if (psta->state & WIFI_SLEEP_STATE) { |
d6846af6 LF |
1680 | u8 wmmps_ac = 0; |
1681 | ||
a66ecb24 | 1682 | if (pstapriv->sta_dz_bitmap & BIT(psta->aid)) { |
8d5bdece | 1683 | list_del_init(&pxmitframe->list); |
d6846af6 | 1684 | |
ae6787ad | 1685 | list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); |
d6846af6 LF |
1686 | |
1687 | psta->sleepq_len++; | |
1688 | ||
1689 | switch (pattrib->priority) { | |
1690 | case 1: | |
1691 | case 2: | |
c89e9869 | 1692 | wmmps_ac = psta->uapsd_bk & BIT(0); |
d6846af6 LF |
1693 | break; |
1694 | case 4: | |
1695 | case 5: | |
c89e9869 | 1696 | wmmps_ac = psta->uapsd_vi & BIT(0); |
d6846af6 LF |
1697 | break; |
1698 | case 6: | |
1699 | case 7: | |
c89e9869 | 1700 | wmmps_ac = psta->uapsd_vo & BIT(0); |
d6846af6 LF |
1701 | break; |
1702 | case 0: | |
1703 | case 3: | |
1704 | default: | |
c89e9869 | 1705 | wmmps_ac = psta->uapsd_be & BIT(0); |
d6846af6 LF |
1706 | break; |
1707 | } | |
1708 | ||
1709 | if (wmmps_ac) | |
1710 | psta->sleepq_ac_len++; | |
1711 | ||
1712 | if (((psta->has_legacy_ac) && (!wmmps_ac)) || | |
1713 | ((!psta->has_legacy_ac) && (wmmps_ac))) { | |
1714 | pstapriv->tim_bitmap |= BIT(psta->aid); | |
1715 | ||
1716 | if (psta->sleepq_len == 1) { | |
40a46d8b | 1717 | /* update BCN for TIM IE */ |
75f1df26 | 1718 | update_beacon(padapter, WLAN_EID_TIM, NULL, false); |
d6846af6 LF |
1719 | } |
1720 | } | |
1721 | ret = true; | |
1722 | } | |
1723 | } | |
1724 | ||
e02bcf61 | 1725 | spin_unlock_bh(&psta->sleep_q.lock); |
d6846af6 LF |
1726 | |
1727 | return ret; | |
1728 | } | |
1729 | ||
1730 | static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct __queue *pframequeue) | |
1731 | { | |
e0f489a2 | 1732 | struct list_head *phead; |
d6846af6 LF |
1733 | u8 ac_index; |
1734 | struct tx_servq *ptxservq; | |
1735 | struct pkt_attrib *pattrib; | |
e0f489a2 | 1736 | struct xmit_frame *pxmitframe, *n; |
d6846af6 LF |
1737 | struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; |
1738 | ||
1739 | phead = get_list_head(pframequeue); | |
e0f489a2 | 1740 | list_for_each_entry_safe(pxmitframe, n, phead, list) { |
d6846af6 LF |
1741 | xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe); |
1742 | ||
1743 | pattrib = &pxmitframe->attrib; | |
1744 | ||
1745 | ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); | |
1746 | ||
1747 | ptxservq->qcnt--; | |
1748 | phwxmits[ac_index].accnt--; | |
1749 | } | |
1750 | } | |
1751 | ||
1752 | void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta) | |
1753 | { | |
d6846af6 LF |
1754 | struct sta_info *psta_bmc; |
1755 | struct sta_xmit_priv *pstaxmitpriv; | |
1756 | struct sta_priv *pstapriv = &padapter->stapriv; | |
1757 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
1758 | ||
1759 | pstaxmitpriv = &psta->sta_xmitpriv; | |
1760 | ||
1761 | /* for BC/MC Frames */ | |
1762 | psta_bmc = rtw_get_bcmc_stainfo(padapter); | |
1763 | ||
7057dcb3 | 1764 | spin_lock_bh(&pxmitpriv->lock); |
d6846af6 LF |
1765 | |
1766 | psta->state |= WIFI_SLEEP_STATE; | |
1767 | ||
1768 | pstapriv->sta_dz_bitmap |= BIT(psta->aid); | |
1769 | ||
e0437819 MS |
1770 | dequeue_xmitframes_to_sleeping_queue(padapter, psta, |
1771 | &pstaxmitpriv->vo_q.sta_pending); | |
ceefaace | 1772 | list_del_init(&pstaxmitpriv->vo_q.tx_pending); |
d6846af6 | 1773 | |
e0437819 MS |
1774 | dequeue_xmitframes_to_sleeping_queue(padapter, psta, |
1775 | &pstaxmitpriv->vi_q.sta_pending); | |
ceefaace | 1776 | list_del_init(&pstaxmitpriv->vi_q.tx_pending); |
d6846af6 | 1777 | |
e0437819 MS |
1778 | dequeue_xmitframes_to_sleeping_queue(padapter, psta, |
1779 | &pstaxmitpriv->be_q.sta_pending); | |
ceefaace | 1780 | list_del_init(&pstaxmitpriv->be_q.tx_pending); |
d6846af6 | 1781 | |
e0437819 MS |
1782 | dequeue_xmitframes_to_sleeping_queue(padapter, psta, |
1783 | &pstaxmitpriv->bk_q.sta_pending); | |
ceefaace | 1784 | list_del_init(&pstaxmitpriv->bk_q.tx_pending); |
d6846af6 LF |
1785 | |
1786 | /* for BC/MC Frames */ | |
1787 | pstaxmitpriv = &psta_bmc->sta_xmitpriv; | |
e0437819 MS |
1788 | dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc, |
1789 | &pstaxmitpriv->be_q.sta_pending); | |
ceefaace | 1790 | list_del_init(&pstaxmitpriv->be_q.tx_pending); |
d6846af6 | 1791 | |
e02bcf61 | 1792 | spin_unlock_bh(&pxmitpriv->lock); |
d6846af6 LF |
1793 | } |
1794 | ||
1795 | void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta) | |
1796 | { | |
d6846af6 LF |
1797 | u8 update_mask = 0, wmmps_ac = 0; |
1798 | struct sta_info *psta_bmc; | |
c47bcff9 DC |
1799 | struct list_head *xmitframe_phead; |
1800 | struct xmit_frame *pxmitframe, *n; | |
d6846af6 LF |
1801 | struct sta_priv *pstapriv = &padapter->stapriv; |
1802 | ||
7057dcb3 | 1803 | spin_lock_bh(&psta->sleep_q.lock); |
d6846af6 LF |
1804 | |
1805 | xmitframe_phead = get_list_head(&psta->sleep_q); | |
c47bcff9 | 1806 | list_for_each_entry_safe(pxmitframe, n, xmitframe_phead, list) { |
8d5bdece | 1807 | list_del_init(&pxmitframe->list); |
d6846af6 LF |
1808 | |
1809 | switch (pxmitframe->attrib.priority) { | |
1810 | case 1: | |
1811 | case 2: | |
c89e9869 | 1812 | wmmps_ac = psta->uapsd_bk & BIT(1); |
d6846af6 LF |
1813 | break; |
1814 | case 4: | |
1815 | case 5: | |
c89e9869 | 1816 | wmmps_ac = psta->uapsd_vi & BIT(1); |
d6846af6 LF |
1817 | break; |
1818 | case 6: | |
1819 | case 7: | |
c89e9869 | 1820 | wmmps_ac = psta->uapsd_vo & BIT(1); |
d6846af6 LF |
1821 | break; |
1822 | case 0: | |
1823 | case 3: | |
1824 | default: | |
c89e9869 | 1825 | wmmps_ac = psta->uapsd_be & BIT(1); |
d6846af6 LF |
1826 | break; |
1827 | } | |
1828 | ||
1829 | psta->sleepq_len--; | |
1830 | if (psta->sleepq_len > 0) | |
1831 | pxmitframe->attrib.mdata = 1; | |
1832 | else | |
1833 | pxmitframe->attrib.mdata = 0; | |
1834 | ||
1835 | if (wmmps_ac) { | |
1836 | psta->sleepq_ac_len--; | |
1837 | if (psta->sleepq_ac_len > 0) { | |
1838 | pxmitframe->attrib.mdata = 1; | |
1839 | pxmitframe->attrib.eosp = 0; | |
1840 | } else { | |
1841 | pxmitframe->attrib.mdata = 0; | |
1842 | pxmitframe->attrib.eosp = 1; | |
1843 | } | |
1844 | } | |
1845 | ||
1846 | pxmitframe->attrib.triggered = 1; | |
1847 | ||
e02bcf61 | 1848 | spin_unlock_bh(&psta->sleep_q.lock); |
d6846af6 LF |
1849 | if (rtw_hal_xmit(padapter, pxmitframe)) |
1850 | rtw_os_xmit_complete(padapter, pxmitframe); | |
7057dcb3 | 1851 | spin_lock_bh(&psta->sleep_q.lock); |
d6846af6 LF |
1852 | } |
1853 | ||
1854 | if (psta->sleepq_len == 0) { | |
1855 | pstapriv->tim_bitmap &= ~BIT(psta->aid); | |
1856 | ||
1857 | update_mask = BIT(0); | |
1858 | ||
a66ecb24 | 1859 | if (psta->state & WIFI_SLEEP_STATE) |
d6846af6 LF |
1860 | psta->state ^= WIFI_SLEEP_STATE; |
1861 | ||
1862 | if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { | |
1863 | psta->expire_to = pstapriv->expire_to; | |
1864 | psta->state ^= WIFI_STA_ALIVE_CHK_STATE; | |
1865 | } | |
1866 | ||
1867 | pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); | |
1868 | } | |
1869 | ||
e02bcf61 | 1870 | spin_unlock_bh(&psta->sleep_q.lock); |
d6846af6 LF |
1871 | |
1872 | /* for BC/MC Frames */ | |
1873 | psta_bmc = rtw_get_bcmc_stainfo(padapter); | |
1874 | if (!psta_bmc) | |
1875 | return; | |
1876 | ||
a66ecb24 | 1877 | if ((pstapriv->sta_dz_bitmap & 0xfffe) == 0x0) { /* no any sta in ps mode */ |
7057dcb3 | 1878 | spin_lock_bh(&psta_bmc->sleep_q.lock); |
d6846af6 LF |
1879 | |
1880 | xmitframe_phead = get_list_head(&psta_bmc->sleep_q); | |
c47bcff9 | 1881 | list_for_each_entry_safe(pxmitframe, n, xmitframe_phead, list) { |
8d5bdece | 1882 | list_del_init(&pxmitframe->list); |
d6846af6 LF |
1883 | |
1884 | psta_bmc->sleepq_len--; | |
1885 | if (psta_bmc->sleepq_len > 0) | |
1886 | pxmitframe->attrib.mdata = 1; | |
1887 | else | |
1888 | pxmitframe->attrib.mdata = 0; | |
1889 | ||
1890 | pxmitframe->attrib.triggered = 1; | |
1891 | ||
e02bcf61 | 1892 | spin_unlock_bh(&psta_bmc->sleep_q.lock); |
d6846af6 LF |
1893 | if (rtw_hal_xmit(padapter, pxmitframe)) |
1894 | rtw_os_xmit_complete(padapter, pxmitframe); | |
7057dcb3 | 1895 | spin_lock_bh(&psta_bmc->sleep_q.lock); |
d6846af6 LF |
1896 | } |
1897 | ||
1898 | if (psta_bmc->sleepq_len == 0) { | |
1899 | pstapriv->tim_bitmap &= ~BIT(0); | |
1900 | pstapriv->sta_dz_bitmap &= ~BIT(0); | |
1901 | ||
1902 | update_mask |= BIT(1); | |
1903 | } | |
1904 | ||
e02bcf61 | 1905 | spin_unlock_bh(&psta_bmc->sleep_q.lock); |
d6846af6 LF |
1906 | } |
1907 | ||
1908 | if (update_mask) | |
75f1df26 | 1909 | update_beacon(padapter, WLAN_EID_TIM, NULL, false); |
d6846af6 LF |
1910 | } |
1911 | ||
1912 | void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta) | |
1913 | { | |
d6846af6 | 1914 | u8 wmmps_ac = 0; |
629132b3 DC |
1915 | struct list_head *xmitframe_phead; |
1916 | struct xmit_frame *pxmitframe, *n; | |
d6846af6 LF |
1917 | struct sta_priv *pstapriv = &padapter->stapriv; |
1918 | ||
7057dcb3 | 1919 | spin_lock_bh(&psta->sleep_q.lock); |
d6846af6 LF |
1920 | |
1921 | xmitframe_phead = get_list_head(&psta->sleep_q); | |
629132b3 | 1922 | list_for_each_entry_safe(pxmitframe, n, xmitframe_phead, list) { |
d6846af6 LF |
1923 | switch (pxmitframe->attrib.priority) { |
1924 | case 1: | |
1925 | case 2: | |
c89e9869 | 1926 | wmmps_ac = psta->uapsd_bk & BIT(1); |
d6846af6 LF |
1927 | break; |
1928 | case 4: | |
1929 | case 5: | |
c89e9869 | 1930 | wmmps_ac = psta->uapsd_vi & BIT(1); |
d6846af6 LF |
1931 | break; |
1932 | case 6: | |
1933 | case 7: | |
c89e9869 | 1934 | wmmps_ac = psta->uapsd_vo & BIT(1); |
d6846af6 LF |
1935 | break; |
1936 | case 0: | |
1937 | case 3: | |
1938 | default: | |
c89e9869 | 1939 | wmmps_ac = psta->uapsd_be & BIT(1); |
d6846af6 LF |
1940 | break; |
1941 | } | |
1942 | ||
1943 | if (!wmmps_ac) | |
1944 | continue; | |
1945 | ||
8d5bdece | 1946 | list_del_init(&pxmitframe->list); |
d6846af6 LF |
1947 | |
1948 | psta->sleepq_len--; | |
1949 | psta->sleepq_ac_len--; | |
1950 | ||
1951 | if (psta->sleepq_ac_len > 0) { | |
1952 | pxmitframe->attrib.mdata = 1; | |
1953 | pxmitframe->attrib.eosp = 0; | |
1954 | } else { | |
1955 | pxmitframe->attrib.mdata = 0; | |
1956 | pxmitframe->attrib.eosp = 1; | |
1957 | } | |
1958 | ||
1959 | pxmitframe->attrib.triggered = 1; | |
1960 | ||
3f95106e | 1961 | if (rtw_hal_xmit(padapter, pxmitframe)) |
d6846af6 LF |
1962 | rtw_os_xmit_complete(padapter, pxmitframe); |
1963 | ||
1964 | if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && (wmmps_ac)) { | |
1965 | pstapriv->tim_bitmap &= ~BIT(psta->aid); | |
1966 | ||
40a46d8b | 1967 | /* update BCN for TIM IE */ |
75f1df26 | 1968 | update_beacon(padapter, WLAN_EID_TIM, NULL, false); |
d6846af6 LF |
1969 | } |
1970 | } | |
1971 | ||
e02bcf61 | 1972 | spin_unlock_bh(&psta->sleep_q.lock); |
d6846af6 LF |
1973 | } |
1974 | ||
1975 | #endif | |
1976 | ||
1977 | void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms) | |
1978 | { | |
1979 | sctx->timeout_ms = timeout_ms; | |
c01fb496 | 1980 | sctx->submit_time = jiffies; |
d6846af6 LF |
1981 | init_completion(&sctx->done); |
1982 | sctx->status = RTW_SCTX_SUBMITTED; | |
1983 | } | |
1984 | ||
1985 | int rtw_sctx_wait(struct submit_ctx *sctx) | |
1986 | { | |
1987 | int ret = _FAIL; | |
1988 | unsigned long expire; | |
1989 | int status = 0; | |
1990 | ||
1991 | expire = sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) : MAX_SCHEDULE_TIMEOUT; | |
1992 | if (!wait_for_completion_timeout(&sctx->done, expire)) { | |
1993 | /* timeout, do something?? */ | |
1994 | status = RTW_SCTX_DONE_TIMEOUT; | |
1995 | DBG_88E("%s timeout\n", __func__); | |
1996 | } else { | |
1997 | status = sctx->status; | |
1998 | } | |
1999 | ||
2000 | if (status == RTW_SCTX_DONE_SUCCESS) | |
2001 | ret = _SUCCESS; | |
2002 | ||
2003 | return ret; | |
2004 | } | |
2005 | ||
f549a60b | 2006 | static bool rtw_sctx_chk_warning_status(int status) |
d6846af6 LF |
2007 | { |
2008 | switch (status) { | |
2009 | case RTW_SCTX_DONE_UNKNOWN: | |
2010 | case RTW_SCTX_DONE_BUF_ALLOC: | |
2011 | case RTW_SCTX_DONE_BUF_FREE: | |
2012 | ||
2013 | case RTW_SCTX_DONE_DRV_STOP: | |
2014 | case RTW_SCTX_DONE_DEV_REMOVE: | |
2015 | return true; | |
2016 | default: | |
2017 | return false; | |
2018 | } | |
2019 | } | |
2020 | ||
2021 | void rtw_sctx_done_err(struct submit_ctx **sctx, int status) | |
2022 | { | |
2023 | if (*sctx) { | |
f549a60b | 2024 | if (rtw_sctx_chk_warning_status(status)) |
d6846af6 LF |
2025 | DBG_88E("%s status:%d\n", __func__, status); |
2026 | (*sctx)->status = status; | |
2027 | complete(&((*sctx)->done)); | |
2028 | *sctx = NULL; | |
2029 | } | |
2030 | } | |
2031 | ||
d6846af6 LF |
2032 | int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms) |
2033 | { | |
2034 | struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; | |
2035 | ||
c01fb496 | 2036 | pack_tx_ops->submit_time = jiffies; |
d6846af6 LF |
2037 | pack_tx_ops->timeout_ms = timeout_ms; |
2038 | pack_tx_ops->status = RTW_SCTX_SUBMITTED; | |
2039 | ||
2040 | return rtw_sctx_wait(pack_tx_ops); | |
2041 | } | |
2042 | ||
2043 | void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status) | |
2044 | { | |
2045 | struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; | |
2046 | ||
2047 | if (pxmitpriv->ack_tx) | |
2048 | rtw_sctx_done_err(&pack_tx_ops, status); | |
2049 | else | |
2050 | DBG_88E("%s ack_tx not set\n", __func__); | |
2051 | } |