blob: 7a5e6bf0d1ae4202aaf794d0e78a3c49ef24b208 [file] [log] [blame]
Larry Finger5e93f352014-03-28 21:37:38 -05001/******************************************************************************
2 *
3 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 ******************************************************************************/
15#define _RTW_XMIT_C_
16
17#include <osdep_service.h>
18#include <drv_types.h>
19#include <wifi.h>
20#include <osdep_intf.h>
21#include <linux/ip.h>
22#include <usb_ops.h>
Jes Sorensen638443d2014-05-16 10:04:18 +020023#include <rtl8723a_xmit.h>
Larry Finger5e93f352014-03-28 21:37:38 -050024
Larry Finger5e93f352014-03-28 21:37:38 -050025static void _init_txservq(struct tx_servq *ptxservq)
26{
27
28 INIT_LIST_HEAD(&ptxservq->tx_pending);
29 _rtw_init_queue23a(&ptxservq->sta_pending);
30 ptxservq->qcnt = 0;
31
32}
33
34void _rtw_init_sta_xmit_priv23a(struct sta_xmit_priv *psta_xmitpriv)
35{
36
37 spin_lock_init(&psta_xmitpriv->lock);
38
39 /* for (i = 0 ; i < MAX_NUMBLKS; i++) */
40 /* _init_txservq(&psta_xmitpriv->blk_q[i]); */
41
42 _init_txservq(&psta_xmitpriv->be_q);
43 _init_txservq(&psta_xmitpriv->bk_q);
44 _init_txservq(&psta_xmitpriv->vi_q);
45 _init_txservq(&psta_xmitpriv->vo_q);
46 INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz);
47 INIT_LIST_HEAD(&psta_xmitpriv->apsd);
48
49}
50
Jes Sorensen269746a2014-05-09 15:03:54 +020051int _rtw_init_xmit_priv23a(struct xmit_priv *pxmitpriv,
52 struct rtw_adapter *padapter)
Larry Finger5e93f352014-03-28 21:37:38 -050053{
54 int i;
55 struct xmit_buf *pxmitbuf;
56 struct xmit_frame *pxframe;
Jes Sorensen269746a2014-05-09 15:03:54 +020057 int res = _SUCCESS;
Larry Finger5e93f352014-03-28 21:37:38 -050058 u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
59 u32 num_xmit_extbuf = NR_XMIT_EXTBUFF;
60
Larry Finger5e93f352014-03-28 21:37:38 -050061 spin_lock_init(&pxmitpriv->lock);
62 spin_lock_init(&pxmitpriv->lock_sctx);
63 sema_init(&pxmitpriv->xmit_sema, 0);
64 sema_init(&pxmitpriv->terminate_xmitthread_sema, 0);
65
Larry Finger5e93f352014-03-28 21:37:38 -050066 pxmitpriv->adapter = padapter;
67
68 _rtw_init_queue23a(&pxmitpriv->be_pending);
69 _rtw_init_queue23a(&pxmitpriv->bk_pending);
70 _rtw_init_queue23a(&pxmitpriv->vi_pending);
71 _rtw_init_queue23a(&pxmitpriv->vo_pending);
72 _rtw_init_queue23a(&pxmitpriv->bm_pending);
73
74 _rtw_init_queue23a(&pxmitpriv->free_xmit_queue);
75
Larry Finger5e93f352014-03-28 21:37:38 -050076 for (i = 0; i < NR_XMITFRAME; i++) {
Sachin Kamat4947f5e2014-05-28 17:36:28 +053077 pxframe = kzalloc(sizeof(struct xmit_frame), GFP_KERNEL);
Jes Sorensen251ccc22014-05-09 15:03:52 +020078 if (!pxframe)
79 break;
Larry Finger5e93f352014-03-28 21:37:38 -050080 INIT_LIST_HEAD(&pxframe->list);
81
82 pxframe->padapter = padapter;
83 pxframe->frame_tag = NULL_FRAMETAG;
84
Larry Finger5e93f352014-03-28 21:37:38 -050085 list_add_tail(&pxframe->list,
86 &pxmitpriv->free_xmit_queue.queue);
Larry Finger5e93f352014-03-28 21:37:38 -050087 }
88
Jes Sorensen251ccc22014-05-09 15:03:52 +020089 pxmitpriv->free_xmitframe_cnt = i;
Larry Finger5e93f352014-03-28 21:37:38 -050090
91 pxmitpriv->frag_len = MAX_FRAG_THRESHOLD;
92
93 /* init xmit_buf */
94 _rtw_init_queue23a(&pxmitpriv->free_xmitbuf_queue);
95 INIT_LIST_HEAD(&pxmitpriv->xmitbuf_list);
96 _rtw_init_queue23a(&pxmitpriv->pending_xmitbuf_queue);
97
98 for (i = 0; i < NR_XMITBUFF; i++) {
99 pxmitbuf = kzalloc(sizeof(struct xmit_buf), GFP_KERNEL);
100 if (!pxmitbuf)
101 goto fail;
102 INIT_LIST_HEAD(&pxmitbuf->list);
103 INIT_LIST_HEAD(&pxmitbuf->list2);
104
105 pxmitbuf->padapter = padapter;
106
107 /* Tx buf allocation may fail sometimes, so sleep and retry. */
108 res = rtw_os_xmit_resource_alloc23a(padapter, pxmitbuf,
109 (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ));
110 if (res == _FAIL) {
111 goto fail;
112 }
113
114 list_add_tail(&pxmitbuf->list,
115 &pxmitpriv->free_xmitbuf_queue.queue);
116 list_add_tail(&pxmitbuf->list2,
117 &pxmitpriv->xmitbuf_list);
118 }
119
120 pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF;
121
122 /* init xframe_ext queue, the same count as extbuf */
123 _rtw_init_queue23a(&pxmitpriv->free_xframe_ext_queue);
124
Larry Finger5e93f352014-03-28 21:37:38 -0500125 for (i = 0; i < num_xmit_extbuf; i++) {
Sachin Kamat4947f5e2014-05-28 17:36:28 +0530126 pxframe = kzalloc(sizeof(struct xmit_frame), GFP_KERNEL);
Jes Sorensen3a350582014-05-09 15:03:53 +0200127 if (!pxframe)
128 break;
Larry Finger5e93f352014-03-28 21:37:38 -0500129 INIT_LIST_HEAD(&pxframe->list);
130
131 pxframe->padapter = padapter;
132 pxframe->frame_tag = NULL_FRAMETAG;
133
134 pxframe->pkt = NULL;
135
136 pxframe->buf_addr = NULL;
137 pxframe->pxmitbuf = NULL;
138
139 pxframe->ext_tag = 1;
140
141 list_add_tail(&pxframe->list,
142 &pxmitpriv->free_xframe_ext_queue.queue);
Larry Finger5e93f352014-03-28 21:37:38 -0500143 }
Jes Sorensen3a350582014-05-09 15:03:53 +0200144 pxmitpriv->free_xframe_ext_cnt = i;
Larry Finger5e93f352014-03-28 21:37:38 -0500145
146 /* Init xmit extension buff */
147 _rtw_init_queue23a(&pxmitpriv->free_xmit_extbuf_queue);
148 INIT_LIST_HEAD(&pxmitpriv->xmitextbuf_list);
149
150 for (i = 0; i < num_xmit_extbuf; i++) {
151 pxmitbuf = kzalloc(sizeof(struct xmit_buf), GFP_KERNEL);
152 if (!pxmitbuf)
153 goto fail;
154 INIT_LIST_HEAD(&pxmitbuf->list);
155 INIT_LIST_HEAD(&pxmitbuf->list2);
156
157 pxmitbuf->padapter = padapter;
158
159 /* Tx buf allocation may fail sometimes, so sleep and retry. */
160 res = rtw_os_xmit_resource_alloc23a(padapter, pxmitbuf,
161 max_xmit_extbuf_size + XMITBUF_ALIGN_SZ);
162 if (res == _FAIL) {
163 goto exit;
164 }
165
166 list_add_tail(&pxmitbuf->list,
167 &pxmitpriv->free_xmit_extbuf_queue.queue);
168 list_add_tail(&pxmitbuf->list2,
169 &pxmitpriv->xmitextbuf_list);
170 }
171
172 pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf;
173
174 rtw_alloc_hwxmits23a(padapter);
175 rtw_init_hwxmits23a(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
176
177 for (i = 0; i < 4; i ++)
178 pxmitpriv->wmm_para_seq[i] = i;
179
Larry Finger5e93f352014-03-28 21:37:38 -0500180 sema_init(&pxmitpriv->tx_retevt, 0);
181
Larry Finger5e93f352014-03-28 21:37:38 -0500182 pxmitpriv->ack_tx = false;
183 mutex_init(&pxmitpriv->ack_tx_mutex);
184 rtw_sctx_init23a(&pxmitpriv->ack_tx_ops, 0);
Jes Sorensenb3d139a2014-05-16 10:04:17 +0200185 tasklet_init(&padapter->xmitpriv.xmit_tasklet,
186 (void(*)(unsigned long))rtl8723au_xmit_tasklet,
187 (unsigned long)padapter);
Larry Finger5e93f352014-03-28 21:37:38 -0500188
189exit:
190
191 return res;
192fail:
193 goto exit;
194}
195
196void _rtw_free_xmit_priv23a (struct xmit_priv *pxmitpriv)
197{
198 struct rtw_adapter *padapter = pxmitpriv->adapter;
Jes Sorensen251ccc22014-05-09 15:03:52 +0200199 struct xmit_frame *pxframe;
Larry Finger5e93f352014-03-28 21:37:38 -0500200 struct xmit_buf *pxmitbuf;
201 struct list_head *plist, *ptmp;
Larry Finger5e93f352014-03-28 21:37:38 -0500202
Jes Sorensen251ccc22014-05-09 15:03:52 +0200203 list_for_each_safe(plist, ptmp, &pxmitpriv->free_xmit_queue.queue) {
204 pxframe = container_of(plist, struct xmit_frame, list);
205 list_del_init(&pxframe->list);
206 rtw_os_xmit_complete23a(padapter, pxframe);
207 kfree(pxframe);
Larry Finger5e93f352014-03-28 21:37:38 -0500208 }
209
210 list_for_each_safe(plist, ptmp, &pxmitpriv->xmitbuf_list) {
211 pxmitbuf = container_of(plist, struct xmit_buf, list2);
212 list_del_init(&pxmitbuf->list2);
213 rtw_os_xmit_resource_free23a(padapter, pxmitbuf);
214 kfree(pxmitbuf);
215 }
216
Larry Finger5e93f352014-03-28 21:37:38 -0500217 /* free xframe_ext queue, the same count as extbuf */
Jes Sorensen3a350582014-05-09 15:03:53 +0200218 list_for_each_safe(plist, ptmp,
219 &pxmitpriv->free_xframe_ext_queue.queue) {
220 pxframe = container_of(plist, struct xmit_frame, list);
221 list_del_init(&pxframe->list);
222 rtw_os_xmit_complete23a(padapter, pxframe);
223 kfree(pxframe);
Larry Finger5e93f352014-03-28 21:37:38 -0500224 }
Larry Finger5e93f352014-03-28 21:37:38 -0500225
226 /* free xmit extension buff */
227 list_for_each_safe(plist, ptmp, &pxmitpriv->xmitextbuf_list) {
228 pxmitbuf = container_of(plist, struct xmit_buf, list2);
229 list_del_init(&pxmitbuf->list2);
230 rtw_os_xmit_resource_free23a(padapter, pxmitbuf);
231 kfree(pxmitbuf);
232 }
233
234 rtw_free_hwxmits23a(padapter);
235 mutex_destroy(&pxmitpriv->ack_tx_mutex);
236}
237
238static void update_attrib_vcs_info(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
239{
240 u32 sz;
241 struct pkt_attrib *pattrib = &pxmitframe->attrib;
242 struct sta_info *psta = pattrib->psta;
243 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
244 struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
245
Greg Donalda82b4b02014-09-08 20:50:23 -0500246 if (pattrib->psta) {
Larry Finger5e93f352014-03-28 21:37:38 -0500247 psta = pattrib->psta;
248 } else {
249 DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
250 psta = rtw_get_stainfo23a(&padapter->stapriv, &pattrib->ra[0]);
251 }
252
Greg Donalda82b4b02014-09-08 20:50:23 -0500253 if (psta == NULL) {
Larry Finger5e93f352014-03-28 21:37:38 -0500254 DBG_8723A("%s, psta == NUL\n", __func__);
255 return;
256 }
257
258 if (!(psta->state &_FW_LINKED)) {
259 DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state);
260 return;
261 }
262
263 if (pattrib->nr_frags != 1)
264 sz = padapter->xmitpriv.frag_len;
265 else /* no frag */
266 sz = pattrib->last_txcmdsz;
267
268 /* (1) RTS_Threshold is compared to the MPDU, not MSDU. */
269 /* (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. */
270 /* Other fragments are protected by previous fragment. */
271 /* So we only need to check the length of first fragment. */
272 if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) {
273 if (sz > padapter->registrypriv.rts_thresh) {
274 pattrib->vcs_mode = RTS_CTS;
275 } else {
276 if (psta->rtsen)
277 pattrib->vcs_mode = RTS_CTS;
278 else if (psta->cts2self)
279 pattrib->vcs_mode = CTS_TO_SELF;
280 else
281 pattrib->vcs_mode = NONE_VCS;
282 }
283 } else {
284 while (true) {
285 /* IOT action */
Jes Sorensen9e3d6df2014-05-21 09:37:34 +0200286 if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS &&
287 pattrib->ampdu_en &&
288 padapter->securitypriv.dot11PrivacyAlgrthm ==
289 WLAN_CIPHER_SUITE_CCMP) {
Larry Finger5e93f352014-03-28 21:37:38 -0500290 pattrib->vcs_mode = CTS_TO_SELF;
291 break;
292 }
293
294 /* check ERP protection */
295 if (psta->rtsen || psta->cts2self) {
296 if (psta->rtsen)
297 pattrib->vcs_mode = RTS_CTS;
298 else if (psta->cts2self)
299 pattrib->vcs_mode = CTS_TO_SELF;
300
301 break;
302 }
303
304 /* check HT op mode */
305 if (pattrib->ht_en) {
306 u8 HTOpMode = pmlmeinfo->HT_protection;
Yeliz Taneroglub8576412014-10-09 01:22:19 +0300307
Larry Finger5e93f352014-03-28 21:37:38 -0500308 if ((pmlmeext->cur_bwmode && (HTOpMode == 2 || HTOpMode == 3)) ||
309 (!pmlmeext->cur_bwmode && HTOpMode == 3)) {
310 pattrib->vcs_mode = RTS_CTS;
311 break;
312 }
313 }
314
315 /* check rts */
316 if (sz > padapter->registrypriv.rts_thresh) {
317 pattrib->vcs_mode = RTS_CTS;
318 break;
319 }
320
321 /* to do list: check MIMO power save condition. */
322
323 /* check AMPDU aggregation for TXOP */
324 if (pattrib->ampdu_en) {
325 pattrib->vcs_mode = RTS_CTS;
326 break;
327 }
328
329 pattrib->vcs_mode = NONE_VCS;
330 break;
331 }
332 }
333}
334
335static void update_attrib_phy_info(struct pkt_attrib *pattrib, struct sta_info *psta)
336{
337 /*if (psta->rtsen)
338 pattrib->vcs_mode = RTS_CTS;
339 else if (psta->cts2self)
340 pattrib->vcs_mode = CTS_TO_SELF;
341 else
342 pattrib->vcs_mode = NONE_VCS;*/
343
344 pattrib->mdata = 0;
345 pattrib->eosp = 0;
346 pattrib->triggered = 0;
347
348 /* qos_en, ht_en, init rate, , bw, ch_offset, sgi */
349 pattrib->qos_en = psta->qos_option;
350
351 pattrib->raid = psta->raid;
352 pattrib->ht_en = psta->htpriv.ht_option;
353 pattrib->bwmode = psta->htpriv.bwmode;
354 pattrib->ch_offset = psta->htpriv.ch_offset;
355 pattrib->sgi = psta->htpriv.sgi;
356 pattrib->ampdu_en = false;
357
358 pattrib->retry_ctrl = false;
359}
360
361u8 qos_acm23a(u8 acm_mask, u8 priority)
362{
363 u8 change_priority = priority;
364
365 switch (priority) {
366 case 0:
367 case 3:
368 if (acm_mask & BIT(1))
369 change_priority = 1;
370 break;
371 case 1:
372 case 2:
373 break;
374 case 4:
375 case 5:
376 if (acm_mask & BIT(2))
377 change_priority = 0;
378 break;
379 case 6:
380 case 7:
381 if (acm_mask & BIT(3))
382 change_priority = 5;
383 break;
384 default:
385 DBG_8723A("qos_acm23a(): invalid pattrib->priority: %d!!!\n",
386 priority);
Jes Sorensen78558482014-05-09 15:04:19 +0200387 change_priority = 0;
Larry Finger5e93f352014-03-28 21:37:38 -0500388 break;
389 }
390
391 return change_priority;
392}
393
Jes Sorensene59cb422014-04-09 23:21:10 +0200394static void set_qos(struct sk_buff *skb, struct pkt_attrib *pattrib)
Larry Finger5e93f352014-03-28 21:37:38 -0500395{
Jes Sorensene59cb422014-04-09 23:21:10 +0200396 u8 *pframe = skb->data;
397 struct iphdr *ip_hdr;
Jes Sorensenc06209d2014-05-09 15:04:18 +0200398 u8 UserPriority = 0;
Larry Finger5e93f352014-03-28 21:37:38 -0500399
Larry Finger5e93f352014-03-28 21:37:38 -0500400 /* get UserPriority from IP hdr */
Jes Sorensen3483b8a2014-04-09 23:21:09 +0200401 if (pattrib->ether_type == ETH_P_IP) {
Jes Sorensene59cb422014-04-09 23:21:10 +0200402 ip_hdr = (struct iphdr *)(pframe + ETH_HLEN);
403 UserPriority = ip_hdr->tos >> 5;
Jes Sorensen3483b8a2014-04-09 23:21:09 +0200404 } else if (pattrib->ether_type == ETH_P_PAE) {
Larry Finger5e93f352014-03-28 21:37:38 -0500405 /* "When priority processing of data frames is supported, */
406 /* a STA's SME should send EAPOL-Key frames at the highest
407 priority." */
408 UserPriority = 7;
409 }
410
411 pattrib->priority = UserPriority;
412 pattrib->hdrlen = sizeof(struct ieee80211_qos_hdr);
Jes Sorensenb2f72ca2014-05-21 09:38:09 +0200413 pattrib->type = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA;
Larry Finger5e93f352014-03-28 21:37:38 -0500414}
415
Jes Sorensen8fd873d2014-05-16 10:04:40 +0200416static int update_attrib(struct rtw_adapter *padapter,
Jes Sorensene59cb422014-04-09 23:21:10 +0200417 struct sk_buff *skb, struct pkt_attrib *pattrib)
Larry Finger5e93f352014-03-28 21:37:38 -0500418{
Larry Finger5e93f352014-03-28 21:37:38 -0500419 struct sta_info *psta = NULL;
Larry Finger5e93f352014-03-28 21:37:38 -0500420 int bmcast;
421 struct sta_priv *pstapriv = &padapter->stapriv;
422 struct security_priv *psecuritypriv = &padapter->securitypriv;
423 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
Larry Finger5e93f352014-03-28 21:37:38 -0500424 int res = _SUCCESS;
Jes Sorensene59cb422014-04-09 23:21:10 +0200425 struct ethhdr *ehdr = (struct ethhdr *) skb->data;
Larry Finger5e93f352014-03-28 21:37:38 -0500426
Jes Sorensene59cb422014-04-09 23:21:10 +0200427 pattrib->ether_type = ntohs(ehdr->h_proto);
Larry Finger5e93f352014-03-28 21:37:38 -0500428
Jes Sorensene59cb422014-04-09 23:21:10 +0200429 ether_addr_copy(pattrib->dst, ehdr->h_dest);
430 ether_addr_copy(pattrib->src, ehdr->h_source);
Larry Finger5e93f352014-03-28 21:37:38 -0500431
432 pattrib->pctrl = 0;
433
Jes Sorensenf2f97032014-05-25 22:43:04 +0200434 if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
435 check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
Jes Sorensene59cb422014-04-09 23:21:10 +0200436 ether_addr_copy(pattrib->ra, pattrib->dst);
437 ether_addr_copy(pattrib->ta, pattrib->src);
Jes Sorensenf2f97032014-05-25 22:43:04 +0200438 } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
Jes Sorensene59cb422014-04-09 23:21:10 +0200439 ether_addr_copy(pattrib->ra, get_bssid(pmlmepriv));
440 ether_addr_copy(pattrib->ta, pattrib->src);
Jes Sorensenf2f97032014-05-25 22:43:04 +0200441 } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
Jes Sorensene59cb422014-04-09 23:21:10 +0200442 ether_addr_copy(pattrib->ra, pattrib->dst);
443 ether_addr_copy(pattrib->ta, get_bssid(pmlmepriv));
Larry Finger5e93f352014-03-28 21:37:38 -0500444 }
445
Jes Sorensene59cb422014-04-09 23:21:10 +0200446 pattrib->pktlen = skb->len - ETH_HLEN;
Larry Finger5e93f352014-03-28 21:37:38 -0500447
448 if (pattrib->ether_type == ETH_P_IP) {
449 /* The following is for DHCP and ARP packet, we use cck1M
450 to tx these packets and let LPS awake some time */
451 /* to prevent DHCP protocol fail */
Larry Finger5e93f352014-03-28 21:37:38 -0500452 pattrib->dhcp_pkt = 0;
Jes Sorensene59cb422014-04-09 23:21:10 +0200453 /* MINIMUM_DHCP_PACKET_SIZE) { */
454 if (pattrib->pktlen > 282 + 24) {
Jes Sorensen3483b8a2014-04-09 23:21:09 +0200455 if (pattrib->ether_type == ETH_P_IP) {/* IP header */
Jes Sorensene59cb422014-04-09 23:21:10 +0200456 u8 *pframe = skb->data;
Yeliz Taneroglub8576412014-10-09 01:22:19 +0300457
Jes Sorensene59cb422014-04-09 23:21:10 +0200458 pframe += ETH_HLEN;
459
460 if ((pframe[21] == 68 && pframe[23] == 67) ||
461 (pframe[21] == 67 && pframe[23] == 68)) {
Larry Finger5e93f352014-03-28 21:37:38 -0500462 /* 68 : UDP BOOTP client */
463 /* 67 : UDP BOOTP server */
464 RT_TRACE(_module_rtl871x_xmit_c_,
465 _drv_err_,
466 ("======================"
467 "update_attrib: get DHCP "
468 "Packet\n"));
469 pattrib->dhcp_pkt = 1;
470 }
471 }
472 }
Jes Sorensen3483b8a2014-04-09 23:21:09 +0200473 } else if (pattrib->ether_type == ETH_P_PAE) {
Larry Finger5e93f352014-03-28 21:37:38 -0500474 DBG_8723A_LEVEL(_drv_always_, "send eapol packet\n");
475 }
476
Jes Sorensen3483b8a2014-04-09 23:21:09 +0200477 if ((pattrib->ether_type == ETH_P_PAE) || (pattrib->dhcp_pkt == 1)) {
Larry Finger5e93f352014-03-28 21:37:38 -0500478 rtw_set_scan_deny(padapter, 3000);
479 }
480
481 /* If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */
Jes Sorensen3483b8a2014-04-09 23:21:09 +0200482 if ((pattrib->ether_type == ETH_P_ARP) ||
483 (pattrib->ether_type == ETH_P_PAE) || (pattrib->dhcp_pkt == 1)) {
Larry Finger5e93f352014-03-28 21:37:38 -0500484 rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_SPECIAL_PACKET, 1);
485 }
486
487 bmcast = is_multicast_ether_addr(pattrib->ra);
488
489 /* get sta_info */
490 if (bmcast) {
491 psta = rtw_get_bcmc_stainfo23a(padapter);
492 } else {
493 psta = rtw_get_stainfo23a(pstapriv, pattrib->ra);
494 if (psta == NULL) { /* if we cannot get psta => drrp the pkt */
495 RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_,
496 ("\nupdate_attrib => get sta_info fail, ra:"
497 MAC_FMT"\n", MAC_ARG(pattrib->ra)));
498 res = _FAIL;
499 goto exit;
Jes Sorensenf2f97032014-05-25 22:43:04 +0200500 } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) &&
Larry Finger5e93f352014-03-28 21:37:38 -0500501 (!(psta->state & _FW_LINKED))) {
502 res = _FAIL;
503 goto exit;
504 }
505 }
506
507 if (psta) {
508 pattrib->mac_id = psta->mac_id;
509 /* DBG_8723A("%s ==> mac_id(%d)\n", __func__, pattrib->mac_id); */
510 pattrib->psta = psta;
511 } else {
512 /* if we cannot get psta => drop the pkt */
513 RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_,
514 ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT
515 "\n", MAC_ARG(pattrib->ra)));
516 res = _FAIL;
517 goto exit;
518 }
519
520 pattrib->ack_policy = 0;
521 /* get ether_hdr_len */
522
523 /* pattrib->ether_type == 0x8100) ? (14 + 4): 14; vlan tag */
524 pattrib->pkt_hdrlen = ETH_HLEN;
525
526 pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
Jes Sorensenb2f72ca2014-05-21 09:38:09 +0200527 pattrib->type = IEEE80211_FTYPE_DATA;
Larry Finger5e93f352014-03-28 21:37:38 -0500528 pattrib->priority = 0;
529
530 if (check_fwstate(pmlmepriv, WIFI_AP_STATE | WIFI_ADHOC_STATE |
531 WIFI_ADHOC_MASTER_STATE)) {
532 if (psta->qos_option)
Jes Sorensene59cb422014-04-09 23:21:10 +0200533 set_qos(skb, pattrib);
Larry Finger5e93f352014-03-28 21:37:38 -0500534 } else {
Jes Sorensenbd8ad4a2014-05-09 15:03:21 +0200535 if (pmlmepriv->qos_option) {
Jes Sorensene59cb422014-04-09 23:21:10 +0200536 set_qos(skb, pattrib);
Larry Finger5e93f352014-03-28 21:37:38 -0500537
538 if (pmlmepriv->acm_mask != 0) {
539 pattrib->priority = qos_acm23a(pmlmepriv->acm_mask,
540 pattrib->priority);
541 }
542 }
543 }
544
545 if (psta->ieee8021x_blocked == true) {
546 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
547 ("\n psta->ieee8021x_blocked == true\n"));
548
549 pattrib->encrypt = 0;
550
Jes Sorensen3483b8a2014-04-09 23:21:09 +0200551 if ((pattrib->ether_type != ETH_P_PAE) &&
Jes Sorensen0618dbc2014-05-25 22:43:06 +0200552 !check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
Larry Finger5e93f352014-03-28 21:37:38 -0500553 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
554 ("\npsta->ieee8021x_blocked == true, "
555 "pattrib->ether_type(%.4x) != 0x888e\n",
556 pattrib->ether_type));
557 res = _FAIL;
558 goto exit;
559 }
560 } else {
561 GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast);
562
563 switch (psecuritypriv->dot11AuthAlgrthm) {
564 case dot11AuthAlgrthm_Open:
565 case dot11AuthAlgrthm_Shared:
566 case dot11AuthAlgrthm_Auto:
567 pattrib->key_idx =
568 (u8)psecuritypriv->dot11PrivacyKeyIndex;
569 break;
570 case dot11AuthAlgrthm_8021X:
571 if (bmcast)
572 pattrib->key_idx =
573 (u8)psecuritypriv->dot118021XGrpKeyid;
574 else
575 pattrib->key_idx = 0;
576 break;
577 default:
578 pattrib->key_idx = 0;
579 break;
580 }
581
582 }
583
584 switch (pattrib->encrypt) {
Jes Sorensen9e3d6df2014-05-21 09:37:34 +0200585 case WLAN_CIPHER_SUITE_WEP40:
586 case WLAN_CIPHER_SUITE_WEP104:
Jes Sorensen06e17e32014-05-25 22:43:02 +0200587 pattrib->iv_len = IEEE80211_WEP_IV_LEN;
588 pattrib->icv_len = IEEE80211_WEP_ICV_LEN;
Larry Finger5e93f352014-03-28 21:37:38 -0500589 break;
590
Jes Sorensen9e3d6df2014-05-21 09:37:34 +0200591 case WLAN_CIPHER_SUITE_TKIP:
Jes Sorensen06e17e32014-05-25 22:43:02 +0200592 pattrib->iv_len = IEEE80211_TKIP_IV_LEN;
593 pattrib->icv_len = IEEE80211_TKIP_ICV_LEN;
Larry Finger5e93f352014-03-28 21:37:38 -0500594
Jes Sorensen9216c512014-05-21 09:37:29 +0200595 if (!padapter->securitypriv.busetkipkey) {
Larry Finger5e93f352014-03-28 21:37:38 -0500596 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
597 ("\npadapter->securitypriv.busetkip"
Jes Sorensen9216c512014-05-21 09:37:29 +0200598 "key(%d) == false drop packet\n",
Larry Finger5e93f352014-03-28 21:37:38 -0500599 padapter->securitypriv.busetkipkey));
600 res = _FAIL;
601 goto exit;
602 }
603
604 break;
Jes Sorensen9e3d6df2014-05-21 09:37:34 +0200605 case WLAN_CIPHER_SUITE_CCMP:
Larry Finger5e93f352014-03-28 21:37:38 -0500606 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
Jes Sorensen9e3d6df2014-05-21 09:37:34 +0200607 ("pattrib->encrypt =%d (WLAN_CIPHER_SUITE_CCMP)\n",
608 pattrib->encrypt));
Jes Sorensen06e17e32014-05-25 22:43:02 +0200609 pattrib->iv_len = IEEE80211_CCMP_HDR_LEN;
610 pattrib->icv_len = IEEE80211_CCMP_MIC_LEN;
Larry Finger5e93f352014-03-28 21:37:38 -0500611 break;
612
613 default:
614 pattrib->iv_len = 0;
615 pattrib->icv_len = 0;
616 break;
617 }
618
619 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
620 ("update_attrib: encrypt =%d\n", pattrib->encrypt));
621
Jes Sorensen9216c512014-05-21 09:37:29 +0200622 if (pattrib->encrypt && !psecuritypriv->hw_decrypted) {
Larry Finger5e93f352014-03-28 21:37:38 -0500623 pattrib->bswenc = true;
624 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
625 ("update_attrib: encrypt =%d bswenc = true\n",
626 pattrib->encrypt));
627 } else {
628 pattrib->bswenc = false;
629 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
630 ("update_attrib: bswenc = false\n"));
631 }
632 update_attrib_phy_info(pattrib, psta);
633
634exit:
635
636 return res;
637}
638
Jes Sorensen8fd873d2014-05-16 10:04:40 +0200639static int xmitframe_addmic(struct rtw_adapter *padapter,
Larry Finger5e93f352014-03-28 21:37:38 -0500640 struct xmit_frame *pxmitframe) {
641 struct mic_data micdata;
642 struct sta_info *stainfo;
643 struct pkt_attrib *pattrib = &pxmitframe->attrib;
644 struct security_priv *psecuritypriv = &padapter->securitypriv;
645 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
646 int curfragnum, length;
647 u8 *pframe, *payload, mic[8];
648 u8 priority[4]= {0x0, 0x0, 0x0, 0x0};
649 u8 hw_hdr_offset = 0;
650 int bmcst = is_multicast_ether_addr(pattrib->ra);
651
652 if (pattrib->psta) {
653 stainfo = pattrib->psta;
654 } else {
655 DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
656 stainfo = rtw_get_stainfo23a(&padapter->stapriv, &pattrib->ra[0]);
657 }
658
659 if (!stainfo) {
660 DBG_8723A("%s, psta == NUL\n", __func__);
661 return _FAIL;
662 }
663
664 if (!(stainfo->state &_FW_LINKED)) {
665 DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n",
666 __func__, stainfo->state);
667 return _FAIL;
668 }
669
670 hw_hdr_offset = TXDESC_OFFSET;
671
Jes Sorensen9e3d6df2014-05-21 09:37:34 +0200672 if (pattrib->encrypt == WLAN_CIPHER_SUITE_TKIP) {
Larry Finger5e93f352014-03-28 21:37:38 -0500673 /* encode mic code */
674 if (stainfo) {
675 u8 null_key[16]={0x0, 0x0, 0x0, 0x0,
676 0x0, 0x0, 0x0, 0x0,
677 0x0, 0x0, 0x0, 0x0,
678 0x0, 0x0, 0x0, 0x0};
679
680 pframe = pxmitframe->buf_addr + hw_hdr_offset;
681
682 if (bmcst) {
683 if (!memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16)) {
684 return _FAIL;
685 }
686 /* start to calculate the mic code */
687 rtw_secmicsetkey23a(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey);
688 } else {
689 if (!memcmp(&stainfo->dot11tkiptxmickey.skey[0],
690 null_key, 16)) {
691 return _FAIL;
692 }
693 /* start to calculate the mic code */
694 rtw_secmicsetkey23a(&micdata, &stainfo->dot11tkiptxmickey.skey[0]);
695 }
696
697 if (pframe[1] & 1) { /* ToDS == 1 */
698 /* DA */
699 rtw_secmicappend23a(&micdata, &pframe[16], 6);
700 if (pframe[1] & 2) /* From Ds == 1 */
701 rtw_secmicappend23a(&micdata,
702 &pframe[24], 6);
703 else
704 rtw_secmicappend23a(&micdata,
705 &pframe[10], 6);
706 } else { /* ToDS == 0 */
707 /* DA */
708 rtw_secmicappend23a(&micdata, &pframe[4], 6);
709 if (pframe[1] & 2) /* From Ds == 1 */
710 rtw_secmicappend23a(&micdata,
711 &pframe[16], 6);
712 else
713 rtw_secmicappend23a(&micdata,
714 &pframe[10], 6);
715 }
716
Jes Sorensenbd8ad4a2014-05-09 15:03:21 +0200717 /* if (pmlmepriv->qos_option == 1) */
Larry Finger5e93f352014-03-28 21:37:38 -0500718 if (pattrib->qos_en)
719 priority[0] = (u8)pxmitframe->attrib.priority;
720
721 rtw_secmicappend23a(&micdata, &priority[0], 4);
722
723 payload = pframe;
724
725 for (curfragnum = 0; curfragnum < pattrib->nr_frags;
726 curfragnum++) {
Larry Fingerc17416e2014-03-28 21:37:42 -0500727 payload = PTR_ALIGN(payload, 4);
Larry Finger5e93f352014-03-28 21:37:38 -0500728 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
729 ("=== curfragnum =%d, pframe = 0x%.2x, "
730 "0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x"
731 "%.2x, 0x%.2x, 0x%.2x,!!!\n",
732 curfragnum, *payload, *(payload + 1),
733 *(payload + 2), *(payload + 3),
734 *(payload + 4), *(payload + 5),
735 *(payload + 6), *(payload + 7)));
736
737 payload = payload + pattrib->hdrlen +
738 pattrib->iv_len;
739 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
740 ("curfragnum =%d pattrib->hdrlen =%d "
741 "pattrib->iv_len =%d", curfragnum,
742 pattrib->hdrlen, pattrib->iv_len));
743 if ((curfragnum + 1) == pattrib->nr_frags) {
744 length = pattrib->last_txcmdsz -
745 pattrib->hdrlen -
746 pattrib->iv_len -
747 ((pattrib->bswenc) ?
748 pattrib->icv_len : 0);
749 rtw_secmicappend23a(&micdata, payload,
750 length);
751 payload = payload + length;
752 } else {
753 length = pxmitpriv->frag_len -
754 pattrib->hdrlen -
755 pattrib->iv_len -
756 ((pattrib->bswenc) ?
757 pattrib->icv_len : 0);
758 rtw_secmicappend23a(&micdata, payload,
759 length);
760 payload = payload + length +
761 pattrib->icv_len;
762 RT_TRACE(_module_rtl871x_xmit_c_,
763 _drv_err_,
764 ("curfragnum =%d length =%d "
765 "pattrib->icv_len =%d",
766 curfragnum, length,
767 pattrib->icv_len));
768 }
769 }
770 rtw_secgetmic23a(&micdata, &mic[0]);
771 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
772 ("xmitframe_addmic: before add mic code!!\n"));
773 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
774 ("xmitframe_addmic: pattrib->last_txcmdsz ="
775 "%d!!!\n", pattrib->last_txcmdsz));
776 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
777 ("xmitframe_addmic: mic[0]= 0x%.2x , mic[1]="
778 "0x%.2x , mic[2]= 0x%.2x , mic[3]= 0x%.2x\n"
779 "mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x "
780 ", mic[7]= 0x%.2x !!!!\n", mic[0], mic[1],
781 mic[2], mic[3], mic[4], mic[5], mic[6],
782 mic[7]));
783 /* add mic code and add the mic code length
784 in last_txcmdsz */
785
786 memcpy(payload, &mic[0], 8);
787 pattrib->last_txcmdsz += 8;
788
789 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
790 ("\n ======== last pkt ========\n"));
791 payload = payload - pattrib->last_txcmdsz + 8;
792 for (curfragnum = 0; curfragnum < pattrib->last_txcmdsz;
793 curfragnum = curfragnum + 8)
794 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
795 (" %.2x, %.2x, %.2x, %.2x, %.2x, "
796 " %.2x, %.2x, %.2x ",
797 *(payload + curfragnum),
798 *(payload + curfragnum + 1),
799 *(payload + curfragnum + 2),
800 *(payload + curfragnum + 3),
801 *(payload + curfragnum + 4),
802 *(payload + curfragnum + 5),
803 *(payload + curfragnum + 6),
804 *(payload + curfragnum + 7)));
805 } else {
806 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
807 ("xmitframe_addmic: rtw_get_stainfo23a =="
808 "NULL!!!\n"));
809 }
810 }
811
812 return _SUCCESS;
813}
814
Jes Sorensen8fd873d2014-05-16 10:04:40 +0200815static int xmitframe_swencrypt(struct rtw_adapter *padapter,
Larry Finger5e93f352014-03-28 21:37:38 -0500816 struct xmit_frame *pxmitframe)
817{
818 struct pkt_attrib *pattrib = &pxmitframe->attrib;
819
820 /* if ((psecuritypriv->sw_encrypt)||(pattrib->bswenc)) */
821 if (pattrib->bswenc) {
822 /* DBG_8723A("start xmitframe_swencrypt\n"); */
823 RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_,
824 ("### xmitframe_swencrypt\n"));
825 switch (pattrib->encrypt) {
Jes Sorensen9e3d6df2014-05-21 09:37:34 +0200826 case WLAN_CIPHER_SUITE_WEP40:
827 case WLAN_CIPHER_SUITE_WEP104:
Larry Finger5e93f352014-03-28 21:37:38 -0500828 rtw_wep_encrypt23a(padapter, pxmitframe);
829 break;
Jes Sorensen9e3d6df2014-05-21 09:37:34 +0200830 case WLAN_CIPHER_SUITE_TKIP:
Larry Finger5e93f352014-03-28 21:37:38 -0500831 rtw_tkip_encrypt23a(padapter, pxmitframe);
832 break;
Jes Sorensen9e3d6df2014-05-21 09:37:34 +0200833 case WLAN_CIPHER_SUITE_CCMP:
Larry Finger5e93f352014-03-28 21:37:38 -0500834 rtw_aes_encrypt23a(padapter, pxmitframe);
835 break;
836 default:
837 break;
838 }
839
840 } else {
841 RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_,
842 ("### xmitframe_hwencrypt\n"));
843 }
844
845 return _SUCCESS;
846}
847
Jes Sorensen39ef8912014-05-21 09:37:58 +0200848static int rtw_make_wlanhdr(struct rtw_adapter *padapter, u8 *hdr,
849 struct pkt_attrib *pattrib)
Larry Finger5e93f352014-03-28 21:37:38 -0500850{
Larry Finger5e93f352014-03-28 21:37:38 -0500851 struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr;
Jes Sorensene5b2a422014-05-21 09:38:05 +0200852 struct ieee80211_qos_hdr *qoshdr;
Larry Finger5e93f352014-03-28 21:37:38 -0500853 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
Larry Finger5e93f352014-03-28 21:37:38 -0500854 u8 qos_option = false;
855 int res = _SUCCESS;
Larry Finger5e93f352014-03-28 21:37:38 -0500856
857 struct sta_info *psta;
858
859 int bmcst = is_multicast_ether_addr(pattrib->ra);
860
861 if (pattrib->psta) {
862 psta = pattrib->psta;
863 } else {
864 DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
865 if (bmcst) {
866 psta = rtw_get_bcmc_stainfo23a(padapter);
867 } else {
868 psta = rtw_get_stainfo23a(&padapter->stapriv, pattrib->ra);
869 }
870 }
871
872 if (psta == NULL) {
873 DBG_8723A("%s, psta == NUL\n", __func__);
874 return _FAIL;
875 }
876
877 if (!(psta->state &_FW_LINKED)) {
878 DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state);
879 return _FAIL;
880 }
881
882 memset(hdr, 0, WLANHDR_OFFSET);
883
Jes Sorensenb2f72ca2014-05-21 09:38:09 +0200884 pwlanhdr->frame_control = cpu_to_le16(pattrib->type);
Larry Finger5e93f352014-03-28 21:37:38 -0500885
Jes Sorensenb2f72ca2014-05-21 09:38:09 +0200886 if (pattrib->type & IEEE80211_FTYPE_DATA) {
Jes Sorensenf2f97032014-05-25 22:43:04 +0200887 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
Larry Finger5e93f352014-03-28 21:37:38 -0500888 /* to_ds = 1, fr_ds = 0; */
889 /* Data transfer to AP */
Jes Sorensenc26e9572014-05-21 09:38:17 +0200890 pwlanhdr->frame_control |=
891 cpu_to_le16(IEEE80211_FCTL_TODS);
Jes Sorensen04e57762014-05-25 22:43:03 +0200892 ether_addr_copy(pwlanhdr->addr1, get_bssid(pmlmepriv));
893 ether_addr_copy(pwlanhdr->addr2, pattrib->src);
894 ether_addr_copy(pwlanhdr->addr3, pattrib->dst);
Larry Finger5e93f352014-03-28 21:37:38 -0500895
Jes Sorensenbd8ad4a2014-05-09 15:03:21 +0200896 if (pmlmepriv->qos_option)
Larry Finger5e93f352014-03-28 21:37:38 -0500897 qos_option = true;
898
Jes Sorensenf2f97032014-05-25 22:43:04 +0200899 } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
Larry Finger5e93f352014-03-28 21:37:38 -0500900 /* to_ds = 0, fr_ds = 1; */
Jes Sorensenc26e9572014-05-21 09:38:17 +0200901 pwlanhdr->frame_control |=
902 cpu_to_le16(IEEE80211_FCTL_FROMDS);
Jes Sorensen04e57762014-05-25 22:43:03 +0200903 ether_addr_copy(pwlanhdr->addr1, pattrib->dst);
904 ether_addr_copy(pwlanhdr->addr2, get_bssid(pmlmepriv));
905 ether_addr_copy(pwlanhdr->addr3, pattrib->src);
Larry Finger5e93f352014-03-28 21:37:38 -0500906
907 if (psta->qos_option)
908 qos_option = true;
Jes Sorensenf2f97032014-05-25 22:43:04 +0200909 } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
910 check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
Jes Sorensen04e57762014-05-25 22:43:03 +0200911 ether_addr_copy(pwlanhdr->addr1, pattrib->dst);
912 ether_addr_copy(pwlanhdr->addr2, pattrib->src);
913 ether_addr_copy(pwlanhdr->addr3, get_bssid(pmlmepriv));
Larry Finger5e93f352014-03-28 21:37:38 -0500914
915 if (psta->qos_option)
916 qos_option = true;
917 }
918 else {
919 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv)));
920 res = _FAIL;
921 goto exit;
922 }
923 if (pattrib->mdata)
Jes Sorensenc6716e12014-05-21 09:38:02 +0200924 pwlanhdr->frame_control |=
925 cpu_to_le16(IEEE80211_FCTL_MOREDATA);
Larry Finger5e93f352014-03-28 21:37:38 -0500926 if (pattrib->encrypt)
Jes Sorensenc6716e12014-05-21 09:38:02 +0200927 pwlanhdr->frame_control |=
928 cpu_to_le16(IEEE80211_FCTL_PROTECTED);
Larry Finger5e93f352014-03-28 21:37:38 -0500929 if (qos_option) {
Jes Sorensene5b2a422014-05-21 09:38:05 +0200930 qoshdr = (struct ieee80211_qos_hdr *)hdr;
931
932 qoshdr->qos_ctrl = cpu_to_le16(
933 pattrib->priority & IEEE80211_QOS_CTL_TID_MASK);
934
935 qoshdr->qos_ctrl |= cpu_to_le16(
936 (pattrib->ack_policy << 5) &
937 IEEE80211_QOS_CTL_ACK_POLICY_MASK);
938
939 if (pattrib->eosp)
940 qoshdr->qos_ctrl |=
941 cpu_to_le16(IEEE80211_QOS_CTL_EOSP);
Larry Finger5e93f352014-03-28 21:37:38 -0500942 }
943 /* TODO: fill HT Control Field */
944
945 /* Update Seq Num will be handled by f/w */
946 if (psta) {
947 psta->sta_xmitpriv.txseq_tid[pattrib->priority]++;
948 psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF;
949 pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority];
Jes Sorensen670ce682014-05-21 09:37:57 +0200950 /* We dont need to worry about frag bits here */
951 pwlanhdr->seq_ctrl = cpu_to_le16(IEEE80211_SN_TO_SEQ(
952 pattrib->seqnum));
Larry Finger5e93f352014-03-28 21:37:38 -0500953 /* check if enable ampdu */
954 if (pattrib->ht_en && psta->htpriv.ampdu_enable) {
Jes Sorensen072fc842014-05-09 15:04:14 +0200955 if (pattrib->priority >= 16)
956 printk(KERN_WARNING "%s: Invalid "
957 "pattrib->priority %i\n",
958 __func__, pattrib->priority);
959 if (psta->htpriv.agg_enable_bitmap &
960 BIT(pattrib->priority))
961 pattrib->ampdu_en = true;
Larry Finger5e93f352014-03-28 21:37:38 -0500962 }
963 /* re-check if enable ampdu by BA_starting_seqctrl */
964 if (pattrib->ampdu_en) {
965 u16 tx_seq;
966
967 tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f];
968
969 /* check BA_starting_seqctrl */
970 if (SN_LESS(pattrib->seqnum, tx_seq)) {
971 /* DBG_8723A("tx ampdu seqnum(%d) < tx_seq(%d)\n", pattrib->seqnum, tx_seq); */
972 pattrib->ampdu_en = false;/* AGG BK */
973 } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) {
974 psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff;
975 pattrib->ampdu_en = true;/* AGG EN */
976 } else {
977 /* DBG_8723A("tx ampdu over run\n"); */
978 psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff;
979 pattrib->ampdu_en = true;/* AGG EN */
980 }
981 }
982 }
983 }
984exit:
985 return res;
986}
987
988s32 rtw_txframes_pending23a(struct rtw_adapter *padapter)
989{
990 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
991
Jes Sorensen794ff052014-05-09 15:03:59 +0200992 return (!list_empty(&pxmitpriv->be_pending.queue)) ||
993 (!list_empty(&pxmitpriv->bk_pending.queue)) ||
994 (!list_empty(&pxmitpriv->vi_pending.queue)) ||
995 (!list_empty(&pxmitpriv->vo_pending.queue));
Larry Finger5e93f352014-03-28 21:37:38 -0500996}
997
998s32 rtw_txframes_sta_ac_pending23a(struct rtw_adapter *padapter,
999 struct pkt_attrib *pattrib)
1000{
1001 struct sta_info *psta;
1002 struct tx_servq *ptxservq;
1003 int priority = pattrib->priority;
1004
1005 if (pattrib->psta) {
1006 psta = pattrib->psta;
1007 } else {
1008 DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
1009 psta = rtw_get_stainfo23a(&padapter->stapriv, &pattrib->ra[0]);
1010 }
1011 if (psta == NULL) {
1012 DBG_8723A("%s, psta == NUL\n", __func__);
1013 return 0;
1014 }
1015 if (!(psta->state &_FW_LINKED)) {
1016 DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__,
1017 psta->state);
1018 return 0;
1019 }
1020 switch (priority) {
1021 case 1:
1022 case 2:
1023 ptxservq = &psta->sta_xmitpriv.bk_q;
1024 break;
1025 case 4:
1026 case 5:
1027 ptxservq = &psta->sta_xmitpriv.vi_q;
1028 break;
1029 case 6:
1030 case 7:
1031 ptxservq = &psta->sta_xmitpriv.vo_q;
1032 break;
1033 case 0:
1034 case 3:
1035 default:
1036 ptxservq = &psta->sta_xmitpriv.be_q;
1037 break;
1038 }
1039 return ptxservq->qcnt;
1040}
1041
Jes Sorensen848ad5d2014-11-10 18:11:40 -05001042/* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header
1043 * IEEE LLC/SNAP header contains 8 octets
1044 * First 3 octets comprise the LLC portion
1045 * SNAP portion, 5 octets, is divided into two fields:
1046 * Organizationally Unique Identifier(OUI), 3 octets,
1047 * type, defined by that organization, 2 octets.
1048 */
1049static int rtw_put_snap(u8 *data, u16 h_proto)
1050{
1051 if (h_proto == ETH_P_IPX || h_proto == ETH_P_AARP)
1052 ether_addr_copy(data, bridge_tunnel_header);
1053 else
1054 ether_addr_copy(data, rfc1042_header);
1055
1056 data += ETH_ALEN;
1057 put_unaligned_be16(h_proto, data);
1058 return ETH_ALEN + sizeof(u16);
1059}
1060
Larry Finger5e93f352014-03-28 21:37:38 -05001061/*
Larry Finger5e93f352014-03-28 21:37:38 -05001062
1063This sub-routine will perform all the following:
1064
10651. remove 802.3 header.
10662. create wlan_header, based on the info in pxmitframe
10673. append sta's iv/ext-iv
10684. append LLC
10695. move frag chunk from pframe to pxmitframe->mem
10706. apply sw-encrypt, if necessary.
1071
1072*/
Jes Sorensen8fd873d2014-05-16 10:04:40 +02001073int rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *skb,
Larry Finger5e93f352014-03-28 21:37:38 -05001074 struct xmit_frame *pxmitframe)
1075{
Jes Sorensen69a0f972014-04-09 23:21:11 +02001076 struct sta_info *psta;
1077 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
1078 struct pkt_attrib *pattrib = &pxmitframe->attrib;
Jes Sorensen8e3ddad2014-05-21 09:37:44 +02001079 struct ieee80211_hdr *hdr;
Larry Finger5e93f352014-03-28 21:37:38 -05001080 s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz;
Larry Finger5e93f352014-03-28 21:37:38 -05001081 u8 *pframe, *mem_start;
1082 u8 hw_hdr_offset;
1083 u8 *pbuf_start;
Jes Sorensen3e689a92014-04-09 23:21:12 +02001084 u8 *pdata = skb->data;
1085 int data_len = skb->len;
Larry Finger5e93f352014-03-28 21:37:38 -05001086 s32 bmcst = is_multicast_ether_addr(pattrib->ra);
Jes Sorensen8fd873d2014-05-16 10:04:40 +02001087 int res = _SUCCESS;
Larry Finger5e93f352014-03-28 21:37:38 -05001088
Jes Sorensen69a0f972014-04-09 23:21:11 +02001089 if (pattrib->psta)
Larry Finger5e93f352014-03-28 21:37:38 -05001090 psta = pattrib->psta;
Jes Sorensen69a0f972014-04-09 23:21:11 +02001091 else {
Larry Finger5e93f352014-03-28 21:37:38 -05001092 DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
1093 psta = rtw_get_stainfo23a(&padapter->stapriv, pattrib->ra);
1094 }
1095
Jes Sorensen69a0f972014-04-09 23:21:11 +02001096 if (!psta) {
Larry Finger5e93f352014-03-28 21:37:38 -05001097 DBG_8723A("%s, psta == NUL\n", __func__);
1098 return _FAIL;
1099 }
1100
1101 if (!(psta->state &_FW_LINKED)) {
Jes Sorensen69a0f972014-04-09 23:21:11 +02001102 DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n",
1103 __func__, psta->state);
Larry Finger5e93f352014-03-28 21:37:38 -05001104 return _FAIL;
1105 }
1106
Jes Sorensen69a0f972014-04-09 23:21:11 +02001107 if (!pxmitframe->buf_addr) {
Larry Finger5e93f352014-03-28 21:37:38 -05001108 DBG_8723A("==> %s buf_addr == NULL\n", __func__);
1109 return _FAIL;
1110 }
1111
1112 pbuf_start = pxmitframe->buf_addr;
1113
1114 hw_hdr_offset = TXDESC_OFFSET;
1115
Jes Sorensen69a0f972014-04-09 23:21:11 +02001116 mem_start = pbuf_start + hw_hdr_offset;
Larry Finger5e93f352014-03-28 21:37:38 -05001117
Jes Sorensen39ef8912014-05-21 09:37:58 +02001118 if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) {
Larry Finger5e93f352014-03-28 21:37:38 -05001119 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
Jes Sorensen39ef8912014-05-21 09:37:58 +02001120 ("%s: rtw_make_wlanhdr fail; drop pkt\n", __func__));
Larry Finger5e93f352014-03-28 21:37:38 -05001121 res = _FAIL;
1122 goto exit;
1123 }
1124
Jes Sorensen3e689a92014-04-09 23:21:12 +02001125 pdata += pattrib->pkt_hdrlen;
1126 data_len -= pattrib->pkt_hdrlen;
Larry Finger5e93f352014-03-28 21:37:38 -05001127
1128 frg_inx = 0;
1129 frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */
1130
1131 while (1) {
1132 llc_sz = 0;
1133
1134 mpdu_len = frg_len;
1135
1136 pframe = mem_start;
Jes Sorensen8e3ddad2014-05-21 09:37:44 +02001137 hdr = (struct ieee80211_hdr *)mem_start;
Larry Finger5e93f352014-03-28 21:37:38 -05001138
1139 pframe += pattrib->hdrlen;
1140 mpdu_len -= pattrib->hdrlen;
1141
1142 /* adding icv, if necessary... */
1143 if (pattrib->iv_len) {
Jes Sorensen69a0f972014-04-09 23:21:11 +02001144 if (psta) {
Larry Finger5e93f352014-03-28 21:37:38 -05001145 switch (pattrib->encrypt) {
Jes Sorensen9e3d6df2014-05-21 09:37:34 +02001146 case WLAN_CIPHER_SUITE_WEP40:
1147 case WLAN_CIPHER_SUITE_WEP104:
Jes Sorensen69a0f972014-04-09 23:21:11 +02001148 WEP_IV(pattrib->iv, psta->dot11txpn,
1149 pattrib->key_idx);
Larry Finger5e93f352014-03-28 21:37:38 -05001150 break;
Jes Sorensen9e3d6df2014-05-21 09:37:34 +02001151 case WLAN_CIPHER_SUITE_TKIP:
Larry Finger5e93f352014-03-28 21:37:38 -05001152 if (bmcst)
Jes Sorensen69a0f972014-04-09 23:21:11 +02001153 TKIP_IV(pattrib->iv,
1154 psta->dot11txpn,
1155 pattrib->key_idx);
Larry Finger5e93f352014-03-28 21:37:38 -05001156 else
Jes Sorensen69a0f972014-04-09 23:21:11 +02001157 TKIP_IV(pattrib->iv,
1158 psta->dot11txpn, 0);
Larry Finger5e93f352014-03-28 21:37:38 -05001159 break;
Jes Sorensen9e3d6df2014-05-21 09:37:34 +02001160 case WLAN_CIPHER_SUITE_CCMP:
Larry Finger5e93f352014-03-28 21:37:38 -05001161 if (bmcst)
Jes Sorensen69a0f972014-04-09 23:21:11 +02001162 AES_IV(pattrib->iv,
1163 psta->dot11txpn,
1164 pattrib->key_idx);
Larry Finger5e93f352014-03-28 21:37:38 -05001165 else
Jes Sorensen69a0f972014-04-09 23:21:11 +02001166 AES_IV(pattrib->iv,
1167 psta->dot11txpn, 0);
Larry Finger5e93f352014-03-28 21:37:38 -05001168 break;
1169 }
1170 }
1171
1172 memcpy(pframe, pattrib->iv, pattrib->iv_len);
1173
1174 RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_,
1175 ("rtw_xmiaframe_coalesce23a: keyid =%d pattrib"
1176 "->iv[3]=%.2x pframe =%.2x %.2x %.2x %.2x\n",
1177 padapter->securitypriv.dot11PrivacyKeyIndex,
1178 pattrib->iv[3], *pframe, *(pframe+1),
1179 *(pframe+2), *(pframe+3)));
1180 pframe += pattrib->iv_len;
1181 mpdu_len -= pattrib->iv_len;
1182 }
1183 if (frg_inx == 0) {
Jes Sorensen848ad5d2014-11-10 18:11:40 -05001184 llc_sz = rtw_put_snap(pframe, pattrib->ether_type);
Larry Finger5e93f352014-03-28 21:37:38 -05001185 pframe += llc_sz;
1186 mpdu_len -= llc_sz;
1187 }
1188
Jes Sorensen69a0f972014-04-09 23:21:11 +02001189 if (pattrib->icv_len > 0 && pattrib->bswenc)
Larry Finger5e93f352014-03-28 21:37:38 -05001190 mpdu_len -= pattrib->icv_len;
1191
Jes Sorensen3e689a92014-04-09 23:21:12 +02001192 if (bmcst)
Masanari Iidac582db42014-07-22 23:42:37 +09001193 /* don't do fragment to broadcast/multicast packets */
Jes Sorensen3e689a92014-04-09 23:21:12 +02001194 mem_sz = min_t(s32, data_len, pattrib->pktlen);
1195 else
1196 mem_sz = min_t(s32, data_len, mpdu_len);
1197
1198 memcpy(pframe, pdata, mem_sz);
1199
Larry Finger5e93f352014-03-28 21:37:38 -05001200 pframe += mem_sz;
Jes Sorensen3e689a92014-04-09 23:21:12 +02001201 pdata += mem_sz;
1202 data_len -= mem_sz;
Larry Finger5e93f352014-03-28 21:37:38 -05001203
1204 if ((pattrib->icv_len >0) && (pattrib->bswenc)) {
1205 memcpy(pframe, pattrib->icv, pattrib->icv_len);
1206 pframe += pattrib->icv_len;
1207 }
1208
1209 frg_inx++;
1210
Jes Sorensen3e689a92014-04-09 23:21:12 +02001211 if (bmcst || data_len <= 0) {
Larry Finger5e93f352014-03-28 21:37:38 -05001212 pattrib->nr_frags = frg_inx;
1213
1214 pattrib->last_txcmdsz = pattrib->hdrlen +
1215 pattrib->iv_len +
1216 ((pattrib->nr_frags == 1) ?
1217 llc_sz : 0) +
1218 ((pattrib->bswenc) ?
1219 pattrib->icv_len : 0) + mem_sz;
Jes Sorensen8e3ddad2014-05-21 09:37:44 +02001220 hdr->frame_control &=
1221 ~cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
Larry Finger5e93f352014-03-28 21:37:38 -05001222
1223 break;
1224 } else {
Jes Sorensen69a0f972014-04-09 23:21:11 +02001225 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
1226 ("%s: There're still something in packet!\n",
1227 __func__));
Larry Finger5e93f352014-03-28 21:37:38 -05001228 }
Jes Sorensen8e3ddad2014-05-21 09:37:44 +02001229 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
Larry Finger5e93f352014-03-28 21:37:38 -05001230
Larry Fingerc17416e2014-03-28 21:37:42 -05001231 mem_start = PTR_ALIGN(pframe, 4) + hw_hdr_offset;
Larry Finger5e93f352014-03-28 21:37:38 -05001232 memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen);
Larry Finger5e93f352014-03-28 21:37:38 -05001233 }
1234
1235 if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) {
Jes Sorensen69a0f972014-04-09 23:21:11 +02001236 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
1237 ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"));
Larry Finger5e93f352014-03-28 21:37:38 -05001238 DBG_8723A("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n");
1239 res = _FAIL;
1240 goto exit;
1241 }
1242
1243 xmitframe_swencrypt(padapter, pxmitframe);
1244
1245 if (bmcst == false)
1246 update_attrib_vcs_info(padapter, pxmitframe);
1247 else
1248 pattrib->vcs_mode = NONE_VCS;
1249
1250exit:
1251 return res;
1252}
1253
Larry Finger5e93f352014-03-28 21:37:38 -05001254void rtw_update_protection23a(struct rtw_adapter *padapter, u8 *ie, uint ie_len)
1255{
Jes Sorensen4bf954b2014-04-15 19:43:54 +02001256 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
1257 struct registry_priv *pregistrypriv = &padapter->registrypriv;
1258 uint protection;
1259 const u8 *p;
Larry Finger5e93f352014-03-28 21:37:38 -05001260
Jes Sorensen70b88f52014-10-10 21:41:29 +02001261 switch (pregistrypriv->vrtl_carrier_sense) {
Larry Finger5e93f352014-03-28 21:37:38 -05001262 case DISABLE_VCS:
1263 pxmitpriv->vcs = NONE_VCS;
1264 break;
1265 case ENABLE_VCS:
1266 break;
1267 case AUTO_VCS:
1268 default:
Jes Sorensen4bf954b2014-04-15 19:43:54 +02001269 p = cfg80211_find_ie(WLAN_EID_ERP_INFO, ie, ie_len);
1270 if (!p)
Larry Finger5e93f352014-03-28 21:37:38 -05001271 pxmitpriv->vcs = NONE_VCS;
Jes Sorensen4bf954b2014-04-15 19:43:54 +02001272 else {
1273 protection = (*(p + 2)) & BIT(1);
Larry Finger5e93f352014-03-28 21:37:38 -05001274 if (protection) {
1275 if (pregistrypriv->vcs_type == RTS_CTS)
1276 pxmitpriv->vcs = RTS_CTS;
1277 else
1278 pxmitpriv->vcs = CTS_TO_SELF;
1279 } else {
1280 pxmitpriv->vcs = NONE_VCS;
1281 }
1282 }
1283 break;
1284 }
1285}
1286
1287void rtw_count_tx_stats23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe, int sz)
1288{
1289 struct sta_info *psta = NULL;
1290 struct stainfo_stats *pstats = NULL;
1291 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
1292 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1293
Jes Sorensenb81f3f22014-11-10 18:11:43 -05001294 if (pxmitframe->frame_tag == DATA_FRAMETAG) {
Larry Finger5e93f352014-03-28 21:37:38 -05001295 pxmitpriv->tx_bytes += sz;
1296 pmlmepriv->LinkDetectInfo.NumTxOkInPeriod++;
1297
1298 psta = pxmitframe->attrib.psta;
1299 if (psta) {
1300 pstats = &psta->sta_stats;
1301 pstats->tx_pkts++;
1302 pstats->tx_bytes += sz;
1303 }
1304 }
1305}
1306
1307struct xmit_buf *rtw_alloc_xmitbuf23a_ext(struct xmit_priv *pxmitpriv)
1308{
1309 unsigned long irqL;
1310 struct xmit_buf *pxmitbuf = NULL;
1311 struct list_head *phead;
1312 struct rtw_queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
1313
1314 spin_lock_irqsave(&pfree_queue->lock, irqL);
1315
1316 phead = get_list_head(pfree_queue);
1317
1318 if (!list_empty(phead)) {
1319 pxmitbuf = list_first_entry(phead, struct xmit_buf, list);
1320
1321 list_del_init(&pxmitbuf->list);
1322
1323 pxmitpriv->free_xmit_extbuf_cnt--;
1324 pxmitbuf->priv_data = NULL;
1325 pxmitbuf->ext_tag = true;
1326
1327 if (pxmitbuf->sctx) {
1328 DBG_8723A("%s pxmitbuf->sctx is not NULL\n", __func__);
1329 rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC);
1330 }
1331 }
1332
1333 spin_unlock_irqrestore(&pfree_queue->lock, irqL);
1334
1335 return pxmitbuf;
1336}
1337
Jes Sorensen8fd873d2014-05-16 10:04:40 +02001338int rtw_free_xmitbuf_ext23a(struct xmit_priv *pxmitpriv,
1339 struct xmit_buf *pxmitbuf)
Larry Finger5e93f352014-03-28 21:37:38 -05001340{
1341 unsigned long irqL;
1342 struct rtw_queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
1343
1344 if (pxmitbuf == NULL)
1345 return _FAIL;
1346
1347 spin_lock_irqsave(&pfree_queue->lock, irqL);
1348
1349 list_del_init(&pxmitbuf->list);
1350
1351 list_add_tail(&pxmitbuf->list, get_list_head(pfree_queue));
1352 pxmitpriv->free_xmit_extbuf_cnt++;
1353
1354 spin_unlock_irqrestore(&pfree_queue->lock, irqL);
1355
1356 return _SUCCESS;
1357}
1358
1359struct xmit_buf *rtw_alloc_xmitbuf23a(struct xmit_priv *pxmitpriv)
1360{
1361 unsigned long irqL;
1362 struct xmit_buf *pxmitbuf = NULL;
1363 struct list_head *phead;
1364 struct rtw_queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
1365
1366 /* DBG_8723A("+rtw_alloc_xmitbuf23a\n"); */
1367
1368 spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL);
1369
1370 phead = get_list_head(pfree_xmitbuf_queue);
1371
1372 if (!list_empty(phead)) {
1373 pxmitbuf = list_first_entry(phead, struct xmit_buf, list);
1374
1375 list_del_init(&pxmitbuf->list);
1376
1377 pxmitpriv->free_xmitbuf_cnt--;
1378 pxmitbuf->priv_data = NULL;
1379 pxmitbuf->ext_tag = false;
1380 pxmitbuf->flags = XMIT_VO_QUEUE;
1381
1382 if (pxmitbuf->sctx) {
1383 DBG_8723A("%s pxmitbuf->sctx is not NULL\n", __func__);
1384 rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC);
1385 }
1386 }
1387
1388 spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL);
1389
1390 return pxmitbuf;
1391}
1392
Jes Sorensen8fd873d2014-05-16 10:04:40 +02001393int rtw_free_xmitbuf23a(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
Larry Finger5e93f352014-03-28 21:37:38 -05001394{
1395 unsigned long irqL;
1396 struct rtw_queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
1397
1398 /* DBG_8723A("+rtw_free_xmitbuf23a\n"); */
1399
1400 if (pxmitbuf == NULL)
1401 return _FAIL;
1402
1403 if (pxmitbuf->sctx) {
1404 DBG_8723A("%s pxmitbuf->sctx is not NULL\n", __func__);
1405 rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE);
1406 }
1407
1408 if (pxmitbuf->ext_tag) {
1409 rtw_free_xmitbuf_ext23a(pxmitpriv, pxmitbuf);
1410 } else {
1411 spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL);
1412
1413 list_del_init(&pxmitbuf->list);
1414
1415 list_add_tail(&pxmitbuf->list,
1416 get_list_head(pfree_xmitbuf_queue));
1417
1418 pxmitpriv->free_xmitbuf_cnt++;
1419 spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL);
1420 }
1421
1422 return _SUCCESS;
1423}
1424
1425static void rtw_init_xmitframe(struct xmit_frame *pxframe)
1426{
1427 if (pxframe != NULL) {
1428 /* default value setting */
1429 pxframe->buf_addr = NULL;
1430 pxframe->pxmitbuf = NULL;
1431
1432 memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib));
1433 /* pxframe->attrib.psta = NULL; */
1434
1435 pxframe->frame_tag = DATA_FRAMETAG;
1436
1437 pxframe->pkt = NULL;
1438 pxframe->pkt_offset = 1;/* default use pkt_offset to fill tx desc */
1439
1440 pxframe->ack_report = 0;
1441 }
1442}
1443
1444/*
1445Calling context:
14461. OS_TXENTRY
14472. RXENTRY (rx_thread or RX_ISR/RX_CallBack)
1448
1449If we turn on USE_RXTHREAD, then, no need for critical section.
1450Otherwise, we must use _enter/_exit critical to protect free_xmit_queue...
1451
1452Must be very very cautious...
1453
1454*/
Jes Sorensen6042cbf2014-05-09 15:03:51 +02001455static struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)
Larry Finger5e93f352014-03-28 21:37:38 -05001456{
Larry Finger5e93f352014-03-28 21:37:38 -05001457 struct xmit_frame *pxframe = NULL;
1458 struct list_head *plist, *phead;
1459 struct rtw_queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue;
1460
1461 spin_lock_bh(&pfree_xmit_queue->lock);
1462
Jes Sorensen794ff052014-05-09 15:03:59 +02001463 if (list_empty(&pfree_xmit_queue->queue)) {
Jes Sorensen6042cbf2014-05-09 15:03:51 +02001464 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
1465 ("rtw_alloc_xmitframe:%d\n",
1466 pxmitpriv->free_xmitframe_cnt));
Larry Finger5e93f352014-03-28 21:37:38 -05001467 pxframe = NULL;
1468 } else {
1469 phead = get_list_head(pfree_xmit_queue);
1470
1471 plist = phead->next;
1472
1473 pxframe = container_of(plist, struct xmit_frame, list);
1474
1475 list_del_init(&pxframe->list);
1476 pxmitpriv->free_xmitframe_cnt--;
Jes Sorensen6042cbf2014-05-09 15:03:51 +02001477 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
1478 ("rtw_alloc_xmitframe():free_xmitframe_cnt =%d\n",
1479 pxmitpriv->free_xmitframe_cnt));
Larry Finger5e93f352014-03-28 21:37:38 -05001480 }
1481
1482 spin_unlock_bh(&pfree_xmit_queue->lock);
1483
1484 rtw_init_xmitframe(pxframe);
1485
1486 return pxframe;
1487}
1488
1489struct xmit_frame *rtw_alloc_xmitframe23a_ext(struct xmit_priv *pxmitpriv)
1490{
1491 struct xmit_frame *pxframe = NULL;
1492 struct list_head *plist, *phead;
1493 struct rtw_queue *queue = &pxmitpriv->free_xframe_ext_queue;
1494
1495 spin_lock_bh(&queue->lock);
1496
Jes Sorensen794ff052014-05-09 15:03:59 +02001497 if (list_empty(&queue->queue)) {
Larry Finger5e93f352014-03-28 21:37:38 -05001498 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe23a_ext:%d\n", pxmitpriv->free_xframe_ext_cnt));
1499 pxframe = NULL;
1500 } else {
1501 phead = get_list_head(queue);
1502 plist = phead->next;
1503 pxframe = container_of(plist, struct xmit_frame, list);
1504
1505 list_del_init(&pxframe->list);
1506 pxmitpriv->free_xframe_ext_cnt--;
1507 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe23a_ext():free_xmitframe_cnt =%d\n", pxmitpriv->free_xframe_ext_cnt));
1508 }
1509
1510 spin_unlock_bh(&queue->lock);
1511
1512 rtw_init_xmitframe(pxframe);
1513
1514 return pxframe;
1515}
1516
1517s32 rtw_free_xmitframe23a(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe)
1518{
1519 struct rtw_queue *queue = NULL;
1520 struct rtw_adapter *padapter = pxmitpriv->adapter;
1521 struct sk_buff *pndis_pkt = NULL;
1522
1523 if (pxmitframe == NULL) {
1524 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== rtw_free_xmitframe23a():pxmitframe == NULL!!!!!!!!!!\n"));
1525 goto exit;
1526 }
1527
1528 if (pxmitframe->pkt) {
1529 pndis_pkt = pxmitframe->pkt;
1530 pxmitframe->pkt = NULL;
1531 }
1532
1533 if (pxmitframe->ext_tag == 0)
1534 queue = &pxmitpriv->free_xmit_queue;
1535 else if (pxmitframe->ext_tag == 1)
1536 queue = &pxmitpriv->free_xframe_ext_queue;
1537
1538 if (!queue)
1539 goto check_pkt_complete;
1540 spin_lock_bh(&queue->lock);
1541
1542 list_del_init(&pxmitframe->list);
1543 list_add_tail(&pxmitframe->list, get_list_head(queue));
1544 if (pxmitframe->ext_tag == 0) {
1545 pxmitpriv->free_xmitframe_cnt++;
1546 RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe23a():free_xmitframe_cnt =%d\n", pxmitpriv->free_xmitframe_cnt));
1547 } else if (pxmitframe->ext_tag == 1) {
1548 pxmitpriv->free_xframe_ext_cnt++;
1549 RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe23a():free_xframe_ext_cnt =%d\n", pxmitpriv->free_xframe_ext_cnt));
1550 }
1551
1552 spin_unlock_bh(&queue->lock);
1553
1554check_pkt_complete:
1555
1556 if (pndis_pkt)
1557 rtw_os_pkt_complete23a(padapter, pndis_pkt);
1558
1559exit:
1560
1561 return _SUCCESS;
1562}
1563
1564void rtw_free_xmitframe_queue23a(struct xmit_priv *pxmitpriv,
1565 struct rtw_queue *pframequeue)
1566{
1567 struct list_head *plist, *phead, *ptmp;
1568 struct xmit_frame *pxmitframe;
1569
1570 spin_lock_bh(&pframequeue->lock);
1571
1572 phead = get_list_head(pframequeue);
1573
1574 list_for_each_safe(plist, ptmp, phead) {
1575 pxmitframe = container_of(plist, struct xmit_frame, list);
1576
1577 rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
1578 }
1579 spin_unlock_bh(&pframequeue->lock);
1580
1581}
1582
Jes Sorensen8fd873d2014-05-16 10:04:40 +02001583int rtw_xmitframe_enqueue23a(struct rtw_adapter *padapter,
Larry Finger5e93f352014-03-28 21:37:38 -05001584 struct xmit_frame *pxmitframe)
1585{
1586 if (rtw_xmit23a_classifier(padapter, pxmitframe) == _FAIL) {
1587 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
1588 ("rtw_xmitframe_enqueue23a: drop xmit pkt for "
1589 "classifier fail\n"));
1590 return _FAIL;
1591 }
1592
1593 return _SUCCESS;
1594}
1595
1596static struct xmit_frame *
1597dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit,
1598 struct tx_servq *ptxservq, struct rtw_queue *pframe_queue)
1599{
1600 struct list_head *phead;
1601 struct xmit_frame *pxmitframe = NULL;
1602
1603 phead = get_list_head(pframe_queue);
1604
1605 if (!list_empty(phead)) {
1606 pxmitframe = list_first_entry(phead, struct xmit_frame, list);
1607 list_del_init(&pxmitframe->list);
1608 ptxservq->qcnt--;
1609 }
1610 return pxmitframe;
1611}
1612
1613struct xmit_frame *
1614rtw_dequeue_xframe23a(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i,
1615 int entry)
1616{
1617 struct list_head *sta_plist, *sta_phead, *ptmp;
1618 struct hw_xmit *phwxmit;
1619 struct tx_servq *ptxservq = NULL;
1620 struct rtw_queue *pframe_queue = NULL;
1621 struct xmit_frame *pxmitframe = NULL;
1622 struct rtw_adapter *padapter = pxmitpriv->adapter;
1623 struct registry_priv *pregpriv = &padapter->registrypriv;
1624 int i, inx[4];
1625
1626 inx[0] = 0;
1627 inx[1] = 1;
1628 inx[2] = 2;
1629 inx[3] = 3;
1630 if (pregpriv->wifi_spec == 1) {
1631 int j;
1632
1633 for (j = 0; j < 4; j++)
1634 inx[j] = pxmitpriv->wmm_para_seq[j];
1635 }
1636
1637 spin_lock_bh(&pxmitpriv->lock);
1638
1639 for (i = 0; i < entry; i++) {
1640 phwxmit = phwxmit_i + inx[i];
1641
1642 sta_phead = get_list_head(phwxmit->sta_queue);
1643
1644 list_for_each_safe(sta_plist, ptmp, sta_phead) {
1645 ptxservq = container_of(sta_plist, struct tx_servq,
1646 tx_pending);
1647
1648 pframe_queue = &ptxservq->sta_pending;
1649
1650 pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue);
1651
1652 if (pxmitframe) {
1653 phwxmit->accnt--;
1654
1655 /* Remove sta node when there is no pending packets. */
Jes Sorensen794ff052014-05-09 15:03:59 +02001656 /* must be done after get_next and
1657 before break */
1658 if (list_empty(&pframe_queue->queue))
Larry Finger5e93f352014-03-28 21:37:38 -05001659 list_del_init(&ptxservq->tx_pending);
1660 goto exit;
1661 }
1662 }
1663 }
1664exit:
1665 spin_unlock_bh(&pxmitpriv->lock);
1666 return pxmitframe;
1667}
1668
1669struct tx_servq *rtw_get_sta_pending23a(struct rtw_adapter *padapter, struct sta_info *psta, int up, u8 *ac)
1670{
1671 struct tx_servq *ptxservq = NULL;
1672
1673 switch (up) {
1674 case 1:
1675 case 2:
1676 ptxservq = &psta->sta_xmitpriv.bk_q;
1677 *(ac) = 3;
1678 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : BK\n"));
1679 break;
1680 case 4:
1681 case 5:
1682 ptxservq = &psta->sta_xmitpriv.vi_q;
1683 *(ac) = 1;
1684 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : VI\n"));
1685 break;
1686 case 6:
1687 case 7:
1688 ptxservq = &psta->sta_xmitpriv.vo_q;
1689 *(ac) = 0;
1690 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : VO\n"));
1691 break;
1692 case 0:
1693 case 3:
1694 default:
1695 ptxservq = &psta->sta_xmitpriv.be_q;
1696 *(ac) = 2;
1697 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : BE\n"));
1698 break;
1699 }
1700 return ptxservq;
1701}
1702
1703/*
1704 * Will enqueue pxmitframe to the proper queue,
1705 * and indicate it to xx_pending list.....
1706 */
Jes Sorensen8fd873d2014-05-16 10:04:40 +02001707int rtw_xmit23a_classifier(struct rtw_adapter *padapter,
1708 struct xmit_frame *pxmitframe)
Larry Finger5e93f352014-03-28 21:37:38 -05001709{
1710 struct sta_info *psta;
1711 struct tx_servq *ptxservq;
1712 struct pkt_attrib *pattrib = &pxmitframe->attrib;
1713 struct sta_priv *pstapriv = &padapter->stapriv;
1714 struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
1715 u8 ac_index;
1716 int res = _SUCCESS;
1717
1718 if (pattrib->psta) {
1719 psta = pattrib->psta;
1720 } else {
1721 DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
1722 psta = rtw_get_stainfo23a(pstapriv, pattrib->ra);
1723 }
1724 if (psta == NULL) {
1725 res = _FAIL;
1726 DBG_8723A("rtw_xmit23a_classifier: psta == NULL\n");
1727 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
1728 ("rtw_xmit23a_classifier: psta == NULL\n"));
1729 goto exit;
1730 }
1731 if (!(psta->state & _FW_LINKED)) {
1732 DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__,
1733 psta->state);
1734 return _FAIL;
1735 }
1736 ptxservq = rtw_get_sta_pending23a(padapter, psta, pattrib->priority,
1737 (u8 *)(&ac_index));
1738
1739 if (list_empty(&ptxservq->tx_pending)) {
1740 list_add_tail(&ptxservq->tx_pending,
1741 get_list_head(phwxmits[ac_index].sta_queue));
1742 }
1743
1744 list_add_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending));
1745 ptxservq->qcnt++;
1746 phwxmits[ac_index].accnt++;
1747exit:
1748 return res;
1749}
1750
1751void rtw_alloc_hwxmits23a(struct rtw_adapter *padapter)
1752{
1753 struct hw_xmit *hwxmits;
1754 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
1755 int size;
1756
1757 pxmitpriv->hwxmit_entry = HWXMIT_ENTRY;
1758
1759 size = sizeof(struct hw_xmit) * (pxmitpriv->hwxmit_entry + 1);
1760 pxmitpriv->hwxmits = kzalloc(size, GFP_KERNEL);
1761
1762 hwxmits = pxmitpriv->hwxmits;
1763
1764 if (pxmitpriv->hwxmit_entry == 5) {
1765 /* pxmitpriv->bmc_txqueue.head = 0; */
1766 /* hwxmits[0] .phwtxqueue = &pxmitpriv->bmc_txqueue; */
1767 hwxmits[0] .sta_queue = &pxmitpriv->bm_pending;
1768
1769 /* pxmitpriv->vo_txqueue.head = 0; */
1770 /* hwxmits[1] .phwtxqueue = &pxmitpriv->vo_txqueue; */
1771 hwxmits[1] .sta_queue = &pxmitpriv->vo_pending;
1772
1773 /* pxmitpriv->vi_txqueue.head = 0; */
1774 /* hwxmits[2] .phwtxqueue = &pxmitpriv->vi_txqueue; */
1775 hwxmits[2] .sta_queue = &pxmitpriv->vi_pending;
1776
1777 /* pxmitpriv->bk_txqueue.head = 0; */
1778 /* hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; */
1779 hwxmits[3] .sta_queue = &pxmitpriv->bk_pending;
1780
1781 /* pxmitpriv->be_txqueue.head = 0; */
1782 /* hwxmits[4] .phwtxqueue = &pxmitpriv->be_txqueue; */
1783 hwxmits[4] .sta_queue = &pxmitpriv->be_pending;
1784
1785 } else if (pxmitpriv->hwxmit_entry == 4) {
1786
1787 /* pxmitpriv->vo_txqueue.head = 0; */
1788 /* hwxmits[0] .phwtxqueue = &pxmitpriv->vo_txqueue; */
1789 hwxmits[0] .sta_queue = &pxmitpriv->vo_pending;
1790
1791 /* pxmitpriv->vi_txqueue.head = 0; */
1792 /* hwxmits[1] .phwtxqueue = &pxmitpriv->vi_txqueue; */
1793 hwxmits[1] .sta_queue = &pxmitpriv->vi_pending;
1794
1795 /* pxmitpriv->be_txqueue.head = 0; */
1796 /* hwxmits[2] .phwtxqueue = &pxmitpriv->be_txqueue; */
1797 hwxmits[2] .sta_queue = &pxmitpriv->be_pending;
1798
1799 /* pxmitpriv->bk_txqueue.head = 0; */
1800 /* hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; */
1801 hwxmits[3] .sta_queue = &pxmitpriv->bk_pending;
1802 } else {
1803
1804 }
1805}
1806
1807void rtw_free_hwxmits23a(struct rtw_adapter *padapter)
1808{
1809 struct hw_xmit *hwxmits;
1810 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
1811
1812 hwxmits = pxmitpriv->hwxmits;
1813 kfree(hwxmits);
1814}
1815
1816void rtw_init_hwxmits23a(struct hw_xmit *phwxmit, int entry)
1817{
1818 int i;
1819
1820 for (i = 0; i < entry; i++, phwxmit++)
1821 phwxmit->accnt = 0;
1822}
1823
1824u32 rtw_get_ff_hwaddr23a(struct xmit_frame *pxmitframe)
1825{
1826 u32 addr;
1827 struct pkt_attrib *pattrib = &pxmitframe->attrib;
1828
1829 switch (pattrib->qsel) {
1830 case 0:
1831 case 3:
1832 addr = BE_QUEUE_INX;
1833 break;
1834 case 1:
1835 case 2:
1836 addr = BK_QUEUE_INX;
1837 break;
1838 case 4:
1839 case 5:
1840 addr = VI_QUEUE_INX;
1841 break;
1842 case 6:
1843 case 7:
1844 addr = VO_QUEUE_INX;
1845 break;
1846 case 0x10:
1847 addr = BCN_QUEUE_INX;
1848 break;
1849 case 0x11:/* BC/MC in PS (HIQ) */
1850 addr = HIGH_QUEUE_INX;
1851 break;
1852 case 0x12:
1853 default:
1854 addr = MGT_QUEUE_INX;
1855 break;
1856 }
1857
1858 return addr;
1859}
1860
Larry Finger5e93f352014-03-28 21:37:38 -05001861/*
1862 * The main transmit(tx) entry
1863 *
1864 * Return
1865 * 1 enqueue
1866 * 0 success, hardware will handle this xmit frame(packet)
1867 * <0 fail
1868 */
1869int rtw_xmit23a(struct rtw_adapter *padapter, struct sk_buff *skb)
1870{
1871 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
1872 struct xmit_frame *pxmitframe = NULL;
Jes Sorensen8fd873d2014-05-16 10:04:40 +02001873 int res;
Larry Finger5e93f352014-03-28 21:37:38 -05001874
Jes Sorensen6042cbf2014-05-09 15:03:51 +02001875 pxmitframe = rtw_alloc_xmitframe(pxmitpriv);
Larry Finger5e93f352014-03-28 21:37:38 -05001876
1877 if (pxmitframe == NULL) {
1878 RT_TRACE(_module_xmit_osdep_c_, _drv_err_,
1879 ("rtw_xmit23a: no more pxmitframe\n"));
1880 return -1;
1881 }
1882
1883 res = update_attrib(padapter, skb, &pxmitframe->attrib);
1884
1885 if (res == _FAIL) {
1886 RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit23a: update attrib fail\n"));
1887 rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
1888 return -1;
1889 }
1890 pxmitframe->pkt = skb;
1891
Jes Sorensen01ffd622014-11-30 16:04:57 -05001892 pxmitframe->attrib.qsel = pxmitframe->attrib.priority;
Larry Finger5e93f352014-03-28 21:37:38 -05001893
1894#ifdef CONFIG_8723AU_AP_MODE
1895 spin_lock_bh(&pxmitpriv->lock);
1896 if (xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe)) {
1897 spin_unlock_bh(&pxmitpriv->lock);
1898 return 1;
1899 }
1900 spin_unlock_bh(&pxmitpriv->lock);
1901#endif
1902
Jes Sorensen638443d2014-05-16 10:04:18 +02001903 if (rtl8723au_hal_xmit(padapter, pxmitframe) == false)
Larry Finger5e93f352014-03-28 21:37:38 -05001904 return 1;
1905
1906 return 0;
1907}
1908
1909#if defined(CONFIG_8723AU_AP_MODE)
1910
1911int xmitframe_enqueue_for_sleeping_sta23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
1912{
1913 int ret = false;
1914 struct sta_info *psta = NULL;
1915 struct sta_priv *pstapriv = &padapter->stapriv;
1916 struct pkt_attrib *pattrib = &pxmitframe->attrib;
1917 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1918 int bmcst = is_multicast_ether_addr(pattrib->ra);
1919
Jes Sorensen0618dbc2014-05-25 22:43:06 +02001920 if (!check_fwstate(pmlmepriv, WIFI_AP_STATE))
Jes Sorensen8fd873d2014-05-16 10:04:40 +02001921 return ret;
Larry Finger5e93f352014-03-28 21:37:38 -05001922
1923 if (pattrib->psta) {
1924 psta = pattrib->psta;
1925 } else {
1926 DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
1927 psta = rtw_get_stainfo23a(pstapriv, pattrib->ra);
1928 }
1929
1930 if (psta == NULL) {
1931 DBG_8723A("%s, psta == NUL\n", __func__);
1932 return false;
1933 }
1934
1935 if (!(psta->state & _FW_LINKED)) {
1936 DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__,
1937 psta->state);
1938 return false;
1939 }
1940
1941 if (pattrib->triggered == 1) {
1942 if (bmcst)
1943 pattrib->qsel = 0x11;/* HIQ */
1944 return ret;
1945 }
1946
1947 if (bmcst) {
1948 spin_lock_bh(&psta->sleep_q.lock);
1949
1950 if (pstapriv->sta_dz_bitmap) {
1951 /* if anyone sta is in ps mode */
1952 list_del_init(&pxmitframe->list);
1953
1954 /* spin_lock_bh(&psta->sleep_q.lock); */
1955
1956 list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q));
1957
1958 psta->sleepq_len++;
1959
1960 pstapriv->tim_bitmap |= BIT(0);/* */
1961 pstapriv->sta_dz_bitmap |= BIT(0);
1962
1963 /* DBG_8723A("enqueue, sq_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */
1964
Masanari Iidac582db42014-07-22 23:42:37 +09001965 /* tx bc/mc packets after update bcn */
Jes Sorensen3455f1f2014-04-15 19:43:31 +02001966 update_beacon23a(padapter, WLAN_EID_TIM, NULL, false);
Larry Finger5e93f352014-03-28 21:37:38 -05001967
1968 /* spin_unlock_bh(&psta->sleep_q.lock); */
1969
1970 ret = true;
1971
1972 }
1973
1974 spin_unlock_bh(&psta->sleep_q.lock);
1975
1976 return ret;
1977
1978 }
1979
1980 spin_lock_bh(&psta->sleep_q.lock);
1981
1982 if (psta->state&WIFI_SLEEP_STATE) {
1983 u8 wmmps_ac = 0;
1984
1985 if (pstapriv->sta_dz_bitmap & CHKBIT(psta->aid)) {
1986 list_del_init(&pxmitframe->list);
1987
1988 /* spin_lock_bh(&psta->sleep_q.lock); */
1989
1990 list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q));
1991
1992 psta->sleepq_len++;
1993
1994 switch (pattrib->priority) {
1995 case 1:
1996 case 2:
1997 wmmps_ac = psta->uapsd_bk & BIT(0);
1998 break;
1999 case 4:
2000 case 5:
2001 wmmps_ac = psta->uapsd_vi & BIT(0);
2002 break;
2003 case 6:
2004 case 7:
2005 wmmps_ac = psta->uapsd_vo & BIT(0);
2006 break;
2007 case 0:
2008 case 3:
2009 default:
2010 wmmps_ac = psta->uapsd_be & BIT(0);
2011 break;
2012 }
2013
2014 if (wmmps_ac)
2015 psta->sleepq_ac_len++;
2016
2017 if (((psta->has_legacy_ac) && (!wmmps_ac)) ||
2018 ((!psta->has_legacy_ac) && (wmmps_ac))) {
2019 pstapriv->tim_bitmap |= CHKBIT(psta->aid);
2020
2021 if (psta->sleepq_len == 1) {
Masanari Iidac582db42014-07-22 23:42:37 +09002022 /* update BCN for TIM IE */
Jes Sorensen3455f1f2014-04-15 19:43:31 +02002023 update_beacon23a(padapter, WLAN_EID_TIM,
2024 NULL, false);
Larry Finger5e93f352014-03-28 21:37:38 -05002025 }
2026 }
2027
2028 /* spin_unlock_bh(&psta->sleep_q.lock); */
2029
2030 /* if (psta->sleepq_len > (NR_XMITFRAME>>3)) */
2031 /* */
2032 /* wakeup_sta_to_xmit23a(padapter, psta); */
2033 /* */
2034
2035 ret = true;
2036
2037 }
2038
2039 }
2040
2041 spin_unlock_bh(&psta->sleep_q.lock);
2042
2043 return ret;
2044}
2045
2046static void
2047dequeue_xmitframes_to_sleeping_queue(struct rtw_adapter *padapter,
2048 struct sta_info *psta,
2049 struct rtw_queue *pframequeue)
2050{
2051 int ret;
2052 struct list_head *plist, *phead, *ptmp;
2053 u8 ac_index;
2054 struct tx_servq *ptxservq;
2055 struct pkt_attrib *pattrib;
2056 struct xmit_frame *pxmitframe;
2057 struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
2058
2059 phead = get_list_head(pframequeue);
2060
2061 list_for_each_safe(plist, ptmp, phead) {
2062 pxmitframe = container_of(plist, struct xmit_frame, list);
2063
2064 ret = xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe);
2065
2066 if (ret == true) {
2067 pattrib = &pxmitframe->attrib;
2068
2069 ptxservq = rtw_get_sta_pending23a(padapter, psta, pattrib->priority, (u8 *)(&ac_index));
2070
2071 ptxservq->qcnt--;
2072 phwxmits[ac_index].accnt--;
2073 } else {
2074 /* DBG_8723A("xmitframe_enqueue_for_sleeping_sta23a return false\n"); */
2075 }
2076 }
2077}
2078
2079void stop_sta_xmit23a(struct rtw_adapter *padapter, struct sta_info *psta)
2080{
2081 struct sta_info *psta_bmc;
2082 struct sta_xmit_priv *pstaxmitpriv;
2083 struct sta_priv *pstapriv = &padapter->stapriv;
2084 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
2085
2086 pstaxmitpriv = &psta->sta_xmitpriv;
2087
2088 /* for BC/MC Frames */
2089 psta_bmc = rtw_get_bcmc_stainfo23a(padapter);
2090
2091 spin_lock_bh(&pxmitpriv->lock);
2092
2093 psta->state |= WIFI_SLEEP_STATE;
2094
2095 pstapriv->sta_dz_bitmap |= CHKBIT(psta->aid);
2096
2097 dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending);
2098 list_del_init(&pstaxmitpriv->vo_q.tx_pending);
2099
2100 dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending);
2101 list_del_init(&pstaxmitpriv->vi_q.tx_pending);
2102
2103 dequeue_xmitframes_to_sleeping_queue(padapter, psta,
2104 &pstaxmitpriv->be_q.sta_pending);
2105 list_del_init(&pstaxmitpriv->be_q.tx_pending);
2106
2107 dequeue_xmitframes_to_sleeping_queue(padapter, psta,
2108 &pstaxmitpriv->bk_q.sta_pending);
2109 list_del_init(&pstaxmitpriv->bk_q.tx_pending);
2110
2111 /* for BC/MC Frames */
2112 pstaxmitpriv = &psta_bmc->sta_xmitpriv;
2113 dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc,
2114 &pstaxmitpriv->be_q.sta_pending);
2115 list_del_init(&pstaxmitpriv->be_q.tx_pending);
2116
2117 spin_unlock_bh(&pxmitpriv->lock);
2118}
2119
2120void wakeup_sta_to_xmit23a(struct rtw_adapter *padapter, struct sta_info *psta)
2121{
2122 u8 update_mask = 0, wmmps_ac = 0;
2123 struct sta_info *psta_bmc;
2124 struct list_head *plist, *phead, *ptmp;
2125 struct xmit_frame *pxmitframe = NULL;
2126 struct sta_priv *pstapriv = &padapter->stapriv;
2127 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
2128
2129 spin_lock_bh(&pxmitpriv->lock);
2130
2131 phead = get_list_head(&psta->sleep_q);
2132
2133 list_for_each_safe(plist, ptmp, phead) {
2134 pxmitframe = container_of(plist, struct xmit_frame, list);
2135 list_del_init(&pxmitframe->list);
2136
2137 switch (pxmitframe->attrib.priority) {
2138 case 1:
2139 case 2:
2140 wmmps_ac = psta->uapsd_bk & BIT(1);
2141 break;
2142 case 4:
2143 case 5:
2144 wmmps_ac = psta->uapsd_vi & BIT(1);
2145 break;
2146 case 6:
2147 case 7:
2148 wmmps_ac = psta->uapsd_vo & BIT(1);
2149 break;
2150 case 0:
2151 case 3:
2152 default:
2153 wmmps_ac = psta->uapsd_be & BIT(1);
2154 break;
2155 }
2156
2157 psta->sleepq_len--;
2158 if (psta->sleepq_len > 0)
2159 pxmitframe->attrib.mdata = 1;
2160 else
2161 pxmitframe->attrib.mdata = 0;
2162
2163 if (wmmps_ac) {
2164 psta->sleepq_ac_len--;
2165 if (psta->sleepq_ac_len > 0) {
2166 pxmitframe->attrib.mdata = 1;
2167 pxmitframe->attrib.eosp = 0;
2168 } else {
2169 pxmitframe->attrib.mdata = 0;
2170 pxmitframe->attrib.eosp = 1;
2171 }
2172 }
2173
2174 pxmitframe->attrib.triggered = 1;
Jes Sorensen638443d2014-05-16 10:04:18 +02002175 rtl8723au_hal_xmitframe_enqueue(padapter, pxmitframe);
Larry Finger5e93f352014-03-28 21:37:38 -05002176 }
2177
2178 if (psta->sleepq_len == 0) {
2179 pstapriv->tim_bitmap &= ~CHKBIT(psta->aid);
2180
Masanari Iidac582db42014-07-22 23:42:37 +09002181 /* update BCN for TIM IE */
Larry Finger5e93f352014-03-28 21:37:38 -05002182 update_mask = BIT(0);
2183
2184 if (psta->state&WIFI_SLEEP_STATE)
2185 psta->state ^= WIFI_SLEEP_STATE;
2186
2187 if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
2188 psta->expire_to = pstapriv->expire_to;
2189 psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
2190 }
2191
2192 pstapriv->sta_dz_bitmap &= ~CHKBIT(psta->aid);
2193 }
2194
2195 /* spin_unlock_bh(&psta->sleep_q.lock); */
2196 spin_unlock_bh(&pxmitpriv->lock);
2197
2198 /* for BC/MC Frames */
2199 psta_bmc = rtw_get_bcmc_stainfo23a(padapter);
2200 if (!psta_bmc)
2201 return;
2202
2203 if ((pstapriv->sta_dz_bitmap&0xfffe) == 0x0) {
2204 /* no any sta in ps mode */
2205 spin_lock_bh(&pxmitpriv->lock);
2206
2207 phead = get_list_head(&psta_bmc->sleep_q);
2208
2209 list_for_each_safe(plist, ptmp, phead) {
2210 pxmitframe = container_of(plist, struct xmit_frame,
2211 list);
2212
2213 list_del_init(&pxmitframe->list);
2214
2215 psta_bmc->sleepq_len--;
2216 if (psta_bmc->sleepq_len > 0)
2217 pxmitframe->attrib.mdata = 1;
2218 else
2219 pxmitframe->attrib.mdata = 0;
2220
2221 pxmitframe->attrib.triggered = 1;
Jes Sorensen638443d2014-05-16 10:04:18 +02002222 rtl8723au_hal_xmitframe_enqueue(padapter, pxmitframe);
Larry Finger5e93f352014-03-28 21:37:38 -05002223 }
2224 if (psta_bmc->sleepq_len == 0) {
2225 pstapriv->tim_bitmap &= ~BIT(0);
2226 pstapriv->sta_dz_bitmap &= ~BIT(0);
2227
Masanari Iidac582db42014-07-22 23:42:37 +09002228 /* update BCN for TIM IE */
Larry Finger5e93f352014-03-28 21:37:38 -05002229 /* update_BCNTIM(padapter); */
2230 update_mask |= BIT(1);
2231 }
2232
2233 /* spin_unlock_bh(&psta_bmc->sleep_q.lock); */
2234 spin_unlock_bh(&pxmitpriv->lock);
2235 }
2236
2237 if (update_mask)
Jes Sorensen3455f1f2014-04-15 19:43:31 +02002238 update_beacon23a(padapter, WLAN_EID_TIM, NULL, false);
Larry Finger5e93f352014-03-28 21:37:38 -05002239}
2240
2241void xmit_delivery_enabled_frames23a(struct rtw_adapter *padapter,
2242 struct sta_info *psta)
2243{
2244 u8 wmmps_ac = 0;
2245 struct list_head *plist, *phead, *ptmp;
2246 struct xmit_frame *pxmitframe;
2247 struct sta_priv *pstapriv = &padapter->stapriv;
2248 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
2249
2250 /* spin_lock_bh(&psta->sleep_q.lock); */
2251 spin_lock_bh(&pxmitpriv->lock);
2252
2253 phead = get_list_head(&psta->sleep_q);
2254
2255 list_for_each_safe(plist, ptmp, phead) {
2256 pxmitframe = container_of(plist, struct xmit_frame, list);
2257
2258 switch (pxmitframe->attrib.priority) {
2259 case 1:
2260 case 2:
2261 wmmps_ac = psta->uapsd_bk & BIT(1);
2262 break;
2263 case 4:
2264 case 5:
2265 wmmps_ac = psta->uapsd_vi & BIT(1);
2266 break;
2267 case 6:
2268 case 7:
2269 wmmps_ac = psta->uapsd_vo & BIT(1);
2270 break;
2271 case 0:
2272 case 3:
2273 default:
2274 wmmps_ac = psta->uapsd_be & BIT(1);
2275 break;
2276 }
2277
2278 if (!wmmps_ac)
2279 continue;
2280
2281 list_del_init(&pxmitframe->list);
2282
2283 psta->sleepq_len--;
2284 psta->sleepq_ac_len--;
2285
2286 if (psta->sleepq_ac_len > 0) {
2287 pxmitframe->attrib.mdata = 1;
2288 pxmitframe->attrib.eosp = 0;
2289 } else {
2290 pxmitframe->attrib.mdata = 0;
2291 pxmitframe->attrib.eosp = 1;
2292 }
2293
2294 pxmitframe->attrib.triggered = 1;
2295
Jes Sorensen638443d2014-05-16 10:04:18 +02002296 rtl8723au_hal_xmitframe_enqueue(padapter, pxmitframe);
Larry Finger5e93f352014-03-28 21:37:38 -05002297
2298 if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) &&
2299 (wmmps_ac)) {
2300 pstapriv->tim_bitmap &= ~CHKBIT(psta->aid);
2301
Masanari Iidac582db42014-07-22 23:42:37 +09002302 /* update BCN for TIM IE */
Jes Sorensen3455f1f2014-04-15 19:43:31 +02002303 update_beacon23a(padapter, WLAN_EID_TIM, NULL, false);
Larry Finger5e93f352014-03-28 21:37:38 -05002304 }
2305 }
2306 spin_unlock_bh(&pxmitpriv->lock);
2307}
2308
2309#endif
2310
2311void rtw_sctx_init23a(struct submit_ctx *sctx, int timeout_ms)
2312{
2313 sctx->timeout_ms = timeout_ms;
2314 init_completion(&sctx->done);
2315 sctx->status = RTW_SCTX_SUBMITTED;
2316}
2317
2318int rtw_sctx_wait23a(struct submit_ctx *sctx)
2319{
2320 int ret = _FAIL;
2321 unsigned long expire;
2322 int status = 0;
2323
2324 expire = sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) :
2325 MAX_SCHEDULE_TIMEOUT;
2326 if (!wait_for_completion_timeout(&sctx->done, expire)) {
2327 /* timeout, do something?? */
2328 status = RTW_SCTX_DONE_TIMEOUT;
2329 DBG_8723A("%s timeout\n", __func__);
2330 } else {
2331 status = sctx->status;
2332 }
2333
2334 if (status == RTW_SCTX_DONE_SUCCESS)
2335 ret = _SUCCESS;
2336
2337 return ret;
2338}
2339
2340static bool rtw_sctx_chk_waring_status(int status)
2341{
2342 switch (status) {
2343 case RTW_SCTX_DONE_UNKNOWN:
2344 case RTW_SCTX_DONE_BUF_ALLOC:
2345 case RTW_SCTX_DONE_BUF_FREE:
2346 case RTW_SCTX_DONE_DRV_STOP:
2347 case RTW_SCTX_DONE_DEV_REMOVE:
2348 return true;
2349 default:
2350 return false;
2351 }
2352}
2353
2354void rtw23a_sctx_done_err(struct submit_ctx **sctx, int status)
2355{
2356 if (*sctx) {
2357 if (rtw_sctx_chk_waring_status(status))
2358 DBG_8723A("%s status:%d\n", __func__, status);
2359 (*sctx)->status = status;
2360 complete(&(*sctx)->done);
2361 *sctx = NULL;
2362 }
2363}
2364
Larry Finger5e93f352014-03-28 21:37:38 -05002365int rtw_ack_tx_wait23a(struct xmit_priv *pxmitpriv, u32 timeout_ms)
2366{
2367 struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops;
2368
2369 pack_tx_ops->timeout_ms = timeout_ms;
2370 pack_tx_ops->status = RTW_SCTX_SUBMITTED;
2371
2372 return rtw_sctx_wait23a(pack_tx_ops);
2373}
2374
2375void rtw_ack_tx_done23a(struct xmit_priv *pxmitpriv, int status)
2376{
2377 struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops;
2378
2379 if (pxmitpriv->ack_tx)
2380 rtw23a_sctx_done_err(&pack_tx_ops, status);
2381 else
2382 DBG_8723A("%s ack_tx not set\n", __func__);
2383}