blob: 122b9abecb50e39310735c98040272541cfd97e7 [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;
546
547 v_BOOL_t txSuspended = VOS_FALSE;
548
549 ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled;
550
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530551 if (unlikely(netif_queue_stopped(dev))) {
Madan Mohan Koyyalamudi87f9a922013-09-25 16:20:07 +0530552 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530553 "%s is called when netif TX is disabled", __func__);
554 return NETDEV_TX_BUSY;
555 }
556
Ravi Joshi8a934352013-09-25 16:46:58 -0700557 if (WLAN_HDD_IBSS == pAdapter->device_mode &&
558 eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState)
Shailender Karmuchia734f332013-04-19 14:02:48 -0700559 {
560 v_MACADDR_t *pDestMacAddress = (v_MACADDR_t*)skb->data;
561
562 STAId = *(v_U8_t *)(((v_U8_t *)(skb->data)) - 1);
563
564 if ((STAId == HDD_WLAN_INVALID_STA_ID) &&
565 (vos_is_macaddr_broadcast( pDestMacAddress ) ||
566 vos_is_macaddr_group(pDestMacAddress)))
567 {
568 STAId = IBSS_BROADCAST_STAID;
569 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
570 "%s: BC/MC packet", __func__);
571 }
572 else if (STAId == HDD_WLAN_INVALID_STA_ID)
573 {
574 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
575 "%s: Received Unicast frame with invalid staID", __func__);
576 ++pAdapter->stats.tx_dropped;
577 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
578 kfree_skb(skb);
579 return NETDEV_TX_OK;
580 }
581 }
582 else
583 {
584 STAId = pHddStaCtx->conn_info.staId[0];
585 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700586 //Get TL AC corresponding to Qdisc queue index/AC.
587 ac = hdd_QdiscAcToTlAC[skb->queue_mapping];
588
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530589 //user priority from IP header, which is already extracted and set from
Jeff Johnson295189b2012-06-20 16:38:30 -0700590 //select_queue call back function
591 up = skb->priority;
592
593 ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac];
594
595#ifdef HDD_WMM_DEBUG
596 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700597 "%s: Classified as ac %d up %d", __func__, ac, up);
Jeff Johnson295189b2012-06-20 16:38:30 -0700598#endif // HDD_WMM_DEBUG
599
600 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
Varun Reddy Yeturu5ba69222013-04-01 18:22:20 -0700601 /*CR 463598,384996*/
602 /*For every increment of 10 pkts in the queue, we inform TL about pending pkts.
603 *We check for +1 in the logic,to take care of Zero count which
604 *occurs very frequently in low traffic cases */
605 if((pAdapter->wmm_tx_queue[ac].count + 1) % 10 == 0)
606 {
Shailender Karmuchia734f332013-04-19 14:02:48 -0700607 /* 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 -0700608 * if it is in the mainline code and if the log level is enabled by someone for debugging
609 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 -0700610
Ravi Joshi8a934352013-09-25 16:46:58 -0700611 status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
612 STAId, ac
613 );
614 if ( !VOS_IS_STATUS_SUCCESS( status ) )
615 {
616 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
617 "%s: WLANTL_STAPktPending() returned error code %d",
618 __func__, status);
619 kfree_skb(skb);
620 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
621 return NETDEV_TX_OK;
622 }
Varun Reddy Yeturu5ba69222013-04-01 18:22:20 -0700623 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700624 //If we have already reached the max queue size, disable the TX queue
625 if ( pAdapter->wmm_tx_queue[ac].count == pAdapter->wmm_tx_queue[ac].max_size)
626 {
627 ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressured;
628 ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressuredAC[ac];
629
630 netif_tx_stop_queue(netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)));
631 pAdapter->isTxSuspended[ac] = VOS_TRUE;
632 txSuspended = VOS_TRUE;
633 }
634
Madan Mohan Koyyalamudifd3b7a92013-10-10 15:02:58 +0530635 /* If 3/4th of the max queue size is used then enable the flag.
636 * This flag indicates to place the DHCP packets in VOICE AC queue.*/
637 if (WLANTL_AC_BE == ac)
638 {
639 if (pAdapter->wmm_tx_queue[ac].count >= HDD_TX_QUEUE_LOW_WATER_MARK)
640 {
641 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
642 "%s: Best Effort AC Tx queue is 3/4th full", __func__);
643 pAdapter->isVosLowResource = VOS_TRUE;
644 }
645 else
646 {
647 pAdapter->isVosLowResource = VOS_FALSE;
648 }
649 }
650
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530651 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
Jeff Johnson295189b2012-06-20 16:38:30 -0700652 if (VOS_TRUE == txSuspended)
653 {
Gopichand Nakkala8fbc3d42013-03-05 21:06:41 -0800654 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530655 "%s: TX queue full for AC=%d Disable OS TX queue",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700656 __func__, ac );
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530657 return NETDEV_TX_BUSY;
Jeff Johnson295189b2012-06-20 16:38:30 -0700658 }
659
660 //Use the skb->cb field to hold the list node information
661 pktNode = (skb_list_node_t *)&skb->cb;
662
663 //Stick the OS packet inside this node.
664 pktNode->skb = skb;
665
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530666 //Stick the User Priority inside this node
Jeff Johnson295189b2012-06-20 16:38:30 -0700667 pktNode->userPriority = up;
668
669
670 INIT_LIST_HEAD(&pktNode->anchor);
671
672 //Insert the OS packet into the appropriate AC queue
673 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
674 status = hdd_list_insert_back_size( &pAdapter->wmm_tx_queue[ac], &pktNode->anchor, &pktListSize );
675 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
676
677 if ( !VOS_IS_STATUS_SUCCESS( status ) )
678 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700679 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 -0700680 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
681 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
682 ++pAdapter->stats.tx_dropped;
683 kfree_skb(skb);
684 return NETDEV_TX_OK;
685 }
686
687 ++pAdapter->hdd_stats.hddTxRxStats.txXmitQueued;
688 ++pAdapter->hdd_stats.hddTxRxStats.txXmitQueuedAC[ac];
Sudhir Sattayappa Kohalli37620692013-08-05 14:02:26 -0700689 ++pAdapter->hdd_stats.hddTxRxStats.pkt_tx_count;
Jeff Johnson295189b2012-06-20 16:38:30 -0700690
691 //Make sure we have access to this access category
Madan Mohan Koyyalamudi0dab1ad2013-08-28 16:19:18 +0530692 if (likely(pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed) ||
Jeff Johnson295189b2012-06-20 16:38:30 -0700693 ( pHddStaCtx->conn_info.uIsAuthenticated == VOS_FALSE))
694 {
695 granted = VOS_TRUE;
696 }
697 else
698 {
699 status = hdd_wmm_acquire_access( pAdapter, ac, &granted );
700 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700701 if ( granted && ( pktListSize == 1 ))
702 {
703 //Let TL know we have a packet to send for this AC
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700704 //VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s:Indicating Packet to TL", __func__);
Shailender Karmuchia734f332013-04-19 14:02:48 -0700705 status = WLANTL_STAPktPending(
706 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
707 STAId, ac );
Jeff Johnson295189b2012-06-20 16:38:30 -0700708 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: Failed to signal TL for AC=%d", __func__, ac );
Jeff Johnson295189b2012-06-20 16:38:30 -0700711
712 //Remove the packet from queue. It must be at the back of the queue, as TX thread cannot preempt us in the middle
713 //as we are in a soft irq context. Also it must be the same packet that we just allocated.
714 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
715 status = hdd_list_remove_back( &pAdapter->wmm_tx_queue[ac], &anchor );
716 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
717 ++pAdapter->stats.tx_dropped;
718 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
719 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
720 kfree_skb(skb);
721 return NETDEV_TX_OK;
722 }
723 }
724
725 dev->trans_start = jiffies;
726
727 return NETDEV_TX_OK;
728}
729
730/**============================================================================
Shailender Karmuchia734f332013-04-19 14:02:48 -0700731 @brief hdd_Ibss_GetStaId() - Get the StationID using the Peer Mac address
732
733 @param pHddStaCtx : [in] pointer to HDD Station Context
734 pMacAddress [in] pointer to Peer Mac address
735 staID [out] pointer to Station Index
736 @return : VOS_STATUS_SUCCESS/VOS_STATUS_E_FAILURE
737 ===========================================================================*/
738
739VOS_STATUS hdd_Ibss_GetStaId(hdd_station_ctx_t *pHddStaCtx, v_MACADDR_t *pMacAddress, v_U8_t *staId)
740{
741 v_U8_t idx;
742
743 for (idx = 0; idx < HDD_MAX_NUM_IBSS_STA; idx++)
744 {
745 if (vos_mem_compare(&pHddStaCtx->conn_info.peerMacAddress[ idx ],
746 pMacAddress, sizeof(v_MACADDR_t)))
747 {
748 *staId = pHddStaCtx->conn_info.staId[idx];
749 return VOS_STATUS_SUCCESS;
750 }
751 }
752
753 return VOS_STATUS_E_FAILURE;
754}
755
756/**============================================================================
Jeff Johnson295189b2012-06-20 16:38:30 -0700757 @brief hdd_tx_timeout() - Function called by OS if there is any
758 timeout during transmission. Since HDD simply enqueues packet
759 and returns control to OS right away, this would never be invoked
760
761 @param dev : [in] pointer to Libra network device
762 @return : None
763 ===========================================================================*/
764void hdd_tx_timeout(struct net_device *dev)
765{
766 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700767 "%s: Transmission timeout occurred", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700768 //Getting here implies we disabled the TX queues for too long. Queues are
769 //disabled either because of disassociation or low resource scenarios. In
770 //case of disassociation it is ok to ignore this. But if associated, we have
771 //do possible recovery here
772}
773
774
775/**============================================================================
776 @brief hdd_stats() - Function registered with the Linux OS for
777 device TX/RX statistic
778
779 @param dev : [in] pointer to Libra network device
780
781 @return : pointer to net_device_stats structure
782 ===========================================================================*/
783struct net_device_stats* hdd_stats(struct net_device *dev)
784{
785 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
786
787 return &pAdapter->stats;
788}
789
790
791/**============================================================================
792 @brief hdd_init_tx_rx() - Init function to initialize Tx/RX
793 modules in HDD
794
795 @param pAdapter : [in] pointer to adapter context
796 @return : VOS_STATUS_E_FAILURE if any errors encountered
797 : VOS_STATUS_SUCCESS otherwise
798 ===========================================================================*/
799VOS_STATUS hdd_init_tx_rx( hdd_adapter_t *pAdapter )
800{
801 VOS_STATUS status = VOS_STATUS_SUCCESS;
802 v_SINT_t i = -1;
803
804 pAdapter->isVosOutOfResource = VOS_FALSE;
Madan Mohan Koyyalamudifd3b7a92013-10-10 15:02:58 +0530805 pAdapter->isVosLowResource = VOS_FALSE;
Jeff Johnson295189b2012-06-20 16:38:30 -0700806
807 //vos_mem_zero(&pAdapter->stats, sizeof(struct net_device_stats));
808 //Will be zeroed out during alloc
809
810 while (++i != NUM_TX_QUEUES)
811 {
812 pAdapter->isTxSuspended[i] = VOS_FALSE;
813 hdd_list_init( &pAdapter->wmm_tx_queue[i], HDD_TX_QUEUE_MAX_LEN);
814 }
815
816 return status;
817}
818
819
820/**============================================================================
821 @brief hdd_deinit_tx_rx() - Deinit function to clean up Tx/RX
822 modules in HDD
823
824 @param pAdapter : [in] pointer to adapter context
825 @return : VOS_STATUS_E_FAILURE if any errors encountered
826 : VOS_STATUS_SUCCESS otherwise
827 ===========================================================================*/
828VOS_STATUS hdd_deinit_tx_rx( hdd_adapter_t *pAdapter )
829{
830 VOS_STATUS status = VOS_STATUS_SUCCESS;
831 v_SINT_t i = -1;
832
833 status = hdd_flush_tx_queues(pAdapter);
834 while (++i != NUM_TX_QUEUES)
835 {
836 //Free up actual list elements in the Tx queue
837 hdd_list_destroy( &pAdapter->wmm_tx_queue[i] );
838 }
839
840 return status;
841}
842
843
844/**============================================================================
845 @brief hdd_disconnect_tx_rx() - Disconnect function to clean up Tx/RX
846 modules in HDD
847
848 @param pAdapter : [in] pointer to adapter context
849 @return : VOS_STATUS_E_FAILURE if any errors encountered
850 : VOS_STATUS_SUCCESS otherwise
851 ===========================================================================*/
852VOS_STATUS hdd_disconnect_tx_rx( hdd_adapter_t *pAdapter )
853{
854 return hdd_flush_tx_queues(pAdapter);
855}
856
857
858/**============================================================================
859 @brief hdd_IsEAPOLPacket() - Checks the packet is EAPOL or not.
860
861 @param pVosPacket : [in] pointer to vos packet
862 @return : VOS_TRUE if the packet is EAPOL
863 : VOS_FALSE otherwise
864 ===========================================================================*/
865
866v_BOOL_t hdd_IsEAPOLPacket( vos_pkt_t *pVosPacket )
867{
868 VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
869 v_BOOL_t fEAPOL = VOS_FALSE;
870 void *pBuffer = NULL;
871
872
873 vosStatus = vos_pkt_peek_data( pVosPacket, (v_SIZE_t)HDD_ETHERTYPE_802_1_X_FRAME_OFFSET,
874 &pBuffer, HDD_ETHERTYPE_802_1_X_SIZE );
875 if (VOS_IS_STATUS_SUCCESS( vosStatus ) )
876 {
877 if ( vos_be16_to_cpu( *(unsigned short*)pBuffer ) == HDD_ETHERTYPE_802_1_X )
878 {
879 fEAPOL = VOS_TRUE;
880 }
881 }
882
883 return fEAPOL;
884}
885
886
887#ifdef FEATURE_WLAN_WAPI // Need to update this function
888/**============================================================================
889 @brief hdd_IsWAIPacket() - Checks the packet is WAI or not.
890
891 @param pVosPacket : [in] pointer to vos packet
892 @return : VOS_TRUE if the packet is WAI
893 : VOS_FALSE otherwise
894 ===========================================================================*/
895
896v_BOOL_t hdd_IsWAIPacket( vos_pkt_t *pVosPacket )
897{
898 VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
899 v_BOOL_t fIsWAI = VOS_FALSE;
900 void *pBuffer = NULL;
901
902 // Need to update this function
903 vosStatus = vos_pkt_peek_data( pVosPacket, (v_SIZE_t)HDD_ETHERTYPE_802_1_X_FRAME_OFFSET,
904 &pBuffer, HDD_ETHERTYPE_802_1_X_SIZE );
905
906 if (VOS_IS_STATUS_SUCCESS( vosStatus ) )
907 {
908 if ( vos_be16_to_cpu( *(unsigned short*)pBuffer ) == HDD_ETHERTYPE_WAI)
909 {
910 fIsWAI = VOS_TRUE;
911 }
912 }
913
914 return fIsWAI;
915}
916#endif /* FEATURE_WLAN_WAPI */
917
918/**============================================================================
919 @brief hdd_tx_complete_cbk() - Callback function invoked by TL
920 to indicate that a packet has been transmitted across the SDIO bus
921 succesfully. OS packet resources can be released after this cbk.
922
923 @param vosContext : [in] pointer to VOS context
924 @param pVosPacket : [in] pointer to VOS packet (containing skb)
925 @param vosStatusIn : [in] status of the transmission
926
927 @return : VOS_STATUS_E_FAILURE if any errors encountered
928 : VOS_STATUS_SUCCESS otherwise
929 ===========================================================================*/
930VOS_STATUS hdd_tx_complete_cbk( v_VOID_t *vosContext,
931 vos_pkt_t *pVosPacket,
932 VOS_STATUS vosStatusIn )
933{
934 VOS_STATUS status = VOS_STATUS_SUCCESS;
935 hdd_adapter_t *pAdapter = NULL;
936 hdd_context_t *pHddCtx = NULL;
937 void* pOsPkt = NULL;
938
939 if( ( NULL == vosContext ) || ( NULL == pVosPacket ) )
940 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700941 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Null params being passed", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700942 return VOS_STATUS_E_FAILURE;
943 }
944
945 //Return the skb to the OS
946 status = vos_pkt_get_os_packet( pVosPacket, &pOsPkt, VOS_TRUE );
947 if(!VOS_IS_STATUS_SUCCESS( status ))
948 {
949 //This is bad but still try to free the VOSS resources if we can
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700950 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 -0700951 vos_pkt_return_packet( pVosPacket );
952 return VOS_STATUS_E_FAILURE;
953 }
954
955 //Get the HDD context.
956 pHddCtx = (hdd_context_t *)vos_get_context( VOS_MODULE_ID_HDD, vosContext );
957 //Get the Adapter context.
958 pAdapter = hdd_get_adapter(pHddCtx,WLAN_HDD_INFRA_STATION);
959 if(pAdapter == NULL)
960 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700961 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700962 }
963 else
964 {
965 ++pAdapter->hdd_stats.hddTxRxStats.txCompleted;
966 }
967
968 kfree_skb((struct sk_buff *)pOsPkt);
969
970 //Return the VOS packet resources.
971 status = vos_pkt_return_packet( pVosPacket );
972 if(!VOS_IS_STATUS_SUCCESS( status ))
973 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700974 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 -0700975 }
976
977 return status;
978}
979
980
981/**============================================================================
982 @brief hdd_tx_fetch_packet_cbk() - Callback function invoked by TL to
983 fetch a packet for transmission.
984
985 @param vosContext : [in] pointer to VOS context
986 @param staId : [in] Station for which TL is requesting a pkt
987 @param ac : [in] access category requested by TL
988 @param pVosPacket : [out] pointer to VOS packet packet pointer
989 @param pPktMetaInfo : [out] pointer to meta info for the pkt
990
991 @return : VOS_STATUS_E_EMPTY if no packets to transmit
992 : VOS_STATUS_E_FAILURE if any errors encountered
993 : VOS_STATUS_SUCCESS otherwise
994 ===========================================================================*/
995VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext,
996 v_U8_t *pStaId,
997 WLANTL_ACEnumType ac,
998 vos_pkt_t **ppVosPacket,
999 WLANTL_MetaInfoType *pPktMetaInfo )
1000{
1001 VOS_STATUS status = VOS_STATUS_E_FAILURE;
1002 hdd_adapter_t *pAdapter = NULL;
1003 hdd_context_t *pHddCtx = NULL;
1004 hdd_list_node_t *anchor = NULL;
1005 skb_list_node_t *pktNode = NULL;
1006 struct sk_buff *skb = NULL;
1007 vos_pkt_t *pVosPacket = NULL;
1008 v_MACADDR_t* pDestMacAddress = NULL;
1009 v_TIME_t timestamp;
1010 WLANTL_ACEnumType newAc;
1011 v_SIZE_t size = 0;
1012 tANI_U8 acAdmitted, i;
1013
1014 //Sanity check on inputs
1015 if ( ( NULL == vosContext ) ||
1016 ( NULL == pStaId ) ||
1017 ( NULL == ppVosPacket ) ||
1018 ( NULL == pPktMetaInfo ) )
1019 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001020 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Null Params being passed", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001021 return VOS_STATUS_E_FAILURE;
1022 }
1023
1024 //Get the HDD context.
1025 pHddCtx = (hdd_context_t *)vos_get_context( VOS_MODULE_ID_HDD, vosContext );
1026 if(pHddCtx == NULL)
1027 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001028 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001029 return VOS_STATUS_E_FAILURE;
1030 }
1031
1032 pAdapter = pHddCtx->sta_to_adapter[*pStaId];
1033 if( NULL == pAdapter )
1034 {
1035 VOS_ASSERT(0);
1036 return VOS_STATUS_E_FAILURE;
1037 }
1038
1039 ++pAdapter->hdd_stats.hddTxRxStats.txFetched;
1040
1041 *ppVosPacket = NULL;
1042
1043 //Make sure the AC being asked for is sane
1044 if( ac >= WLANTL_MAX_AC || ac < 0)
1045 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001046 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 -07001047 return VOS_STATUS_E_FAILURE;
1048 }
1049
1050 ++pAdapter->hdd_stats.hddTxRxStats.txFetchedAC[ac];
1051
1052#ifdef HDD_WMM_DEBUG
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001053 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 -07001054#endif // HDD_WMM_DEBUG
1055
1056 // We find an AC with packets
1057 // or we determine we have no more packets to send
1058 // HDD is not allowed to change AC.
1059
1060 // has this AC been admitted? or
1061 // To allow EAPOL packets when not authenticated
1062 if (unlikely((0==pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed) &&
1063 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.uIsAuthenticated))
1064 {
1065 ++pAdapter->hdd_stats.hddTxRxStats.txFetchEmpty;
1066#ifdef HDD_WMM_DEBUG
1067 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001068 "%s: no packets pending", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001069#endif // HDD_WMM_DEBUG
1070 return VOS_STATUS_E_FAILURE;
1071 }
1072
1073 // do we have any packets pending in this AC?
1074 hdd_list_size( &pAdapter->wmm_tx_queue[ac], &size );
1075 if( size > 0 )
1076 {
1077 // yes, so process it
1078#ifdef HDD_WMM_DEBUG
1079 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001080 "%s: AC %d has packets pending", __func__, ac);
Jeff Johnson295189b2012-06-20 16:38:30 -07001081#endif // HDD_WMM_DEBUG
1082 }
1083 else
1084 {
1085 ++pAdapter->hdd_stats.hddTxRxStats.txFetchEmpty;
1086#ifdef HDD_WMM_DEBUG
1087 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001088 "%s: no packets pending", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001089#endif // HDD_WMM_DEBUG
1090 return VOS_STATUS_E_FAILURE;
1091 }
1092
1093 //Get the vos packet. I don't want to dequeue and enqueue again if we are out of VOS resources
1094 //This simplifies the locking and unlocking of Tx queue
1095 status = vos_pkt_wrap_data_packet( &pVosPacket,
1096 VOS_PKT_TYPE_TX_802_3_DATA,
1097 NULL, //OS Pkt is not being passed
1098 hdd_tx_low_resource_cbk,
1099 pAdapter );
1100
1101 if (status == VOS_STATUS_E_ALREADY || status == VOS_STATUS_E_RESOURCES)
1102 {
1103 //Remember VOS is in a low resource situation
1104 pAdapter->isVosOutOfResource = VOS_TRUE;
1105 ++pAdapter->hdd_stats.hddTxRxStats.txFetchLowResources;
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001106 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s: VOSS in Low Resource scenario", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001107 //TL will now think we have no more packets in this AC
1108 return VOS_STATUS_E_FAILURE;
1109 }
1110
1111 //Remove the packet from the queue
1112 spin_lock_bh(&pAdapter->wmm_tx_queue[ac].lock);
1113 status = hdd_list_remove_front( &pAdapter->wmm_tx_queue[ac], &anchor );
1114 spin_unlock_bh(&pAdapter->wmm_tx_queue[ac].lock);
1115
1116 if(VOS_STATUS_SUCCESS == status)
1117 {
1118 //If success then we got a valid packet from some AC
1119 pktNode = list_entry(anchor, skb_list_node_t, anchor);
1120 skb = pktNode->skb;
1121 }
1122 else
1123 {
1124 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError;
Madan Mohan Koyyalamudi60a6a8d2012-10-21 11:57:42 -07001125 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "%s: Error in de-queuing "
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001126 "skb from Tx queue status = %d", __func__, status );
Jeff Johnson295189b2012-06-20 16:38:30 -07001127 vos_pkt_return_packet(pVosPacket);
1128 return VOS_STATUS_E_FAILURE;
1129 }
1130
1131 //Attach skb to VOS packet.
1132 status = vos_pkt_set_os_packet( pVosPacket, skb );
1133 if (status != VOS_STATUS_SUCCESS)
1134 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001135 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s: Error attaching skb", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001136 vos_pkt_return_packet(pVosPacket);
1137 ++pAdapter->stats.tx_dropped;
1138 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError;
1139 kfree_skb(skb);
1140 return VOS_STATUS_E_FAILURE;
1141 }
1142
1143 //Just being paranoid. To be removed later
1144 if(pVosPacket == NULL)
1145 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001146 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 -07001147 ++pAdapter->stats.tx_dropped;
1148 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError;
1149 kfree_skb(skb);
1150 return VOS_STATUS_E_FAILURE;
1151 }
1152
Chilam NG571c65a2013-01-19 12:27:36 +05301153#ifdef FEATURE_WLAN_TDLS
Gopichand Nakkala4ddf0192013-03-27 13:41:20 -07001154 if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode)
Chilam NG571c65a2013-01-19 12:27:36 +05301155 {
1156 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
Chilam NG571c65a2013-01-19 12:27:36 +05301157 u8 mac[6];
1158
Hoonki Lee387663d2013-02-05 18:08:43 -08001159 wlan_hdd_tdls_extract_da(skb, mac);
Chilam NG571c65a2013-01-19 12:27:36 +05301160
Hoonki Lee5fcc4582013-02-05 20:28:26 -08001161 if (vos_is_macaddr_group((v_MACADDR_t *)mac)) {
Chilam NG571c65a2013-01-19 12:27:36 +05301162 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1163 "broadcast packet, not adding to peer list");
1164 } else if (memcmp(pHddStaCtx->conn_info.bssId,
1165 mac, 6) != 0) {
1166 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
Gopichand Nakkala4ddf0192013-03-27 13:41:20 -07001167 "extract mac: " MAC_ADDRESS_STR,
1168 MAC_ADDR_ARRAY(mac) );
Chilam NG571c65a2013-01-19 12:27:36 +05301169
Gopichand Nakkala4327a152013-03-04 23:22:42 -08001170 wlan_hdd_tdls_increment_pkt_count(pAdapter, mac, 1);
Chilam NG571c65a2013-01-19 12:27:36 +05301171 } else {
1172 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1173 "packet da is bssid, not adding to peer list");
1174 }
1175 }
1176#endif
1177
Jeff Johnson295189b2012-06-20 16:38:30 -07001178 //Return VOS packet to TL;
1179 *ppVosPacket = pVosPacket;
1180
1181 //Fill out the meta information needed by TL
1182 //FIXME This timestamp is really the time stamp of wrap_data_packet
1183 vos_pkt_get_timestamp( pVosPacket, &timestamp );
1184 pPktMetaInfo->usTimeStamp = (v_U16_t)timestamp;
1185
1186 if(pAdapter->sessionCtx.station.conn_info.uIsAuthenticated == VOS_TRUE)
1187 pPktMetaInfo->ucIsEapol = 0;
1188 else
1189 pPktMetaInfo->ucIsEapol = hdd_IsEAPOLPacket( pVosPacket ) ? 1 : 0;
1190
1191#ifdef FEATURE_WLAN_WAPI
1192 // Override usIsEapol value when its zero for WAPI case
1193 pPktMetaInfo->ucIsWai = hdd_IsWAIPacket( pVosPacket ) ? 1 : 0;
1194#endif /* FEATURE_WLAN_WAPI */
1195
1196 if ((HDD_WMM_USER_MODE_NO_QOS == pHddCtx->cfg_ini->WmmMode) ||
1197 (!pAdapter->hddWmmStatus.wmmQap))
1198 {
1199 // either we don't want QoS or the AP doesn't support QoS
1200 pPktMetaInfo->ucUP = 0;
1201 pPktMetaInfo->ucTID = 0;
1202 }
1203 else
1204 {
1205 /* 1. Check if ACM is set for this AC
1206 * 2. If set, check if this AC had already admitted
1207 * 3. If not already admitted, downgrade the UP to next best UP */
1208 if(!pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessRequired ||
1209 pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcTspecValid)
1210 {
1211 pPktMetaInfo->ucUP = pktNode->userPriority;
1212 pPktMetaInfo->ucTID = pPktMetaInfo->ucUP;
1213 }
1214 else
1215 {
1216 //Downgrade the UP
1217 acAdmitted = pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcTspecValid;
1218 newAc = WLANTL_AC_BK;
1219 for (i=ac-1; i>0; i--)
1220 {
1221 if (pAdapter->hddWmmStatus.wmmAcStatus[i].wmmAcAccessRequired == 0)
1222 {
1223 newAc = i;
1224 break;
1225 }
1226 }
1227 pPktMetaInfo->ucUP = hddWmmAcToHighestUp[newAc];
1228 pPktMetaInfo->ucTID = pPktMetaInfo->ucUP;
1229 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,"Downgrading UP %d to UP %d ", pktNode->userPriority, pPktMetaInfo->ucUP);
1230 }
1231 }
1232
1233 pPktMetaInfo->ucType = 0; //FIXME Don't know what this is
1234 pPktMetaInfo->ucDisableFrmXtl = 0; //802.3 frame so we need to xlate
1235 if ( 1 < size )
1236 {
1237 pPktMetaInfo->bMorePackets = 1; //HDD has more packets to send
1238 }
1239 else
1240 {
1241 pPktMetaInfo->bMorePackets = 0;
1242 }
1243
1244 //Extract the destination address from ethernet frame
1245 pDestMacAddress = (v_MACADDR_t*)skb->data;
1246 pPktMetaInfo->ucBcast = vos_is_macaddr_broadcast( pDestMacAddress ) ? 1 : 0;
1247 pPktMetaInfo->ucMcast = vos_is_macaddr_group( pDestMacAddress ) ? 1 : 0;
1248
1249
1250
1251 // if we are in a backpressure situation see if we can turn the hose back on
1252 if ( (pAdapter->isTxSuspended[ac]) &&
1253 (size <= HDD_TX_QUEUE_LOW_WATER_MARK) )
1254 {
1255 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDePressured;
1256 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDePressuredAC[ac];
Gopichand Nakkala8fbc3d42013-03-05 21:06:41 -08001257 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001258 "%s: TX queue[%d] re-enabled", __func__, ac);
Jeff Johnson295189b2012-06-20 16:38:30 -07001259 pAdapter->isTxSuspended[ac] = VOS_FALSE;
1260 netif_tx_wake_queue(netdev_get_tx_queue(pAdapter->dev,
1261 skb_get_queue_mapping(skb) ));
1262 }
1263
1264
1265 // We're giving the packet to TL so consider it transmitted from
1266 // a statistics perspective. We account for it here instead of
1267 // when the packet is returned for two reasons. First, TL will
1268 // manipulate the skb to the point where the len field is not
1269 // accurate, leading to inaccurate byte counts if we account for
1270 // it later. Second, TL does not provide any feedback as to
1271 // whether or not the packet was successfully sent over the air,
1272 // so the packet counts will be the same regardless of where we
1273 // account for them
1274 pAdapter->stats.tx_bytes += skb->len;
1275 ++pAdapter->stats.tx_packets;
1276 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeued;
1277 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeuedAC[ac];
1278
Leo Chang50bbd252013-04-25 14:58:01 -07001279 if((pHddCtx->cfg_ini->thermalMitigationEnable) &&
1280 (WLAN_HDD_INFRA_STATION == pAdapter->device_mode))
Jeff Johnson295189b2012-06-20 16:38:30 -07001281 {
1282 if(mutex_lock_interruptible(&pHddCtx->tmInfo.tmOperationLock))
1283 {
1284 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001285 "%s: Tm Lock fail", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001286 return VOS_STATUS_E_FAILURE;
1287 }
1288 if(WLAN_HDD_TM_LEVEL_1 < pHddCtx->tmInfo.currentTmLevel)
1289 {
1290 if(0 == pHddCtx->tmInfo.txFrameCount)
1291 {
1292 /* Just recovered from sleep timeout */
1293 pHddCtx->tmInfo.lastOpenTs = timestamp;
1294 }
1295
Leo Chang50bbd252013-04-25 14:58:01 -07001296 if((VOS_FALSE == pHddCtx->tmInfo.qBlocked) &&
1297 ((timestamp - pHddCtx->tmInfo.lastOpenTs) > (pHddCtx->tmInfo.tmAction.txOperationDuration / 10)) &&
Jeff Johnson295189b2012-06-20 16:38:30 -07001298 (pHddCtx->tmInfo.txFrameCount >= pHddCtx->tmInfo.tmAction.txBlockFrameCountThreshold))
1299 {
Jeff Johnson295189b2012-06-20 16:38:30 -07001300 /* During TX open duration, TX frame count is larger than threshold
1301 * Block TX during Sleep time */
1302 netif_tx_stop_all_queues(pAdapter->dev);
Leo Chang50bbd252013-04-25 14:58:01 -07001303 pHddCtx->tmInfo.qBlocked = VOS_TRUE;
Jeff Johnson295189b2012-06-20 16:38:30 -07001304 pHddCtx->tmInfo.lastblockTs = timestamp;
1305 if(VOS_TIMER_STATE_STOPPED == vos_timer_getCurrentState(&pHddCtx->tmInfo.txSleepTimer))
1306 {
1307 vos_timer_start(&pHddCtx->tmInfo.txSleepTimer, pHddCtx->tmInfo.tmAction.txSleepDuration);
1308 }
1309 }
1310 else if(((timestamp - pHddCtx->tmInfo.lastOpenTs) > (pHddCtx->tmInfo.tmAction.txOperationDuration / 10)) &&
1311 (pHddCtx->tmInfo.txFrameCount < pHddCtx->tmInfo.tmAction.txBlockFrameCountThreshold))
1312 {
1313 /* During TX open duration, TX frame count is less than threshold
1314 * Reset count and timestamp to prepare next cycle */
1315 pHddCtx->tmInfo.lastOpenTs = timestamp;
1316 pHddCtx->tmInfo.txFrameCount = 0;
1317 }
1318 else
1319 {
1320 /* Do Nothing */
1321 }
1322 pHddCtx->tmInfo.txFrameCount++;
1323 }
1324 mutex_unlock(&pHddCtx->tmInfo.tmOperationLock);
1325 }
1326
1327
1328#ifdef HDD_WMM_DEBUG
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001329 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 -07001330#endif // HDD_WMM_DEBUG
1331
1332 return status;
1333}
1334
1335
1336/**============================================================================
1337 @brief hdd_tx_low_resource_cbk() - Callback function invoked in the
1338 case where VOS packets are not available at the time of the call to get
1339 packets. This callback function is invoked by VOS when packets are
1340 available.
1341
1342 @param pVosPacket : [in] pointer to VOS packet
1343 @param userData : [in] opaque user data that was passed initially
1344
1345 @return : VOS_STATUS_E_FAILURE if any errors encountered,
1346 : VOS_STATUS_SUCCESS otherwise
1347 =============================================================================*/
1348VOS_STATUS hdd_tx_low_resource_cbk( vos_pkt_t *pVosPacket,
1349 v_VOID_t *userData )
1350{
1351 VOS_STATUS status;
1352 v_SINT_t i = 0;
1353 v_SIZE_t size = 0;
1354 hdd_adapter_t* pAdapter = (hdd_adapter_t *)userData;
1355
1356 if(pAdapter == NULL)
1357 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001358 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001359 return VOS_STATUS_E_FAILURE;
1360 }
1361
1362 //Return the packet to VOS. We just needed to know that VOS is out of low resource
1363 //situation. Here we will only signal TL that there is a pending data for a STA.
1364 //VOS packet will be requested (if needed) when TL comes back to fetch data.
1365 vos_pkt_return_packet( pVosPacket );
1366
1367 pAdapter->isVosOutOfResource = VOS_FALSE;
1368
1369 //Indicate to TL that there is pending data if a queue is non empty
1370 for( i=NUM_TX_QUEUES-1; i>=0; --i )
1371 {
1372 size = 0;
1373 hdd_list_size( &pAdapter->wmm_tx_queue[i], &size );
1374 if ( size > 0 )
1375 {
1376 status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
1377 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId [0],
1378 (WLANTL_ACEnumType)i );
1379 if( !VOS_IS_STATUS_SUCCESS( status ) )
1380 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001381 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 -07001382 }
1383 }
1384 }
1385
1386 return VOS_STATUS_SUCCESS;
1387}
1388
1389
1390/**============================================================================
1391 @brief hdd_rx_packet_cbk() - Receive callback registered with TL.
1392 TL will call this to notify the HDD when one or more packets were
1393 received for a registered STA.
1394
1395 @param vosContext : [in] pointer to VOS context
1396 @param pVosPacketChain : [in] pointer to VOS packet chain
1397 @param staId : [in] Station Id
1398 @param pRxMetaInfo : [in] pointer to meta info for the received pkt(s)
1399
1400 @return : VOS_STATUS_E_FAILURE if any errors encountered,
1401 : VOS_STATUS_SUCCESS otherwise
1402 ===========================================================================*/
1403VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext,
1404 vos_pkt_t *pVosPacketChain,
1405 v_U8_t staId,
1406 WLANTL_RxMetaInfoType* pRxMetaInfo )
1407{
1408 hdd_adapter_t *pAdapter = NULL;
1409 hdd_context_t *pHddCtx = NULL;
1410 VOS_STATUS status = VOS_STATUS_E_FAILURE;
1411 int rxstat;
1412 struct sk_buff *skb = NULL;
1413 vos_pkt_t* pVosPacket;
1414 vos_pkt_t* pNextVosPacket;
1415
1416 //Sanity check on inputs
1417 if ( ( NULL == vosContext ) ||
1418 ( NULL == pVosPacketChain ) ||
1419 ( NULL == pRxMetaInfo ) )
1420 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001421 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Null params being passed", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001422 return VOS_STATUS_E_FAILURE;
1423 }
1424
1425 pHddCtx = (hdd_context_t *)vos_get_context( VOS_MODULE_ID_HDD, vosContext );
1426 if ( NULL == pHddCtx )
1427 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001428 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001429 return VOS_STATUS_E_FAILURE;
1430 }
1431
1432 pAdapter = pHddCtx->sta_to_adapter[staId];
1433 if( NULL == pAdapter )
1434 {
Madan Mohan Koyyalamudi858bb362013-08-05 19:57:37 +05301435 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: pAdapter is Null for staId %u",
1436 __func__, staId);
Jeff Johnson295189b2012-06-20 16:38:30 -07001437 return VOS_STATUS_E_FAILURE;
1438 }
1439
1440 ++pAdapter->hdd_stats.hddTxRxStats.rxChains;
1441
1442 // walk the chain until all are processed
1443 pVosPacket = pVosPacketChain;
1444 do
1445 {
1446 // get the pointer to the next packet in the chain
1447 // (but don't unlink the packet since we free the entire chain later)
1448 status = vos_pkt_walk_packet_chain( pVosPacket, &pNextVosPacket, VOS_FALSE);
1449
1450 // both "success" and "empty" are acceptable results
1451 if (!((status == VOS_STATUS_SUCCESS) || (status == VOS_STATUS_E_EMPTY)))
1452 {
1453 ++pAdapter->hdd_stats.hddTxRxStats.rxDropped;
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001454 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Failure walking packet chain", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001455 return VOS_STATUS_E_FAILURE;
1456 }
1457
1458 // Extract the OS packet (skb).
1459 // Tell VOS to detach the OS packet from the VOS packet
1460 status = vos_pkt_get_os_packet( pVosPacket, (v_VOID_t **)&skb, VOS_TRUE );
1461 if(!VOS_IS_STATUS_SUCCESS( status ))
1462 {
1463 ++pAdapter->hdd_stats.hddTxRxStats.rxDropped;
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001464 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 -07001465 return VOS_STATUS_E_FAILURE;
1466 }
Jeff Johnsone7245742012-09-05 17:12:55 -07001467
1468 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
1469 {
1470 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
1471 "Magic cookie(%x) for adapter sanity verification is invalid", pAdapter->magic);
1472 return eHAL_STATUS_FAILURE;
1473 }
1474
Chilam Ng1279e232013-01-25 15:06:52 -08001475#ifdef FEATURE_WLAN_TDLS
Gopichand Nakkala4ddf0192013-03-27 13:41:20 -07001476 if ((eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode) &&
1477 0 != pHddCtx->connected_peer_count)
Chilam Ng1279e232013-01-25 15:06:52 -08001478 {
1479 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
Chilam Ng1279e232013-01-25 15:06:52 -08001480 u8 mac[6];
1481
Hoonki Lee387663d2013-02-05 18:08:43 -08001482 wlan_hdd_tdls_extract_sa(skb, mac);
Chilam Ng1279e232013-01-25 15:06:52 -08001483
Hoonki Lee5fcc4582013-02-05 20:28:26 -08001484 if (vos_is_macaddr_group((v_MACADDR_t *)mac)) {
Chilam Ng1279e232013-01-25 15:06:52 -08001485 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1486 "rx broadcast packet, not adding to peer list");
1487 } else if (memcmp(pHddStaCtx->conn_info.bssId,
1488 mac, 6) != 0) {
Shailender Karmuchi13c0d082013-03-26 14:41:39 -07001489 hddTdlsPeer_t *curr_peer;
Chilam Ng1279e232013-01-25 15:06:52 -08001490 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
Shailender Karmuchi13c0d082013-03-26 14:41:39 -07001491 "rx extract mac:" MAC_ADDRESS_STR,
1492 MAC_ADDR_ARRAY(mac) );
Madan Mohan Koyyalamudi96797442013-10-08 16:04:42 +05301493 curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, TRUE);
Gopichand Nakkala4a2fc1a2013-05-17 16:59:39 +05301494 if ((NULL != curr_peer) && (eTDLS_LINK_CONNECTED == curr_peer->link_status)
1495 && (TRUE == pRxMetaInfo->isStaTdls))
Shailender Karmuchi13c0d082013-03-26 14:41:39 -07001496 {
1497 wlan_hdd_tdls_increment_pkt_count(pAdapter, mac, 0);
1498 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"rssi is %d", pRxMetaInfo->rssiAvg);
1499 wlan_hdd_tdls_set_rssi (pAdapter, mac, pRxMetaInfo->rssiAvg);
1500 }
Chilam Ng1279e232013-01-25 15:06:52 -08001501 } else {
1502 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1503 "rx packet sa is bssid, not adding to peer list");
1504 }
1505 }
1506#endif
1507
Jeff Johnson295189b2012-06-20 16:38:30 -07001508 skb->dev = pAdapter->dev;
1509 skb->protocol = eth_type_trans(skb, skb->dev);
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001510 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnson295189b2012-06-20 16:38:30 -07001511 ++pAdapter->hdd_stats.hddTxRxStats.rxPackets;
1512 ++pAdapter->stats.rx_packets;
1513 pAdapter->stats.rx_bytes += skb->len;
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001514#ifdef WLAN_OPEN_SOURCE
Jeff Johnsone7245742012-09-05 17:12:55 -07001515#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
Amar Singhal6144c002013-05-03 16:11:42 -07001516 wake_lock_timeout(&pHddCtx->rx_wake_lock, msecs_to_jiffies(HDD_WAKE_LOCK_DURATION));
Jeff Johnsone7245742012-09-05 17:12:55 -07001517#endif
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001518#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001519 rxstat = netif_rx_ni(skb);
1520 if (NET_RX_SUCCESS == rxstat)
1521 {
1522 ++pAdapter->hdd_stats.hddTxRxStats.rxDelivered;
Sudhir Sattayappa Kohalli37620692013-08-05 14:02:26 -07001523 ++pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count;
Jeff Johnson295189b2012-06-20 16:38:30 -07001524 }
1525 else
1526 {
1527 ++pAdapter->hdd_stats.hddTxRxStats.rxRefused;
1528 }
1529 // now process the next packet in the chain
1530 pVosPacket = pNextVosPacket;
1531
1532 } while (pVosPacket);
1533
1534 //Return the entire VOS packet chain to the resource pool
1535 status = vos_pkt_return_packet( pVosPacketChain );
1536 if(!VOS_IS_STATUS_SUCCESS( status ))
1537 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001538 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Failure returning vos pkt", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001539 }
1540
1541 pAdapter->dev->last_rx = jiffies;
1542
1543 return status;
1544}
Sudhir Sattayappa Kohalli37620692013-08-05 14:02:26 -07001545/**============================================================================
1546 @brief hdd_tx_rx_pkt_cnt_stat_timer_handler() -
1547 Enable/Disable split scan based on TX and RX traffic.
1548 @param HddContext : [in] pointer to Hdd context
1549 @return : None
1550 ===========================================================================*/
1551void hdd_tx_rx_pkt_cnt_stat_timer_handler( void *phddctx)
1552{
1553 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
1554 hdd_adapter_t *pAdapter = NULL;
1555 hdd_station_ctx_t *pHddStaCtx = NULL;
1556 hdd_context_t *pHddCtx = (hdd_context_t *)phddctx;
1557 hdd_config_t *cfg_param = pHddCtx->cfg_ini;
1558 VOS_STATUS status;
1559 v_U8_t staId = 0;
1560 v_U8_t fconnected = 0;
1561
1562 if (!cfg_param->dynSplitscan)
1563 {
1564 hddLog(VOS_TRACE_LEVEL_INFO,
1565 "%s: Error : Dynamic split scan is not Enabled : %d",
1566 __func__, pHddCtx->cfg_ini->dynSplitscan);
1567 return;
1568 }
1569
1570 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
1571 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
1572 {
1573 pAdapter = pAdapterNode->pAdapter;
1574
1575 if ( pAdapter )
1576 {
1577 hddLog(VOS_TRACE_LEVEL_INFO,
1578 "%s: Adapter with device mode %d exists",
1579 __func__, pAdapter->device_mode);
1580
1581 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
1582 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode))
1583 {
1584 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
1585 if ((eConnectionState_Associated ==
1586 pHddStaCtx->conn_info.connState) &&
1587 (VOS_TRUE == pHddStaCtx->conn_info.uIsAuthenticated))
1588 {
1589 fconnected = TRUE;
1590 }
1591 }
1592 else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) ||
1593 (WLAN_HDD_P2P_GO == pAdapter->device_mode))
1594 {
1595 for (staId = 0; staId < WLAN_MAX_STA_COUNT; staId++)
1596 {
1597 if ((pAdapter->aStaInfo[staId].isUsed) &&
1598 (WLANTL_STA_AUTHENTICATED ==
1599 pAdapter->aStaInfo[staId].tlSTAState))
1600 {
1601 fconnected = TRUE;
1602 }
1603 }
1604 }
1605 if ( fconnected )
1606 {
1607 hddLog(VOS_TRACE_LEVEL_INFO,
1608 "%s: One of the interface is connected check for scan",
1609 __func__);
1610 hddLog(VOS_TRACE_LEVEL_INFO,
1611 "%s: pkt_tx_count: %d, pkt_rx_count: %d", __func__,
1612 pAdapter->hdd_stats.hddTxRxStats.pkt_tx_count,
1613 pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count);
1614
1615 vos_timer_start(&pHddCtx->tx_rx_trafficTmr,
1616 cfg_param->trafficMntrTmrForSplitScan);
1617 //Check for the previous statistics count
1618 if ((pAdapter->hdd_stats.hddTxRxStats.pkt_tx_count >
1619 cfg_param->txRxThresholdForSplitScan) ||
1620 (pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count >
1621 cfg_param->txRxThresholdForSplitScan) ||
1622 pHddCtx->drvr_miracast)
1623 {
1624 pAdapter->hdd_stats.hddTxRxStats.pkt_tx_count = 0;
1625 pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count = 0;
1626
1627 if (!pHddCtx->issplitscan_enabled)
1628 {
1629 pHddCtx->issplitscan_enabled = TRUE;
1630 sme_enable_disable_split_scan(
1631 WLAN_HDD_GET_HAL_CTX(pAdapter),
1632 cfg_param->nNumStaChanCombinedConc,
1633 cfg_param->nNumP2PChanCombinedConc);
1634 }
1635 return;
1636 }
1637 else
1638 {
1639 pAdapter->hdd_stats.hddTxRxStats.pkt_tx_count = 0;
1640 pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count = 0;
1641 }
1642 fconnected = FALSE;
1643 }
1644 }
1645 status = hdd_get_next_adapter( pHddCtx, pAdapterNode, &pNext);
1646 pAdapterNode = pNext;
1647 }
1648
1649 if (pHddCtx->issplitscan_enabled)
1650 {
1651 hddLog(VOS_TRACE_LEVEL_ERROR,
1652 "%s: Disable split scan", __func__);
1653 pHddCtx->issplitscan_enabled = FALSE;
1654 sme_enable_disable_split_scan(
1655 pHddCtx->hHal,
1656 SME_DISABLE_SPLIT_SCAN,
1657 SME_DISABLE_SPLIT_SCAN);
1658 }
1659 return;
1660}
Jeff Johnson295189b2012-06-20 16:38:30 -07001661