blob: 4f5efd3eb53fb4b038c545a8c387b65e94f4582e [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Gopichand Nakkala92f07d82013-01-08 21:16:34 -08002 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21/*
Jeff Johnson32d95a32012-09-10 13:15:23 -070022 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jeff Johnson295189b2012-06-20 16:38:30 -070023 *
24 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
25 *
26 *
27 * Permission to use, copy, modify, and/or distribute this software for
28 * any purpose with or without fee is hereby granted, provided that the
29 * above copyright notice and this permission notice appear in all
30 * copies.
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
33 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
35 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
36 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
37 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
38 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
39 * PERFORMANCE OF THIS SOFTWARE.
40 */
41
42/**===========================================================================
43
44 \file wlan_hdd_tx_rx.c
45
46 \brief Linux HDD Tx/RX APIs
47 Copyright 2008 (c) Qualcomm, Incorporated.
48 All Rights Reserved.
49 Qualcomm Confidential and Proprietary.
50
51 ==========================================================================*/
52
53/*---------------------------------------------------------------------------
54 Include files
55 -------------------------------------------------------------------------*/
56#include <wlan_hdd_tx_rx.h>
57#include <wlan_hdd_softap_tx_rx.h>
58#include <wlan_hdd_dp_utils.h>
59#include <wlan_qct_tl.h>
60#include <linux/netdevice.h>
61#include <linux/skbuff.h>
62#include <linux/etherdevice.h>
63
Jeff Johnson295189b2012-06-20 16:38:30 -070064#include <wlan_hdd_p2p.h>
65#include <linux/wireless.h>
66#include <net/cfg80211.h>
67#include <net/ieee80211_radiotap.h>
68#include "sapApi.h"
Jeff Johnson295189b2012-06-20 16:38:30 -070069
Chilam NG571c65a2013-01-19 12:27:36 +053070#ifdef FEATURE_WLAN_TDLS
71#include "wlan_hdd_tdls.h"
72#endif
73
Jeff Johnson295189b2012-06-20 16:38:30 -070074/*---------------------------------------------------------------------------
75 Preprocessor definitions and constants
76 -------------------------------------------------------------------------*/
77
78const v_U8_t hddWmmAcToHighestUp[] = {
79 SME_QOS_WMM_UP_RESV,
80 SME_QOS_WMM_UP_EE,
81 SME_QOS_WMM_UP_VI,
82 SME_QOS_WMM_UP_NC
83};
84
85//Mapping Linux AC interpretation to TL AC.
86const v_U8_t hdd_QdiscAcToTlAC[] = {
87 WLANTL_AC_VO,
88 WLANTL_AC_VI,
89 WLANTL_AC_BE,
90 WLANTL_AC_BK,
91};
92
Jeff Johnson295189b2012-06-20 16:38:30 -070093static struct sk_buff* hdd_mon_tx_fetch_pkt(hdd_adapter_t* pAdapter);
Jeff Johnson295189b2012-06-20 16:38:30 -070094
95/*---------------------------------------------------------------------------
96 Type declarations
97 -------------------------------------------------------------------------*/
98
99/*---------------------------------------------------------------------------
100 Function definitions and documenation
101 -------------------------------------------------------------------------*/
102
103#ifdef DATA_PATH_UNIT_TEST
104//Utility function to dump an sk_buff
105static void dump_sk_buff(struct sk_buff * skb)
106{
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700107 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: head = %p ", __func__, skb->head);
108 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: data = %p ", __func__, skb->data);
109 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: tail = %p ", __func__, skb->tail);
110 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: end = %p ", __func__, skb->end);
111 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: len = %d ", __func__, skb->len);
112 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: data_len = %d ", __func__, skb->data_len);
113 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: mac_len = %d\n", __func__, skb->mac_len);
Jeff Johnson295189b2012-06-20 16:38:30 -0700114
115 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ",
116 skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4],
117 skb->data[5], skb->data[6], skb->data[7]);
118 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
119 skb->data[8], skb->data[9], skb->data[10], skb->data[11], skb->data[12],
120 skb->data[13], skb->data[14], skb->data[15]);
121}
122
123//Function for Unit Test only
124static void transport_thread(hdd_adapter_t *pAdapter)
125{
126 v_U8_t staId;
127 WLANTL_ACEnumType ac = WLANTL_AC_BE;
128 vos_pkt_t *pVosPacket = NULL ;
129 vos_pkt_t dummyPacket;
130 WLANTL_MetaInfoType pktMetaInfo;
131 WLANTL_RxMetaInfoType pktRxMetaInfo;
132 VOS_STATUS status = VOS_STATUS_E_FAILURE;
133
134 status = hdd_tx_fetch_packet_cbk( pAdapter->pvosContext,
135 &staId,
136 &ac,
137 &pVosPacket,
138 &pktMetaInfo );
139 if (status != VOS_STATUS_SUCCESS && status != VOS_STATUS_E_EMPTY)
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700140 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Test FAIL hdd_tx_fetch_packet_cbk", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700141 else
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700142 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Test PASS hdd_tx_fetch_packet_cbk", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700143
Madan Mohan Koyyalamudi4e31b132012-11-02 13:13:52 -0700144 status = hdd_tx_complete_cbk(pAdapter->pvosContext, &dummyPacket, VOS_STATUS_SUCCESS);
Jeff Johnson295189b2012-06-20 16:38:30 -0700145 if (status != VOS_STATUS_SUCCESS)
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700146 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Test FAIL hdd_tx_complete_cbk", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700147 else
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700148 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Test PASS hdd_tx_complete_cbk", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700149
150 status = hdd_tx_low_resource_cbk(pVosPacket, pAdapter);
151 if (status != VOS_STATUS_SUCCESS)
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700152 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Test FAIL hdd_tx_low_resource_cbk", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700153 else
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700154 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Test PASS hdd_tx_low_resource_cbk", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700155
156 status = hdd_rx_packet_cbk( pAdapter->pvosContext,
157 &dummyPacket,
158 staId,
159 &pktRxMetaInfo);
160 if (status != VOS_STATUS_SUCCESS)
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700161 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Test FAIL hdd_rx_packet_cbk", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700162 else
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700163 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Test PASS hdd_rx_packet_cbk", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700164
165}
166#endif
167
168
169/**============================================================================
170 @brief hdd_flush_tx_queues() - Utility function to flush the TX queues
171
172 @param pAdapter : [in] pointer to adapter context
173 @return : VOS_STATUS_E_FAILURE if any errors encountered
174 : VOS_STATUS_SUCCESS otherwise
175 ===========================================================================*/
176static VOS_STATUS hdd_flush_tx_queues( hdd_adapter_t *pAdapter )
177{
178 VOS_STATUS status = VOS_STATUS_SUCCESS;
179 v_SINT_t i = -1;
180 hdd_list_node_t *anchor = NULL;
181 skb_list_node_t *pktNode = NULL;
182 struct sk_buff *skb = NULL;
183
Madan Mohan Koyyalamudifd3b7a92013-10-10 15:02:58 +0530184 pAdapter->isVosLowResource = VOS_FALSE;
185
Jeff Johnson295189b2012-06-20 16:38:30 -0700186 while (++i != NUM_TX_QUEUES)
187 {
188 //Free up any packets in the Tx queue
189 spin_lock_bh(&pAdapter->wmm_tx_queue[i].lock);
190 while (true)
191 {
192 status = hdd_list_remove_front( &pAdapter->wmm_tx_queue[i], &anchor );
193 if(VOS_STATUS_E_EMPTY != status)
194 {
195 pktNode = list_entry(anchor, skb_list_node_t, anchor);
196 skb = pktNode->skb;
197 //TODO
198 //++pAdapter->stats.tx_dropped;
199 ++pAdapter->hdd_stats.hddTxRxStats.txFlushed;
200 ++pAdapter->hdd_stats.hddTxRxStats.txFlushedAC[i];
201 kfree_skb(skb);
202 continue;
203 }
204 break;
205 }
206 spin_unlock_bh(&pAdapter->wmm_tx_queue[i].lock);
207 // backpressure is no longer in effect
208 pAdapter->isTxSuspended[i] = VOS_FALSE;
209 }
210
211 return status;
212}
213
Jeff Johnson295189b2012-06-20 16:38:30 -0700214static struct sk_buff* hdd_mon_tx_fetch_pkt(hdd_adapter_t* pAdapter)
215{
216 skb_list_node_t *pktNode = NULL;
217 struct sk_buff *skb = NULL;
218 v_SIZE_t size = 0;
219 WLANTL_ACEnumType ac = 0;
220 VOS_STATUS status = VOS_STATUS_E_FAILURE;
221 hdd_list_node_t *anchor = NULL;
222
223 if( NULL == pAdapter )
224 {
225 VOS_ASSERT(0);
226 return NULL;
227 }
228
229 // do we have any packets pending in this AC?
230 hdd_list_size( &pAdapter->wmm_tx_queue[ac], &size );
231 if( size == 0 )
232 {
233 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700234 "%s: NO Packet Pending", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700235 return NULL;
236 }
237
238 //Remove the packet from the queue
239 spin_lock_bh(&pAdapter->wmm_tx_queue[ac].lock);
240 status = hdd_list_remove_front( &pAdapter->wmm_tx_queue[ac], &anchor );
241 spin_unlock_bh(&pAdapter->wmm_tx_queue[ac].lock);
242
243 if(VOS_STATUS_SUCCESS == status)
244 {
245 //If success then we got a valid packet from some AC
246 pktNode = list_entry(anchor, skb_list_node_t, anchor);
247 skb = pktNode->skb;
248 }
249 else
250 {
251 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
252 "%s: Not able to remove Packet from the list",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700253 __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700254
255 return NULL;
256 }
257
258 // if we are in a backpressure situation see if we can turn the hose back on
259 if ( (pAdapter->isTxSuspended[ac]) &&
260 (size <= HDD_TX_QUEUE_LOW_WATER_MARK) )
261 {
262 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700263 "%s: TX queue[%d] re-enabled", __func__, ac);
Jeff Johnson295189b2012-06-20 16:38:30 -0700264 pAdapter->isTxSuspended[ac] = VOS_FALSE;
265 /* Enable Queues which we have disabled earlier */
266 netif_tx_start_all_queues( pAdapter->dev );
267 }
268
269 return skb;
270}
271
272void hdd_mon_tx_mgmt_pkt(hdd_adapter_t* pAdapter)
273{
274 hdd_cfg80211_state_t *cfgState;
275 struct sk_buff* skb;
276 hdd_adapter_t* pMonAdapter = NULL;
277 struct ieee80211_hdr *hdr;
278
279 if (pAdapter == NULL )
280 {
281 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
282 "%s: pAdapter is NULL", __func__);
283 return;
284 }
285
286 pMonAdapter = hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_MONITOR );
287
288 cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
289
290 if( NULL != cfgState->buf )
291 {
292 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
293 "%s: Already one MGMT packet Tx going on", __func__);
294 return;
295 }
296
297 skb = hdd_mon_tx_fetch_pkt(pMonAdapter);
298
299 if (NULL == skb)
300 {
301 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
302 "%s: No Packet Pending", __func__);
303 return;
304 }
305
306 cfgState->buf = vos_mem_malloc( skb->len ); //buf;
307 if( cfgState->buf == NULL )
308 {
309 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
310 "%s: Failed to Allocate memory", __func__);
311 goto fail;
312 }
313
314 cfgState->len = skb->len;
315
316 vos_mem_copy( cfgState->buf, skb->data, skb->len);
317
318 cfgState->skb = skb; //buf;
319 cfgState->action_cookie = (tANI_U32)cfgState->buf;
320
321 hdr = (struct ieee80211_hdr *)skb->data;
322 if( (hdr->frame_control & HDD_FRAME_TYPE_MASK)
323 == HDD_FRAME_TYPE_MGMT )
324 {
325 if( (hdr->frame_control & HDD_FRAME_SUBTYPE_MASK)
326 == HDD_FRAME_SUBTYPE_DEAUTH )
327 {
328 hdd_softap_sta_deauth( pAdapter, hdr->addr1 );
329 goto mgmt_handled;
330 }
331 else if( (hdr->frame_control & HDD_FRAME_SUBTYPE_MASK)
332 == HDD_FRAME_SUBTYPE_DISASSOC )
333 {
334 hdd_softap_sta_disassoc( pAdapter, hdr->addr1 );
335 goto mgmt_handled;
336 }
337 }
338 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
339 "%s: Sending action frame to SAP to TX, Len %d", __func__, skb->len);
340
Jeff Johnson43971f52012-07-17 12:26:56 -0700341 if (VOS_STATUS_SUCCESS !=
Jeff Johnson295189b2012-06-20 16:38:30 -0700342 WLANSAP_SendAction( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
Jeff Johnsone7245742012-09-05 17:12:55 -0700343 skb->data, skb->len, 0) )
Jeff Johnson295189b2012-06-20 16:38:30 -0700344 {
345 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
346 "%s: WLANSAP_SendAction returned fail", __func__);
347 hdd_sendActionCnf( pAdapter, FALSE );
348 }
349 return;
350
351mgmt_handled:
352 hdd_sendActionCnf( pAdapter, TRUE );
353 return;
354fail:
355 kfree_skb(pAdapter->skb_to_tx);
356 pAdapter->skb_to_tx = NULL;
357 return;
358}
359
360void hdd_mon_tx_work_queue(struct work_struct *work)
361{
362 hdd_adapter_t* pAdapter = container_of(work, hdd_adapter_t, monTxWorkQueue);
363 hdd_mon_tx_mgmt_pkt(pAdapter);
364}
365
366int hdd_mon_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
367{
368 v_U16_t rt_hdr_len;
369 struct ieee80211_hdr *hdr;
370 hdd_adapter_t *pPgBkAdapter, *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
371 struct ieee80211_radiotap_header *rtap_hdr =
372 (struct ieee80211_radiotap_header *)skb->data;
373
374 /*Supplicant sends the EAPOL packet on monitor interface*/
375 pPgBkAdapter = pAdapter->sessionCtx.monitor.pAdapterForTx;
376 if(pPgBkAdapter == NULL)
377 {
378 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
379 "%s: No Adapter to piggy back. Dropping the pkt on monitor inf",
380 __func__);
381 goto fail; /* too short to be possibly valid */
382 }
383
384 /* check if toal skb length is greater then radio tab header length of not */
385 if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
386 goto fail; /* too short to be possibly valid */
387
388 /* check if radio tap header version is correct or not */
389 if (unlikely(rtap_hdr->it_version))
390 goto fail; /* only version 0 is supported */
391
392 /*Strip off the radio tap header*/
393 rt_hdr_len = ieee80211_get_radiotap_len(skb->data);
394
395 /* check if skb length if greator then total radio tap header length ot not*/
396 if (unlikely(skb->len < rt_hdr_len))
397 goto fail;
398
399 /* Update the trans_start for this netdev */
400 dev->trans_start = jiffies;
401 /*
402 * fix up the pointers accounting for the radiotap
403 * header still being in there.
404 */
405 skb_set_mac_header(skb, rt_hdr_len);
406 skb_set_network_header(skb, rt_hdr_len);
407 skb_set_transport_header(skb, rt_hdr_len);
408
409 /* Pull rtap header out of the skb */
410 skb_pull(skb, rt_hdr_len);
411
412 /*Supplicant adds: radiotap Hdr + radiotap data + 80211 Header. So after
413 * radio tap header and 802.11 header starts
414 */
415 hdr = (struct ieee80211_hdr *)skb->data;
416
417 /* Send data frames through the normal Data path. In this path we will
418 * conver rcvd 802.11 packet to 802.3 packet */
419 if ( (hdr->frame_control & HDD_FRAME_TYPE_MASK) == HDD_FRAME_TYPE_DATA)
420 {
421 v_U8_t da[6];
422 v_U8_t sa[6];
423
424 memcpy (da, hdr->addr1, VOS_MAC_ADDR_SIZE);
425 memcpy (sa, hdr->addr2, VOS_MAC_ADDR_SIZE);
426
427 /* Pull 802.11 MAC header */
428 skb_pull(skb, HDD_80211_HEADER_LEN);
429
430 if ( HDD_FRAME_SUBTYPE_QOSDATA ==
431 (hdr->frame_control & HDD_FRAME_SUBTYPE_MASK))
432 {
433 skb_pull(skb, HDD_80211_HEADER_QOS_CTL);
434 }
435
436 /* Pull LLC header */
437 skb_pull(skb, HDD_LLC_HDR_LEN);
438
439 /* Create space for Ethernet header */
440 skb_push(skb, HDD_MAC_HDR_SIZE*2);
441 memcpy(&skb->data[0], da, HDD_MAC_HDR_SIZE);
442 memcpy(&skb->data[HDD_DEST_ADDR_OFFSET], sa, HDD_MAC_HDR_SIZE);
443
444 /* Only EAPOL Data packets are allowed through monitor interface */
445 if (vos_be16_to_cpu(
446 (*(unsigned short*)&skb->data[HDD_ETHERTYPE_802_1_X_FRAME_OFFSET]) )
447 != HDD_ETHERTYPE_802_1_X)
448 {
449 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
450 "%s: Not a Eapol packet. Drop this frame", __func__);
451 //If not EAPOL frames, drop them.
452 kfree_skb(skb);
453 return NETDEV_TX_OK;
454 }
455
456 skb->protocol = htons(HDD_ETHERTYPE_802_1_X);
457
458 hdd_hostapd_select_queue(pPgBkAdapter->dev, skb);
459 return hdd_softap_hard_start_xmit( skb, pPgBkAdapter->dev );
460 }
461 else
462 {
463 VOS_STATUS status;
464 WLANTL_ACEnumType ac = 0;
465 skb_list_node_t *pktNode = NULL;
466 v_SIZE_t pktListSize = 0;
467
468 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
469 //If we have already reached the max queue size, disable the TX queue
470 if ( pAdapter->wmm_tx_queue[ac].count == pAdapter->wmm_tx_queue[ac].max_size)
471 {
472 /* We want to process one packet at a time, so lets disable all TX queues
473 * and re-enable the queues once we get TX feedback for this packet */
474 netif_tx_stop_all_queues(pAdapter->dev);
475 pAdapter->isTxSuspended[ac] = VOS_TRUE;
476 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
477 return NETDEV_TX_BUSY;
478 }
479 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
480
481 //Use the skb->cb field to hold the list node information
482 pktNode = (skb_list_node_t *)&skb->cb;
483
484 //Stick the OS packet inside this node.
485 pktNode->skb = skb;
486
487 INIT_LIST_HEAD(&pktNode->anchor);
488
489 //Insert the OS packet into the appropriate AC queue
490 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
491 status = hdd_list_insert_back_size( &pAdapter->wmm_tx_queue[ac],
492 &pktNode->anchor, &pktListSize );
493 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
494
495 if ( !VOS_IS_STATUS_SUCCESS( status ) )
496 {
497 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700498 "%s:Insert Tx queue failed. Pkt dropped", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700499 kfree_skb(skb);
500 return NETDEV_TX_OK;
501 }
502
503 if ( pktListSize == 1 )
504 {
505 /* In this context we cannot acquire any mutex etc. And to transmit
506 * this packet we need to call SME API. So to take care of this we will
507 * schedule a workqueue
508 */
509 schedule_work(&pPgBkAdapter->monTxWorkQueue);
510 }
511 return NETDEV_TX_OK;
512 }
513
514fail:
515 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
516 "%s: Packet Rcvd at Monitor interface is not proper,"
517 " Dropping the packet",
518 __func__);
519 kfree_skb(skb);
520 return NETDEV_TX_OK;
521}
Jeff Johnson295189b2012-06-20 16:38:30 -0700522/**============================================================================
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530523 @brief hdd_hard_start_xmit() - Function registered with the Linux OS for
Jeff Johnson295189b2012-06-20 16:38:30 -0700524 transmitting packets. There are 2 versions of this function. One that uses
525 locked queue and other that uses lockless queues. Both have been retained to
526 do some performance testing
527
528 @param skb : [in] pointer to OS packet (sk_buff)
529 @param dev : [in] pointer to Libra network device
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530530
Jeff Johnson295189b2012-06-20 16:38:30 -0700531 @return : NET_XMIT_DROP if packets are dropped
532 : NET_XMIT_SUCCESS if packet is enqueued succesfully
533 ===========================================================================*/
534int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
535{
536 VOS_STATUS status;
537 WLANTL_ACEnumType ac;
538 sme_QosWmmUpType up;
539 skb_list_node_t *pktNode = NULL;
540 hdd_list_node_t *anchor = NULL;
541 v_SIZE_t pktListSize = 0;
542 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
543 v_BOOL_t granted;
Shailender Karmuchia734f332013-04-19 14:02:48 -0700544 v_U8_t STAId = WLAN_MAX_STA_COUNT;
Jeff Johnson295189b2012-06-20 16:38:30 -0700545 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
Jeff Johnson295189b2012-06-20 16:38:30 -0700546 v_BOOL_t txSuspended = VOS_FALSE;
547
548 ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled;
549
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530550 if (unlikely(netif_queue_stopped(dev))) {
Madan Mohan Koyyalamudi87f9a922013-09-25 16:20:07 +0530551 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530552 "%s is called when netif TX is disabled", __func__);
553 return NETDEV_TX_BUSY;
554 }
555
Ravi Joshicc57ed42013-10-12 16:31:25 -0700556 //Get TL AC corresponding to Qdisc queue index/AC.
557 ac = hdd_QdiscAcToTlAC[skb->queue_mapping];
558
559 if (WLAN_HDD_IBSS == pAdapter->device_mode)
Shailender Karmuchia734f332013-04-19 14:02:48 -0700560 {
561 v_MACADDR_t *pDestMacAddress = (v_MACADDR_t*)skb->data;
562
Ravi Joshicc57ed42013-10-12 16:31:25 -0700563 if (eConnectionState_IbssConnected != pHddStaCtx->conn_info.connState)
564 {
565 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
566 "%s: Tx frame in disconnected state in IBSS mode", __func__);
567 ++pAdapter->stats.tx_dropped;
568 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
569 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
570 kfree_skb(skb);
571 return NETDEV_TX_OK;
572 }
573
Shailender Karmuchia734f332013-04-19 14:02:48 -0700574 STAId = *(v_U8_t *)(((v_U8_t *)(skb->data)) - 1);
575
576 if ((STAId == HDD_WLAN_INVALID_STA_ID) &&
577 (vos_is_macaddr_broadcast( pDestMacAddress ) ||
578 vos_is_macaddr_group(pDestMacAddress)))
579 {
580 STAId = IBSS_BROADCAST_STAID;
581 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
582 "%s: BC/MC packet", __func__);
583 }
584 else if (STAId == HDD_WLAN_INVALID_STA_ID)
585 {
Ravi Joshicc57ed42013-10-12 16:31:25 -0700586 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
Shailender Karmuchia734f332013-04-19 14:02:48 -0700587 "%s: Received Unicast frame with invalid staID", __func__);
588 ++pAdapter->stats.tx_dropped;
589 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
Ravi Joshicc57ed42013-10-12 16:31:25 -0700590 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
Shailender Karmuchia734f332013-04-19 14:02:48 -0700591 kfree_skb(skb);
592 return NETDEV_TX_OK;
593 }
594 }
595 else
596 {
597 STAId = pHddStaCtx->conn_info.staId[0];
598 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700599
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530600 //user priority from IP header, which is already extracted and set from
Jeff Johnson295189b2012-06-20 16:38:30 -0700601 //select_queue call back function
602 up = skb->priority;
603
604 ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac];
605
606#ifdef HDD_WMM_DEBUG
607 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700608 "%s: Classified as ac %d up %d", __func__, ac, up);
Jeff Johnson295189b2012-06-20 16:38:30 -0700609#endif // HDD_WMM_DEBUG
610
611 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
Varun Reddy Yeturu5ba69222013-04-01 18:22:20 -0700612 /*CR 463598,384996*/
613 /*For every increment of 10 pkts in the queue, we inform TL about pending pkts.
614 *We check for +1 in the logic,to take care of Zero count which
615 *occurs very frequently in low traffic cases */
616 if((pAdapter->wmm_tx_queue[ac].count + 1) % 10 == 0)
617 {
Shailender Karmuchia734f332013-04-19 14:02:48 -0700618 /* Use the following debug statement during Engineering Debugging.There are chance that this will lead to a Watchdog Bark
Varun Reddy Yeturu5ba69222013-04-01 18:22:20 -0700619 * if it is in the mainline code and if the log level is enabled by someone for debugging
620 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%s:Queue is Filling up.Inform TL again about pending packets", __func__);*/
Shailender Karmuchia734f332013-04-19 14:02:48 -0700621
Ravi Joshi8a934352013-09-25 16:46:58 -0700622 status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
623 STAId, ac
624 );
625 if ( !VOS_IS_STATUS_SUCCESS( status ) )
626 {
627 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
628 "%s: WLANTL_STAPktPending() returned error code %d",
629 __func__, status);
Ravi Joshicc57ed42013-10-12 16:31:25 -0700630 ++pAdapter->stats.tx_dropped;
631 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
632 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
Ravi Joshi8a934352013-09-25 16:46:58 -0700633 kfree_skb(skb);
634 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
635 return NETDEV_TX_OK;
636 }
Varun Reddy Yeturu5ba69222013-04-01 18:22:20 -0700637 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700638 //If we have already reached the max queue size, disable the TX queue
639 if ( pAdapter->wmm_tx_queue[ac].count == pAdapter->wmm_tx_queue[ac].max_size)
640 {
Ravi Joshicc57ed42013-10-12 16:31:25 -0700641 if (WLAN_HDD_IBSS != pAdapter->device_mode)
642 {
643 ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressured;
644 ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressuredAC[ac];
645 netif_tx_stop_queue(netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)));
646 pAdapter->isTxSuspended[ac] = VOS_TRUE;
647 txSuspended = VOS_TRUE;
648 }
649 else
650 {
651 /* In IBSS when a IBSS peer departs, there is no explicit
652 DEAUTH/DISASSOC to detect peer has left the N/W. The only way to
653 detect peer leaving is via heartbeat which is of the order of few
654 seconds. Hence do not back pressure during IBSS as one peer leaving
655 can potentially throttle traffic for other peers in the N/W
656 */
657 ++pAdapter->stats.tx_dropped;
658 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
659 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
660 kfree_skb(skb);
661 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
662 return NETDEV_TX_OK;
663 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700664 }
665
Madan Mohan Koyyalamudifd3b7a92013-10-10 15:02:58 +0530666 /* If 3/4th of the max queue size is used then enable the flag.
667 * This flag indicates to place the DHCP packets in VOICE AC queue.*/
668 if (WLANTL_AC_BE == ac)
669 {
670 if (pAdapter->wmm_tx_queue[ac].count >= HDD_TX_QUEUE_LOW_WATER_MARK)
671 {
672 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
673 "%s: Best Effort AC Tx queue is 3/4th full", __func__);
674 pAdapter->isVosLowResource = VOS_TRUE;
675 }
676 else
677 {
678 pAdapter->isVosLowResource = VOS_FALSE;
679 }
680 }
681
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530682 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
Jeff Johnson295189b2012-06-20 16:38:30 -0700683 if (VOS_TRUE == txSuspended)
684 {
Gopichand Nakkala8fbc3d42013-03-05 21:06:41 -0800685 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530686 "%s: TX queue full for AC=%d Disable OS TX queue",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700687 __func__, ac );
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530688 return NETDEV_TX_BUSY;
Jeff Johnson295189b2012-06-20 16:38:30 -0700689 }
690
691 //Use the skb->cb field to hold the list node information
692 pktNode = (skb_list_node_t *)&skb->cb;
693
694 //Stick the OS packet inside this node.
695 pktNode->skb = skb;
696
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530697 //Stick the User Priority inside this node
Jeff Johnson295189b2012-06-20 16:38:30 -0700698 pktNode->userPriority = up;
699
700
701 INIT_LIST_HEAD(&pktNode->anchor);
702
703 //Insert the OS packet into the appropriate AC queue
704 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
705 status = hdd_list_insert_back_size( &pAdapter->wmm_tx_queue[ac], &pktNode->anchor, &pktListSize );
706 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
707
708 if ( !VOS_IS_STATUS_SUCCESS( status ) )
709 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700710 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s:Insert Tx queue failed. Pkt dropped", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700711 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
712 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
713 ++pAdapter->stats.tx_dropped;
714 kfree_skb(skb);
715 return NETDEV_TX_OK;
716 }
717
718 ++pAdapter->hdd_stats.hddTxRxStats.txXmitQueued;
719 ++pAdapter->hdd_stats.hddTxRxStats.txXmitQueuedAC[ac];
Sudhir Sattayappa Kohalli37620692013-08-05 14:02:26 -0700720 ++pAdapter->hdd_stats.hddTxRxStats.pkt_tx_count;
Jeff Johnson295189b2012-06-20 16:38:30 -0700721
722 //Make sure we have access to this access category
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530723 if (likely(pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed) ||
Jeff Johnson295189b2012-06-20 16:38:30 -0700724 ( pHddStaCtx->conn_info.uIsAuthenticated == VOS_FALSE))
725 {
726 granted = VOS_TRUE;
727 }
728 else
729 {
730 status = hdd_wmm_acquire_access( pAdapter, ac, &granted );
731 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700732 if ( granted && ( pktListSize == 1 ))
733 {
734 //Let TL know we have a packet to send for this AC
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700735 //VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s:Indicating Packet to TL", __func__);
Shailender Karmuchia734f332013-04-19 14:02:48 -0700736 status = WLANTL_STAPktPending(
737 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
738 STAId, ac );
Jeff Johnson295189b2012-06-20 16:38:30 -0700739 if ( !VOS_IS_STATUS_SUCCESS( status ) )
740 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700741 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "%s: Failed to signal TL for AC=%d", __func__, ac );
Jeff Johnson295189b2012-06-20 16:38:30 -0700742
743 //Remove the packet from queue. It must be at the back of the queue, as TX thread cannot preempt us in the middle
744 //as we are in a soft irq context. Also it must be the same packet that we just allocated.
745 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
746 status = hdd_list_remove_back( &pAdapter->wmm_tx_queue[ac], &anchor );
747 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
748 ++pAdapter->stats.tx_dropped;
749 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
750 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
751 kfree_skb(skb);
752 return NETDEV_TX_OK;
753 }
754 }
755
756 dev->trans_start = jiffies;
757
758 return NETDEV_TX_OK;
759}
760
761/**============================================================================
Shailender Karmuchia734f332013-04-19 14:02:48 -0700762 @brief hdd_Ibss_GetStaId() - Get the StationID using the Peer Mac address
763
764 @param pHddStaCtx : [in] pointer to HDD Station Context
765 pMacAddress [in] pointer to Peer Mac address
766 staID [out] pointer to Station Index
767 @return : VOS_STATUS_SUCCESS/VOS_STATUS_E_FAILURE
768 ===========================================================================*/
769
770VOS_STATUS hdd_Ibss_GetStaId(hdd_station_ctx_t *pHddStaCtx, v_MACADDR_t *pMacAddress, v_U8_t *staId)
771{
772 v_U8_t idx;
773
774 for (idx = 0; idx < HDD_MAX_NUM_IBSS_STA; idx++)
775 {
776 if (vos_mem_compare(&pHddStaCtx->conn_info.peerMacAddress[ idx ],
777 pMacAddress, sizeof(v_MACADDR_t)))
778 {
779 *staId = pHddStaCtx->conn_info.staId[idx];
780 return VOS_STATUS_SUCCESS;
781 }
782 }
783
784 return VOS_STATUS_E_FAILURE;
785}
786
787/**============================================================================
Jeff Johnson295189b2012-06-20 16:38:30 -0700788 @brief hdd_tx_timeout() - Function called by OS if there is any
789 timeout during transmission. Since HDD simply enqueues packet
790 and returns control to OS right away, this would never be invoked
791
792 @param dev : [in] pointer to Libra network device
793 @return : None
794 ===========================================================================*/
795void hdd_tx_timeout(struct net_device *dev)
796{
Ravi Joshicc57ed42013-10-12 16:31:25 -0700797 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
798 struct netdev_queue *txq;
799 int i = 0;
800
Jeff Johnson295189b2012-06-20 16:38:30 -0700801 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700802 "%s: Transmission timeout occurred", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700803 //Getting here implies we disabled the TX queues for too long. Queues are
804 //disabled either because of disassociation or low resource scenarios. In
805 //case of disassociation it is ok to ignore this. But if associated, we have
806 //do possible recovery here
Ravi Joshicc57ed42013-10-12 16:31:25 -0700807
808 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
809 "num_bytes AC0: %d AC1: %d AC2: %d AC3: %d",
810 pAdapter->wmm_tx_queue[0].count,
811 pAdapter->wmm_tx_queue[1].count,
812 pAdapter->wmm_tx_queue[2].count,
813 pAdapter->wmm_tx_queue[3].count);
814
815 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
816 "tx_suspend AC0: %d AC1: %d AC2: %d AC3: %d",
817 pAdapter->isTxSuspended[0],
818 pAdapter->isTxSuspended[1],
819 pAdapter->isTxSuspended[2],
820 pAdapter->isTxSuspended[3]);
821
822 for (i = 0; i < 8; i++)
823 {
824 txq = netdev_get_tx_queue(dev, i);
825 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
826 "Queue%d status: %d", i, netif_tx_queue_stopped(txq));
827 }
828
829 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
830 "carrier state: %d", netif_carrier_ok(dev));
Jeff Johnson295189b2012-06-20 16:38:30 -0700831}
832
833
834/**============================================================================
835 @brief hdd_stats() - Function registered with the Linux OS for
836 device TX/RX statistic
837
838 @param dev : [in] pointer to Libra network device
839
840 @return : pointer to net_device_stats structure
841 ===========================================================================*/
842struct net_device_stats* hdd_stats(struct net_device *dev)
843{
844 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
845
846 return &pAdapter->stats;
847}
848
849
850/**============================================================================
851 @brief hdd_init_tx_rx() - Init function to initialize Tx/RX
852 modules in HDD
853
854 @param pAdapter : [in] pointer to adapter context
855 @return : VOS_STATUS_E_FAILURE if any errors encountered
856 : VOS_STATUS_SUCCESS otherwise
857 ===========================================================================*/
858VOS_STATUS hdd_init_tx_rx( hdd_adapter_t *pAdapter )
859{
860 VOS_STATUS status = VOS_STATUS_SUCCESS;
861 v_SINT_t i = -1;
862
863 pAdapter->isVosOutOfResource = VOS_FALSE;
Madan Mohan Koyyalamudifd3b7a92013-10-10 15:02:58 +0530864 pAdapter->isVosLowResource = VOS_FALSE;
Jeff Johnson295189b2012-06-20 16:38:30 -0700865
866 //vos_mem_zero(&pAdapter->stats, sizeof(struct net_device_stats));
867 //Will be zeroed out during alloc
868
869 while (++i != NUM_TX_QUEUES)
870 {
871 pAdapter->isTxSuspended[i] = VOS_FALSE;
872 hdd_list_init( &pAdapter->wmm_tx_queue[i], HDD_TX_QUEUE_MAX_LEN);
873 }
874
875 return status;
876}
877
878
879/**============================================================================
880 @brief hdd_deinit_tx_rx() - Deinit function to clean up Tx/RX
881 modules in HDD
882
883 @param pAdapter : [in] pointer to adapter context
884 @return : VOS_STATUS_E_FAILURE if any errors encountered
885 : VOS_STATUS_SUCCESS otherwise
886 ===========================================================================*/
887VOS_STATUS hdd_deinit_tx_rx( hdd_adapter_t *pAdapter )
888{
889 VOS_STATUS status = VOS_STATUS_SUCCESS;
890 v_SINT_t i = -1;
891
892 status = hdd_flush_tx_queues(pAdapter);
893 while (++i != NUM_TX_QUEUES)
894 {
895 //Free up actual list elements in the Tx queue
896 hdd_list_destroy( &pAdapter->wmm_tx_queue[i] );
897 }
898
899 return status;
900}
901
902
903/**============================================================================
904 @brief hdd_disconnect_tx_rx() - Disconnect function to clean up Tx/RX
905 modules in HDD
906
907 @param pAdapter : [in] pointer to adapter context
908 @return : VOS_STATUS_E_FAILURE if any errors encountered
909 : VOS_STATUS_SUCCESS otherwise
910 ===========================================================================*/
911VOS_STATUS hdd_disconnect_tx_rx( hdd_adapter_t *pAdapter )
912{
913 return hdd_flush_tx_queues(pAdapter);
914}
915
916
917/**============================================================================
918 @brief hdd_IsEAPOLPacket() - Checks the packet is EAPOL or not.
919
920 @param pVosPacket : [in] pointer to vos packet
921 @return : VOS_TRUE if the packet is EAPOL
922 : VOS_FALSE otherwise
923 ===========================================================================*/
924
925v_BOOL_t hdd_IsEAPOLPacket( vos_pkt_t *pVosPacket )
926{
927 VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
928 v_BOOL_t fEAPOL = VOS_FALSE;
929 void *pBuffer = NULL;
930
931
932 vosStatus = vos_pkt_peek_data( pVosPacket, (v_SIZE_t)HDD_ETHERTYPE_802_1_X_FRAME_OFFSET,
933 &pBuffer, HDD_ETHERTYPE_802_1_X_SIZE );
934 if (VOS_IS_STATUS_SUCCESS( vosStatus ) )
935 {
936 if ( vos_be16_to_cpu( *(unsigned short*)pBuffer ) == HDD_ETHERTYPE_802_1_X )
937 {
938 fEAPOL = VOS_TRUE;
939 }
940 }
941
942 return fEAPOL;
943}
944
945
946#ifdef FEATURE_WLAN_WAPI // Need to update this function
947/**============================================================================
948 @brief hdd_IsWAIPacket() - Checks the packet is WAI or not.
949
950 @param pVosPacket : [in] pointer to vos packet
951 @return : VOS_TRUE if the packet is WAI
952 : VOS_FALSE otherwise
953 ===========================================================================*/
954
955v_BOOL_t hdd_IsWAIPacket( vos_pkt_t *pVosPacket )
956{
957 VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
958 v_BOOL_t fIsWAI = VOS_FALSE;
959 void *pBuffer = NULL;
960
961 // Need to update this function
962 vosStatus = vos_pkt_peek_data( pVosPacket, (v_SIZE_t)HDD_ETHERTYPE_802_1_X_FRAME_OFFSET,
963 &pBuffer, HDD_ETHERTYPE_802_1_X_SIZE );
964
965 if (VOS_IS_STATUS_SUCCESS( vosStatus ) )
966 {
967 if ( vos_be16_to_cpu( *(unsigned short*)pBuffer ) == HDD_ETHERTYPE_WAI)
968 {
969 fIsWAI = VOS_TRUE;
970 }
971 }
972
973 return fIsWAI;
974}
975#endif /* FEATURE_WLAN_WAPI */
976
977/**============================================================================
978 @brief hdd_tx_complete_cbk() - Callback function invoked by TL
979 to indicate that a packet has been transmitted across the SDIO bus
980 succesfully. OS packet resources can be released after this cbk.
981
982 @param vosContext : [in] pointer to VOS context
983 @param pVosPacket : [in] pointer to VOS packet (containing skb)
984 @param vosStatusIn : [in] status of the transmission
985
986 @return : VOS_STATUS_E_FAILURE if any errors encountered
987 : VOS_STATUS_SUCCESS otherwise
988 ===========================================================================*/
989VOS_STATUS hdd_tx_complete_cbk( v_VOID_t *vosContext,
990 vos_pkt_t *pVosPacket,
991 VOS_STATUS vosStatusIn )
992{
993 VOS_STATUS status = VOS_STATUS_SUCCESS;
994 hdd_adapter_t *pAdapter = NULL;
995 hdd_context_t *pHddCtx = NULL;
996 void* pOsPkt = NULL;
997
998 if( ( NULL == vosContext ) || ( NULL == pVosPacket ) )
999 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001000 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Null params being passed", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001001 return VOS_STATUS_E_FAILURE;
1002 }
1003
1004 //Return the skb to the OS
1005 status = vos_pkt_get_os_packet( pVosPacket, &pOsPkt, VOS_TRUE );
1006 if(!VOS_IS_STATUS_SUCCESS( status ))
1007 {
1008 //This is bad but still try to free the VOSS resources if we can
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001009 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Failure extracting skb from vos pkt", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001010 vos_pkt_return_packet( pVosPacket );
1011 return VOS_STATUS_E_FAILURE;
1012 }
1013
1014 //Get the HDD context.
1015 pHddCtx = (hdd_context_t *)vos_get_context( VOS_MODULE_ID_HDD, vosContext );
1016 //Get the Adapter context.
1017 pAdapter = hdd_get_adapter(pHddCtx,WLAN_HDD_INFRA_STATION);
1018 if(pAdapter == NULL)
1019 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001020 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001021 }
1022 else
1023 {
1024 ++pAdapter->hdd_stats.hddTxRxStats.txCompleted;
1025 }
1026
1027 kfree_skb((struct sk_buff *)pOsPkt);
1028
1029 //Return the VOS packet resources.
1030 status = vos_pkt_return_packet( pVosPacket );
1031 if(!VOS_IS_STATUS_SUCCESS( status ))
1032 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001033 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Could not return VOS packet to the pool", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001034 }
1035
1036 return status;
1037}
1038
1039
1040/**============================================================================
1041 @brief hdd_tx_fetch_packet_cbk() - Callback function invoked by TL to
1042 fetch a packet for transmission.
1043
1044 @param vosContext : [in] pointer to VOS context
1045 @param staId : [in] Station for which TL is requesting a pkt
1046 @param ac : [in] access category requested by TL
1047 @param pVosPacket : [out] pointer to VOS packet packet pointer
1048 @param pPktMetaInfo : [out] pointer to meta info for the pkt
1049
1050 @return : VOS_STATUS_E_EMPTY if no packets to transmit
1051 : VOS_STATUS_E_FAILURE if any errors encountered
1052 : VOS_STATUS_SUCCESS otherwise
1053 ===========================================================================*/
1054VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext,
1055 v_U8_t *pStaId,
1056 WLANTL_ACEnumType ac,
1057 vos_pkt_t **ppVosPacket,
1058 WLANTL_MetaInfoType *pPktMetaInfo )
1059{
1060 VOS_STATUS status = VOS_STATUS_E_FAILURE;
1061 hdd_adapter_t *pAdapter = NULL;
1062 hdd_context_t *pHddCtx = NULL;
1063 hdd_list_node_t *anchor = NULL;
1064 skb_list_node_t *pktNode = NULL;
1065 struct sk_buff *skb = NULL;
1066 vos_pkt_t *pVosPacket = NULL;
1067 v_MACADDR_t* pDestMacAddress = NULL;
1068 v_TIME_t timestamp;
1069 WLANTL_ACEnumType newAc;
1070 v_SIZE_t size = 0;
1071 tANI_U8 acAdmitted, i;
1072
1073 //Sanity check on inputs
1074 if ( ( NULL == vosContext ) ||
1075 ( NULL == pStaId ) ||
1076 ( NULL == ppVosPacket ) ||
1077 ( NULL == pPktMetaInfo ) )
1078 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001079 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Null Params being passed", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001080 return VOS_STATUS_E_FAILURE;
1081 }
1082
1083 //Get the HDD context.
1084 pHddCtx = (hdd_context_t *)vos_get_context( VOS_MODULE_ID_HDD, vosContext );
1085 if(pHddCtx == NULL)
1086 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001087 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001088 return VOS_STATUS_E_FAILURE;
1089 }
1090
1091 pAdapter = pHddCtx->sta_to_adapter[*pStaId];
1092 if( NULL == pAdapter )
1093 {
1094 VOS_ASSERT(0);
1095 return VOS_STATUS_E_FAILURE;
1096 }
1097
1098 ++pAdapter->hdd_stats.hddTxRxStats.txFetched;
1099
1100 *ppVosPacket = NULL;
1101
1102 //Make sure the AC being asked for is sane
1103 if( ac >= WLANTL_MAX_AC || ac < 0)
1104 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001105 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Invalid AC %d passed by TL", __func__, ac);
Jeff Johnson295189b2012-06-20 16:38:30 -07001106 return VOS_STATUS_E_FAILURE;
1107 }
1108
1109 ++pAdapter->hdd_stats.hddTxRxStats.txFetchedAC[ac];
1110
1111#ifdef HDD_WMM_DEBUG
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001112 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,"%s: AC %d passed by TL", __func__, ac);
Jeff Johnson295189b2012-06-20 16:38:30 -07001113#endif // HDD_WMM_DEBUG
1114
1115 // We find an AC with packets
1116 // or we determine we have no more packets to send
1117 // HDD is not allowed to change AC.
1118
1119 // has this AC been admitted? or
1120 // To allow EAPOL packets when not authenticated
1121 if (unlikely((0==pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed) &&
1122 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.uIsAuthenticated))
1123 {
1124 ++pAdapter->hdd_stats.hddTxRxStats.txFetchEmpty;
1125#ifdef HDD_WMM_DEBUG
1126 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001127 "%s: no packets pending", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001128#endif // HDD_WMM_DEBUG
1129 return VOS_STATUS_E_FAILURE;
1130 }
1131
1132 // do we have any packets pending in this AC?
1133 hdd_list_size( &pAdapter->wmm_tx_queue[ac], &size );
1134 if( size > 0 )
1135 {
1136 // yes, so process it
1137#ifdef HDD_WMM_DEBUG
1138 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001139 "%s: AC %d has packets pending", __func__, ac);
Jeff Johnson295189b2012-06-20 16:38:30 -07001140#endif // HDD_WMM_DEBUG
1141 }
1142 else
1143 {
1144 ++pAdapter->hdd_stats.hddTxRxStats.txFetchEmpty;
1145#ifdef HDD_WMM_DEBUG
1146 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001147 "%s: no packets pending", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001148#endif // HDD_WMM_DEBUG
1149 return VOS_STATUS_E_FAILURE;
1150 }
1151
1152 //Get the vos packet. I don't want to dequeue and enqueue again if we are out of VOS resources
1153 //This simplifies the locking and unlocking of Tx queue
1154 status = vos_pkt_wrap_data_packet( &pVosPacket,
1155 VOS_PKT_TYPE_TX_802_3_DATA,
1156 NULL, //OS Pkt is not being passed
1157 hdd_tx_low_resource_cbk,
1158 pAdapter );
1159
1160 if (status == VOS_STATUS_E_ALREADY || status == VOS_STATUS_E_RESOURCES)
1161 {
1162 //Remember VOS is in a low resource situation
1163 pAdapter->isVosOutOfResource = VOS_TRUE;
1164 ++pAdapter->hdd_stats.hddTxRxStats.txFetchLowResources;
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001165 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s: VOSS in Low Resource scenario", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001166 //TL will now think we have no more packets in this AC
1167 return VOS_STATUS_E_FAILURE;
1168 }
1169
1170 //Remove the packet from the queue
1171 spin_lock_bh(&pAdapter->wmm_tx_queue[ac].lock);
1172 status = hdd_list_remove_front( &pAdapter->wmm_tx_queue[ac], &anchor );
1173 spin_unlock_bh(&pAdapter->wmm_tx_queue[ac].lock);
1174
1175 if(VOS_STATUS_SUCCESS == status)
1176 {
1177 //If success then we got a valid packet from some AC
1178 pktNode = list_entry(anchor, skb_list_node_t, anchor);
1179 skb = pktNode->skb;
1180 }
1181 else
1182 {
1183 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError;
Madan Mohan Koyyalamudi60a6a8d2012-10-21 11:57:42 -07001184 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "%s: Error in de-queuing "
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001185 "skb from Tx queue status = %d", __func__, status );
Jeff Johnson295189b2012-06-20 16:38:30 -07001186 vos_pkt_return_packet(pVosPacket);
1187 return VOS_STATUS_E_FAILURE;
1188 }
1189
1190 //Attach skb to VOS packet.
1191 status = vos_pkt_set_os_packet( pVosPacket, skb );
1192 if (status != VOS_STATUS_SUCCESS)
1193 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001194 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s: Error attaching skb", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001195 vos_pkt_return_packet(pVosPacket);
1196 ++pAdapter->stats.tx_dropped;
1197 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError;
1198 kfree_skb(skb);
1199 return VOS_STATUS_E_FAILURE;
1200 }
1201
1202 //Just being paranoid. To be removed later
1203 if(pVosPacket == NULL)
1204 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001205 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s: VOS packet returned by VOSS is NULL", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001206 ++pAdapter->stats.tx_dropped;
1207 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError;
1208 kfree_skb(skb);
1209 return VOS_STATUS_E_FAILURE;
1210 }
1211
Chilam NG571c65a2013-01-19 12:27:36 +05301212#ifdef FEATURE_WLAN_TDLS
Gopichand Nakkala4ddf0192013-03-27 13:41:20 -07001213 if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode)
Chilam NG571c65a2013-01-19 12:27:36 +05301214 {
1215 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
Chilam NG571c65a2013-01-19 12:27:36 +05301216 u8 mac[6];
1217
Hoonki Lee387663d2013-02-05 18:08:43 -08001218 wlan_hdd_tdls_extract_da(skb, mac);
Chilam NG571c65a2013-01-19 12:27:36 +05301219
Hoonki Lee5fcc4582013-02-05 20:28:26 -08001220 if (vos_is_macaddr_group((v_MACADDR_t *)mac)) {
Chilam NG571c65a2013-01-19 12:27:36 +05301221 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1222 "broadcast packet, not adding to peer list");
1223 } else if (memcmp(pHddStaCtx->conn_info.bssId,
1224 mac, 6) != 0) {
1225 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
Gopichand Nakkala4ddf0192013-03-27 13:41:20 -07001226 "extract mac: " MAC_ADDRESS_STR,
1227 MAC_ADDR_ARRAY(mac) );
Chilam NG571c65a2013-01-19 12:27:36 +05301228
Gopichand Nakkala4327a152013-03-04 23:22:42 -08001229 wlan_hdd_tdls_increment_pkt_count(pAdapter, mac, 1);
Chilam NG571c65a2013-01-19 12:27:36 +05301230 } else {
1231 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1232 "packet da is bssid, not adding to peer list");
1233 }
1234 }
1235#endif
1236
Jeff Johnson295189b2012-06-20 16:38:30 -07001237 //Return VOS packet to TL;
1238 *ppVosPacket = pVosPacket;
1239
1240 //Fill out the meta information needed by TL
1241 //FIXME This timestamp is really the time stamp of wrap_data_packet
1242 vos_pkt_get_timestamp( pVosPacket, &timestamp );
1243 pPktMetaInfo->usTimeStamp = (v_U16_t)timestamp;
1244
1245 if(pAdapter->sessionCtx.station.conn_info.uIsAuthenticated == VOS_TRUE)
1246 pPktMetaInfo->ucIsEapol = 0;
1247 else
1248 pPktMetaInfo->ucIsEapol = hdd_IsEAPOLPacket( pVosPacket ) ? 1 : 0;
1249
1250#ifdef FEATURE_WLAN_WAPI
1251 // Override usIsEapol value when its zero for WAPI case
1252 pPktMetaInfo->ucIsWai = hdd_IsWAIPacket( pVosPacket ) ? 1 : 0;
1253#endif /* FEATURE_WLAN_WAPI */
1254
1255 if ((HDD_WMM_USER_MODE_NO_QOS == pHddCtx->cfg_ini->WmmMode) ||
1256 (!pAdapter->hddWmmStatus.wmmQap))
1257 {
1258 // either we don't want QoS or the AP doesn't support QoS
1259 pPktMetaInfo->ucUP = 0;
1260 pPktMetaInfo->ucTID = 0;
1261 }
1262 else
1263 {
1264 /* 1. Check if ACM is set for this AC
1265 * 2. If set, check if this AC had already admitted
1266 * 3. If not already admitted, downgrade the UP to next best UP */
1267 if(!pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessRequired ||
1268 pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcTspecValid)
1269 {
1270 pPktMetaInfo->ucUP = pktNode->userPriority;
1271 pPktMetaInfo->ucTID = pPktMetaInfo->ucUP;
1272 }
1273 else
1274 {
1275 //Downgrade the UP
1276 acAdmitted = pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcTspecValid;
1277 newAc = WLANTL_AC_BK;
1278 for (i=ac-1; i>0; i--)
1279 {
1280 if (pAdapter->hddWmmStatus.wmmAcStatus[i].wmmAcAccessRequired == 0)
1281 {
1282 newAc = i;
1283 break;
1284 }
1285 }
1286 pPktMetaInfo->ucUP = hddWmmAcToHighestUp[newAc];
1287 pPktMetaInfo->ucTID = pPktMetaInfo->ucUP;
1288 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,"Downgrading UP %d to UP %d ", pktNode->userPriority, pPktMetaInfo->ucUP);
1289 }
1290 }
1291
1292 pPktMetaInfo->ucType = 0; //FIXME Don't know what this is
1293 pPktMetaInfo->ucDisableFrmXtl = 0; //802.3 frame so we need to xlate
1294 if ( 1 < size )
1295 {
1296 pPktMetaInfo->bMorePackets = 1; //HDD has more packets to send
1297 }
1298 else
1299 {
1300 pPktMetaInfo->bMorePackets = 0;
1301 }
1302
1303 //Extract the destination address from ethernet frame
1304 pDestMacAddress = (v_MACADDR_t*)skb->data;
1305 pPktMetaInfo->ucBcast = vos_is_macaddr_broadcast( pDestMacAddress ) ? 1 : 0;
1306 pPktMetaInfo->ucMcast = vos_is_macaddr_group( pDestMacAddress ) ? 1 : 0;
1307
1308
1309
1310 // if we are in a backpressure situation see if we can turn the hose back on
1311 if ( (pAdapter->isTxSuspended[ac]) &&
1312 (size <= HDD_TX_QUEUE_LOW_WATER_MARK) )
1313 {
1314 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDePressured;
1315 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDePressuredAC[ac];
Gopichand Nakkala8fbc3d42013-03-05 21:06:41 -08001316 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001317 "%s: TX queue[%d] re-enabled", __func__, ac);
Jeff Johnson295189b2012-06-20 16:38:30 -07001318 pAdapter->isTxSuspended[ac] = VOS_FALSE;
1319 netif_tx_wake_queue(netdev_get_tx_queue(pAdapter->dev,
1320 skb_get_queue_mapping(skb) ));
1321 }
1322
1323
1324 // We're giving the packet to TL so consider it transmitted from
1325 // a statistics perspective. We account for it here instead of
1326 // when the packet is returned for two reasons. First, TL will
1327 // manipulate the skb to the point where the len field is not
1328 // accurate, leading to inaccurate byte counts if we account for
1329 // it later. Second, TL does not provide any feedback as to
1330 // whether or not the packet was successfully sent over the air,
1331 // so the packet counts will be the same regardless of where we
1332 // account for them
1333 pAdapter->stats.tx_bytes += skb->len;
1334 ++pAdapter->stats.tx_packets;
1335 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeued;
1336 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeuedAC[ac];
1337
Leo Chang50bbd252013-04-25 14:58:01 -07001338 if((pHddCtx->cfg_ini->thermalMitigationEnable) &&
1339 (WLAN_HDD_INFRA_STATION == pAdapter->device_mode))
Jeff Johnson295189b2012-06-20 16:38:30 -07001340 {
1341 if(mutex_lock_interruptible(&pHddCtx->tmInfo.tmOperationLock))
1342 {
1343 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001344 "%s: Tm Lock fail", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001345 return VOS_STATUS_E_FAILURE;
1346 }
1347 if(WLAN_HDD_TM_LEVEL_1 < pHddCtx->tmInfo.currentTmLevel)
1348 {
1349 if(0 == pHddCtx->tmInfo.txFrameCount)
1350 {
1351 /* Just recovered from sleep timeout */
1352 pHddCtx->tmInfo.lastOpenTs = timestamp;
1353 }
1354
Leo Chang50bbd252013-04-25 14:58:01 -07001355 if((VOS_FALSE == pHddCtx->tmInfo.qBlocked) &&
1356 ((timestamp - pHddCtx->tmInfo.lastOpenTs) > (pHddCtx->tmInfo.tmAction.txOperationDuration / 10)) &&
Jeff Johnson295189b2012-06-20 16:38:30 -07001357 (pHddCtx->tmInfo.txFrameCount >= pHddCtx->tmInfo.tmAction.txBlockFrameCountThreshold))
1358 {
Jeff Johnson295189b2012-06-20 16:38:30 -07001359 /* During TX open duration, TX frame count is larger than threshold
1360 * Block TX during Sleep time */
1361 netif_tx_stop_all_queues(pAdapter->dev);
Leo Chang50bbd252013-04-25 14:58:01 -07001362 pHddCtx->tmInfo.qBlocked = VOS_TRUE;
Jeff Johnson295189b2012-06-20 16:38:30 -07001363 pHddCtx->tmInfo.lastblockTs = timestamp;
1364 if(VOS_TIMER_STATE_STOPPED == vos_timer_getCurrentState(&pHddCtx->tmInfo.txSleepTimer))
1365 {
1366 vos_timer_start(&pHddCtx->tmInfo.txSleepTimer, pHddCtx->tmInfo.tmAction.txSleepDuration);
1367 }
1368 }
1369 else if(((timestamp - pHddCtx->tmInfo.lastOpenTs) > (pHddCtx->tmInfo.tmAction.txOperationDuration / 10)) &&
1370 (pHddCtx->tmInfo.txFrameCount < pHddCtx->tmInfo.tmAction.txBlockFrameCountThreshold))
1371 {
1372 /* During TX open duration, TX frame count is less than threshold
1373 * Reset count and timestamp to prepare next cycle */
1374 pHddCtx->tmInfo.lastOpenTs = timestamp;
1375 pHddCtx->tmInfo.txFrameCount = 0;
1376 }
1377 else
1378 {
1379 /* Do Nothing */
1380 }
1381 pHddCtx->tmInfo.txFrameCount++;
1382 }
1383 mutex_unlock(&pHddCtx->tmInfo.tmOperationLock);
1384 }
1385
1386
1387#ifdef HDD_WMM_DEBUG
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001388 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,"%s: Valid VOS PKT returned to TL", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001389#endif // HDD_WMM_DEBUG
1390
1391 return status;
1392}
1393
1394
1395/**============================================================================
1396 @brief hdd_tx_low_resource_cbk() - Callback function invoked in the
1397 case where VOS packets are not available at the time of the call to get
1398 packets. This callback function is invoked by VOS when packets are
1399 available.
1400
1401 @param pVosPacket : [in] pointer to VOS packet
1402 @param userData : [in] opaque user data that was passed initially
1403
1404 @return : VOS_STATUS_E_FAILURE if any errors encountered,
1405 : VOS_STATUS_SUCCESS otherwise
1406 =============================================================================*/
1407VOS_STATUS hdd_tx_low_resource_cbk( vos_pkt_t *pVosPacket,
1408 v_VOID_t *userData )
1409{
1410 VOS_STATUS status;
1411 v_SINT_t i = 0;
1412 v_SIZE_t size = 0;
1413 hdd_adapter_t* pAdapter = (hdd_adapter_t *)userData;
1414
1415 if(pAdapter == NULL)
1416 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001417 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001418 return VOS_STATUS_E_FAILURE;
1419 }
1420
1421 //Return the packet to VOS. We just needed to know that VOS is out of low resource
1422 //situation. Here we will only signal TL that there is a pending data for a STA.
1423 //VOS packet will be requested (if needed) when TL comes back to fetch data.
1424 vos_pkt_return_packet( pVosPacket );
1425
1426 pAdapter->isVosOutOfResource = VOS_FALSE;
1427
1428 //Indicate to TL that there is pending data if a queue is non empty
1429 for( i=NUM_TX_QUEUES-1; i>=0; --i )
1430 {
1431 size = 0;
1432 hdd_list_size( &pAdapter->wmm_tx_queue[i], &size );
1433 if ( size > 0 )
1434 {
1435 status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
1436 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId [0],
1437 (WLANTL_ACEnumType)i );
1438 if( !VOS_IS_STATUS_SUCCESS( status ) )
1439 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001440 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Failure in indicating pkt to TL for ac=%d", __func__,i);
Jeff Johnson295189b2012-06-20 16:38:30 -07001441 }
1442 }
1443 }
1444
1445 return VOS_STATUS_SUCCESS;
1446}
1447
1448
1449/**============================================================================
1450 @brief hdd_rx_packet_cbk() - Receive callback registered with TL.
1451 TL will call this to notify the HDD when one or more packets were
1452 received for a registered STA.
1453
1454 @param vosContext : [in] pointer to VOS context
1455 @param pVosPacketChain : [in] pointer to VOS packet chain
1456 @param staId : [in] Station Id
1457 @param pRxMetaInfo : [in] pointer to meta info for the received pkt(s)
1458
1459 @return : VOS_STATUS_E_FAILURE if any errors encountered,
1460 : VOS_STATUS_SUCCESS otherwise
1461 ===========================================================================*/
1462VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext,
1463 vos_pkt_t *pVosPacketChain,
1464 v_U8_t staId,
1465 WLANTL_RxMetaInfoType* pRxMetaInfo )
1466{
1467 hdd_adapter_t *pAdapter = NULL;
1468 hdd_context_t *pHddCtx = NULL;
1469 VOS_STATUS status = VOS_STATUS_E_FAILURE;
1470 int rxstat;
1471 struct sk_buff *skb = NULL;
1472 vos_pkt_t* pVosPacket;
1473 vos_pkt_t* pNextVosPacket;
1474
1475 //Sanity check on inputs
1476 if ( ( NULL == vosContext ) ||
1477 ( NULL == pVosPacketChain ) ||
1478 ( NULL == pRxMetaInfo ) )
1479 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001480 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Null params being passed", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001481 return VOS_STATUS_E_FAILURE;
1482 }
1483
1484 pHddCtx = (hdd_context_t *)vos_get_context( VOS_MODULE_ID_HDD, vosContext );
1485 if ( NULL == pHddCtx )
1486 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001487 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001488 return VOS_STATUS_E_FAILURE;
1489 }
1490
1491 pAdapter = pHddCtx->sta_to_adapter[staId];
1492 if( NULL == pAdapter )
1493 {
Madan Mohan Koyyalamudi858bb362013-08-05 19:57:37 +05301494 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: pAdapter is Null for staId %u",
1495 __func__, staId);
Jeff Johnson295189b2012-06-20 16:38:30 -07001496 return VOS_STATUS_E_FAILURE;
1497 }
1498
1499 ++pAdapter->hdd_stats.hddTxRxStats.rxChains;
1500
1501 // walk the chain until all are processed
1502 pVosPacket = pVosPacketChain;
1503 do
1504 {
1505 // get the pointer to the next packet in the chain
1506 // (but don't unlink the packet since we free the entire chain later)
1507 status = vos_pkt_walk_packet_chain( pVosPacket, &pNextVosPacket, VOS_FALSE);
1508
1509 // both "success" and "empty" are acceptable results
1510 if (!((status == VOS_STATUS_SUCCESS) || (status == VOS_STATUS_E_EMPTY)))
1511 {
1512 ++pAdapter->hdd_stats.hddTxRxStats.rxDropped;
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001513 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Failure walking packet chain", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001514 return VOS_STATUS_E_FAILURE;
1515 }
1516
1517 // Extract the OS packet (skb).
1518 // Tell VOS to detach the OS packet from the VOS packet
1519 status = vos_pkt_get_os_packet( pVosPacket, (v_VOID_t **)&skb, VOS_TRUE );
1520 if(!VOS_IS_STATUS_SUCCESS( status ))
1521 {
1522 ++pAdapter->hdd_stats.hddTxRxStats.rxDropped;
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001523 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Failure extracting skb from vos pkt", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001524 return VOS_STATUS_E_FAILURE;
1525 }
Jeff Johnsone7245742012-09-05 17:12:55 -07001526
1527 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
1528 {
1529 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
1530 "Magic cookie(%x) for adapter sanity verification is invalid", pAdapter->magic);
1531 return eHAL_STATUS_FAILURE;
1532 }
1533
Chilam Ng1279e232013-01-25 15:06:52 -08001534#ifdef FEATURE_WLAN_TDLS
Gopichand Nakkala4ddf0192013-03-27 13:41:20 -07001535 if ((eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode) &&
1536 0 != pHddCtx->connected_peer_count)
Chilam Ng1279e232013-01-25 15:06:52 -08001537 {
1538 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
Chilam Ng1279e232013-01-25 15:06:52 -08001539 u8 mac[6];
1540
Hoonki Lee387663d2013-02-05 18:08:43 -08001541 wlan_hdd_tdls_extract_sa(skb, mac);
Chilam Ng1279e232013-01-25 15:06:52 -08001542
Hoonki Lee5fcc4582013-02-05 20:28:26 -08001543 if (vos_is_macaddr_group((v_MACADDR_t *)mac)) {
Chilam Ng1279e232013-01-25 15:06:52 -08001544 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1545 "rx broadcast packet, not adding to peer list");
1546 } else if (memcmp(pHddStaCtx->conn_info.bssId,
1547 mac, 6) != 0) {
Shailender Karmuchi13c0d082013-03-26 14:41:39 -07001548 hddTdlsPeer_t *curr_peer;
Chilam Ng1279e232013-01-25 15:06:52 -08001549 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
Shailender Karmuchi13c0d082013-03-26 14:41:39 -07001550 "rx extract mac:" MAC_ADDRESS_STR,
1551 MAC_ADDR_ARRAY(mac) );
Madan Mohan Koyyalamudi96797442013-10-08 16:04:42 +05301552 curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, TRUE);
Gopichand Nakkala4a2fc1a2013-05-17 16:59:39 +05301553 if ((NULL != curr_peer) && (eTDLS_LINK_CONNECTED == curr_peer->link_status)
1554 && (TRUE == pRxMetaInfo->isStaTdls))
Shailender Karmuchi13c0d082013-03-26 14:41:39 -07001555 {
1556 wlan_hdd_tdls_increment_pkt_count(pAdapter, mac, 0);
1557 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"rssi is %d", pRxMetaInfo->rssiAvg);
1558 wlan_hdd_tdls_set_rssi (pAdapter, mac, pRxMetaInfo->rssiAvg);
1559 }
Chilam Ng1279e232013-01-25 15:06:52 -08001560 } else {
1561 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1562 "rx packet sa is bssid, not adding to peer list");
1563 }
1564 }
1565#endif
1566
Jeff Johnson295189b2012-06-20 16:38:30 -07001567 skb->dev = pAdapter->dev;
1568 skb->protocol = eth_type_trans(skb, skb->dev);
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001569 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnson295189b2012-06-20 16:38:30 -07001570 ++pAdapter->hdd_stats.hddTxRxStats.rxPackets;
1571 ++pAdapter->stats.rx_packets;
1572 pAdapter->stats.rx_bytes += skb->len;
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001573#ifdef WLAN_OPEN_SOURCE
Jeff Johnsone7245742012-09-05 17:12:55 -07001574#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
Amar Singhal6144c002013-05-03 16:11:42 -07001575 wake_lock_timeout(&pHddCtx->rx_wake_lock, msecs_to_jiffies(HDD_WAKE_LOCK_DURATION));
Jeff Johnsone7245742012-09-05 17:12:55 -07001576#endif
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001577#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001578 rxstat = netif_rx_ni(skb);
1579 if (NET_RX_SUCCESS == rxstat)
1580 {
1581 ++pAdapter->hdd_stats.hddTxRxStats.rxDelivered;
Sudhir Sattayappa Kohalli37620692013-08-05 14:02:26 -07001582 ++pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count;
Jeff Johnson295189b2012-06-20 16:38:30 -07001583 }
1584 else
1585 {
1586 ++pAdapter->hdd_stats.hddTxRxStats.rxRefused;
1587 }
1588 // now process the next packet in the chain
1589 pVosPacket = pNextVosPacket;
1590
1591 } while (pVosPacket);
1592
1593 //Return the entire VOS packet chain to the resource pool
1594 status = vos_pkt_return_packet( pVosPacketChain );
1595 if(!VOS_IS_STATUS_SUCCESS( status ))
1596 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001597 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Failure returning vos pkt", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001598 }
1599
1600 pAdapter->dev->last_rx = jiffies;
1601
1602 return status;
1603}
Sudhir Sattayappa Kohalli37620692013-08-05 14:02:26 -07001604/**============================================================================
1605 @brief hdd_tx_rx_pkt_cnt_stat_timer_handler() -
1606 Enable/Disable split scan based on TX and RX traffic.
1607 @param HddContext : [in] pointer to Hdd context
1608 @return : None
1609 ===========================================================================*/
1610void hdd_tx_rx_pkt_cnt_stat_timer_handler( void *phddctx)
1611{
1612 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
1613 hdd_adapter_t *pAdapter = NULL;
1614 hdd_station_ctx_t *pHddStaCtx = NULL;
1615 hdd_context_t *pHddCtx = (hdd_context_t *)phddctx;
1616 hdd_config_t *cfg_param = pHddCtx->cfg_ini;
1617 VOS_STATUS status;
1618 v_U8_t staId = 0;
1619 v_U8_t fconnected = 0;
1620
1621 if (!cfg_param->dynSplitscan)
1622 {
1623 hddLog(VOS_TRACE_LEVEL_INFO,
1624 "%s: Error : Dynamic split scan is not Enabled : %d",
1625 __func__, pHddCtx->cfg_ini->dynSplitscan);
1626 return;
1627 }
1628
1629 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
1630 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
1631 {
1632 pAdapter = pAdapterNode->pAdapter;
1633
1634 if ( pAdapter )
1635 {
1636 hddLog(VOS_TRACE_LEVEL_INFO,
1637 "%s: Adapter with device mode %d exists",
1638 __func__, pAdapter->device_mode);
1639
1640 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
1641 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode))
1642 {
1643 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
1644 if ((eConnectionState_Associated ==
1645 pHddStaCtx->conn_info.connState) &&
1646 (VOS_TRUE == pHddStaCtx->conn_info.uIsAuthenticated))
1647 {
1648 fconnected = TRUE;
1649 }
1650 }
1651 else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) ||
1652 (WLAN_HDD_P2P_GO == pAdapter->device_mode))
1653 {
1654 for (staId = 0; staId < WLAN_MAX_STA_COUNT; staId++)
1655 {
1656 if ((pAdapter->aStaInfo[staId].isUsed) &&
1657 (WLANTL_STA_AUTHENTICATED ==
1658 pAdapter->aStaInfo[staId].tlSTAState))
1659 {
1660 fconnected = TRUE;
1661 }
1662 }
1663 }
1664 if ( fconnected )
1665 {
1666 hddLog(VOS_TRACE_LEVEL_INFO,
1667 "%s: One of the interface is connected check for scan",
1668 __func__);
1669 hddLog(VOS_TRACE_LEVEL_INFO,
1670 "%s: pkt_tx_count: %d, pkt_rx_count: %d", __func__,
1671 pAdapter->hdd_stats.hddTxRxStats.pkt_tx_count,
1672 pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count);
1673
1674 vos_timer_start(&pHddCtx->tx_rx_trafficTmr,
1675 cfg_param->trafficMntrTmrForSplitScan);
1676 //Check for the previous statistics count
1677 if ((pAdapter->hdd_stats.hddTxRxStats.pkt_tx_count >
1678 cfg_param->txRxThresholdForSplitScan) ||
1679 (pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count >
1680 cfg_param->txRxThresholdForSplitScan) ||
1681 pHddCtx->drvr_miracast)
1682 {
1683 pAdapter->hdd_stats.hddTxRxStats.pkt_tx_count = 0;
1684 pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count = 0;
1685
1686 if (!pHddCtx->issplitscan_enabled)
1687 {
1688 pHddCtx->issplitscan_enabled = TRUE;
1689 sme_enable_disable_split_scan(
1690 WLAN_HDD_GET_HAL_CTX(pAdapter),
1691 cfg_param->nNumStaChanCombinedConc,
1692 cfg_param->nNumP2PChanCombinedConc);
1693 }
1694 return;
1695 }
1696 else
1697 {
1698 pAdapter->hdd_stats.hddTxRxStats.pkt_tx_count = 0;
1699 pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count = 0;
1700 }
1701 fconnected = FALSE;
1702 }
1703 }
1704 status = hdd_get_next_adapter( pHddCtx, pAdapterNode, &pNext);
1705 pAdapterNode = pNext;
1706 }
1707
1708 if (pHddCtx->issplitscan_enabled)
1709 {
1710 hddLog(VOS_TRACE_LEVEL_ERROR,
1711 "%s: Disable split scan", __func__);
1712 pHddCtx->issplitscan_enabled = FALSE;
1713 sme_enable_disable_split_scan(
1714 pHddCtx->hHal,
1715 SME_DISABLE_SPLIT_SCAN,
1716 SME_DISABLE_SPLIT_SCAN);
1717 }
1718 return;
1719}
Jeff Johnson295189b2012-06-20 16:38:30 -07001720