blob: b68beee47d906d3468d9fc6a20ad3909628fa5ce [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
64#ifdef CONFIG_CFG80211
65#include <wlan_hdd_p2p.h>
66#include <linux/wireless.h>
67#include <net/cfg80211.h>
68#include <net/ieee80211_radiotap.h>
69#include "sapApi.h"
70#endif
71
Chilam NG571c65a2013-01-19 12:27:36 +053072#ifdef FEATURE_WLAN_TDLS
73#include "wlan_hdd_tdls.h"
74#endif
75
Jeff Johnson295189b2012-06-20 16:38:30 -070076/*---------------------------------------------------------------------------
77 Preprocessor definitions and constants
78 -------------------------------------------------------------------------*/
79
80const v_U8_t hddWmmAcToHighestUp[] = {
81 SME_QOS_WMM_UP_RESV,
82 SME_QOS_WMM_UP_EE,
83 SME_QOS_WMM_UP_VI,
84 SME_QOS_WMM_UP_NC
85};
86
87//Mapping Linux AC interpretation to TL AC.
88const v_U8_t hdd_QdiscAcToTlAC[] = {
89 WLANTL_AC_VO,
90 WLANTL_AC_VI,
91 WLANTL_AC_BE,
92 WLANTL_AC_BK,
93};
94
95#ifdef CONFIG_CFG80211
96static struct sk_buff* hdd_mon_tx_fetch_pkt(hdd_adapter_t* pAdapter);
97#endif
98
99/*---------------------------------------------------------------------------
100 Type declarations
101 -------------------------------------------------------------------------*/
102
103/*---------------------------------------------------------------------------
104 Function definitions and documenation
105 -------------------------------------------------------------------------*/
106
107#ifdef DATA_PATH_UNIT_TEST
108//Utility function to dump an sk_buff
109static void dump_sk_buff(struct sk_buff * skb)
110{
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700111 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: head = %p ", __func__, skb->head);
112 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: data = %p ", __func__, skb->data);
113 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: tail = %p ", __func__, skb->tail);
114 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: end = %p ", __func__, skb->end);
115 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: len = %d ", __func__, skb->len);
116 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: data_len = %d ", __func__, skb->data_len);
117 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 -0700118
119 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 ",
120 skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4],
121 skb->data[5], skb->data[6], skb->data[7]);
122 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",
123 skb->data[8], skb->data[9], skb->data[10], skb->data[11], skb->data[12],
124 skb->data[13], skb->data[14], skb->data[15]);
125}
126
127//Function for Unit Test only
128static void transport_thread(hdd_adapter_t *pAdapter)
129{
130 v_U8_t staId;
131 WLANTL_ACEnumType ac = WLANTL_AC_BE;
132 vos_pkt_t *pVosPacket = NULL ;
133 vos_pkt_t dummyPacket;
134 WLANTL_MetaInfoType pktMetaInfo;
135 WLANTL_RxMetaInfoType pktRxMetaInfo;
136 VOS_STATUS status = VOS_STATUS_E_FAILURE;
137
138 status = hdd_tx_fetch_packet_cbk( pAdapter->pvosContext,
139 &staId,
140 &ac,
141 &pVosPacket,
142 &pktMetaInfo );
143 if (status != VOS_STATUS_SUCCESS && status != VOS_STATUS_E_EMPTY)
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700144 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 -0700145 else
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700146 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 -0700147
Madan Mohan Koyyalamudi4e31b132012-11-02 13:13:52 -0700148 status = hdd_tx_complete_cbk(pAdapter->pvosContext, &dummyPacket, VOS_STATUS_SUCCESS);
Jeff Johnson295189b2012-06-20 16:38:30 -0700149 if (status != VOS_STATUS_SUCCESS)
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700150 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 -0700151 else
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700152 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 -0700153
154 status = hdd_tx_low_resource_cbk(pVosPacket, pAdapter);
155 if (status != VOS_STATUS_SUCCESS)
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700156 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 -0700157 else
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700158 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 -0700159
160 status = hdd_rx_packet_cbk( pAdapter->pvosContext,
161 &dummyPacket,
162 staId,
163 &pktRxMetaInfo);
164 if (status != VOS_STATUS_SUCCESS)
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700165 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 -0700166 else
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700167 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 -0700168
169}
170#endif
171
172
173/**============================================================================
174 @brief hdd_flush_tx_queues() - Utility function to flush the TX queues
175
176 @param pAdapter : [in] pointer to adapter context
177 @return : VOS_STATUS_E_FAILURE if any errors encountered
178 : VOS_STATUS_SUCCESS otherwise
179 ===========================================================================*/
180static VOS_STATUS hdd_flush_tx_queues( hdd_adapter_t *pAdapter )
181{
182 VOS_STATUS status = VOS_STATUS_SUCCESS;
183 v_SINT_t i = -1;
184 hdd_list_node_t *anchor = NULL;
185 skb_list_node_t *pktNode = NULL;
186 struct sk_buff *skb = NULL;
187
188 while (++i != NUM_TX_QUEUES)
189 {
190 //Free up any packets in the Tx queue
191 spin_lock_bh(&pAdapter->wmm_tx_queue[i].lock);
192 while (true)
193 {
194 status = hdd_list_remove_front( &pAdapter->wmm_tx_queue[i], &anchor );
195 if(VOS_STATUS_E_EMPTY != status)
196 {
197 pktNode = list_entry(anchor, skb_list_node_t, anchor);
198 skb = pktNode->skb;
199 //TODO
200 //++pAdapter->stats.tx_dropped;
201 ++pAdapter->hdd_stats.hddTxRxStats.txFlushed;
202 ++pAdapter->hdd_stats.hddTxRxStats.txFlushedAC[i];
203 kfree_skb(skb);
204 continue;
205 }
206 break;
207 }
208 spin_unlock_bh(&pAdapter->wmm_tx_queue[i].lock);
209 // backpressure is no longer in effect
210 pAdapter->isTxSuspended[i] = VOS_FALSE;
211 }
212
213 return status;
214}
215
216#ifdef CONFIG_CFG80211
217static struct sk_buff* hdd_mon_tx_fetch_pkt(hdd_adapter_t* pAdapter)
218{
219 skb_list_node_t *pktNode = NULL;
220 struct sk_buff *skb = NULL;
221 v_SIZE_t size = 0;
222 WLANTL_ACEnumType ac = 0;
223 VOS_STATUS status = VOS_STATUS_E_FAILURE;
224 hdd_list_node_t *anchor = NULL;
225
226 if( NULL == pAdapter )
227 {
228 VOS_ASSERT(0);
229 return NULL;
230 }
231
232 // do we have any packets pending in this AC?
233 hdd_list_size( &pAdapter->wmm_tx_queue[ac], &size );
234 if( size == 0 )
235 {
236 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700237 "%s: NO Packet Pending", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700238 return NULL;
239 }
240
241 //Remove the packet from the queue
242 spin_lock_bh(&pAdapter->wmm_tx_queue[ac].lock);
243 status = hdd_list_remove_front( &pAdapter->wmm_tx_queue[ac], &anchor );
244 spin_unlock_bh(&pAdapter->wmm_tx_queue[ac].lock);
245
246 if(VOS_STATUS_SUCCESS == status)
247 {
248 //If success then we got a valid packet from some AC
249 pktNode = list_entry(anchor, skb_list_node_t, anchor);
250 skb = pktNode->skb;
251 }
252 else
253 {
254 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
255 "%s: Not able to remove Packet from the list",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700256 __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700257
258 return NULL;
259 }
260
261 // if we are in a backpressure situation see if we can turn the hose back on
262 if ( (pAdapter->isTxSuspended[ac]) &&
263 (size <= HDD_TX_QUEUE_LOW_WATER_MARK) )
264 {
265 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700266 "%s: TX queue[%d] re-enabled", __func__, ac);
Jeff Johnson295189b2012-06-20 16:38:30 -0700267 pAdapter->isTxSuspended[ac] = VOS_FALSE;
268 /* Enable Queues which we have disabled earlier */
269 netif_tx_start_all_queues( pAdapter->dev );
270 }
271
272 return skb;
273}
274
275void hdd_mon_tx_mgmt_pkt(hdd_adapter_t* pAdapter)
276{
277 hdd_cfg80211_state_t *cfgState;
278 struct sk_buff* skb;
279 hdd_adapter_t* pMonAdapter = NULL;
280 struct ieee80211_hdr *hdr;
281
282 if (pAdapter == NULL )
283 {
284 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
285 "%s: pAdapter is NULL", __func__);
286 return;
287 }
288
289 pMonAdapter = hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_MONITOR );
290
291 cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
292
293 if( NULL != cfgState->buf )
294 {
295 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
296 "%s: Already one MGMT packet Tx going on", __func__);
297 return;
298 }
299
300 skb = hdd_mon_tx_fetch_pkt(pMonAdapter);
301
302 if (NULL == skb)
303 {
304 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
305 "%s: No Packet Pending", __func__);
306 return;
307 }
308
309 cfgState->buf = vos_mem_malloc( skb->len ); //buf;
310 if( cfgState->buf == NULL )
311 {
312 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
313 "%s: Failed to Allocate memory", __func__);
314 goto fail;
315 }
316
317 cfgState->len = skb->len;
318
319 vos_mem_copy( cfgState->buf, skb->data, skb->len);
320
321 cfgState->skb = skb; //buf;
322 cfgState->action_cookie = (tANI_U32)cfgState->buf;
323
324 hdr = (struct ieee80211_hdr *)skb->data;
325 if( (hdr->frame_control & HDD_FRAME_TYPE_MASK)
326 == HDD_FRAME_TYPE_MGMT )
327 {
328 if( (hdr->frame_control & HDD_FRAME_SUBTYPE_MASK)
329 == HDD_FRAME_SUBTYPE_DEAUTH )
330 {
331 hdd_softap_sta_deauth( pAdapter, hdr->addr1 );
332 goto mgmt_handled;
333 }
334 else if( (hdr->frame_control & HDD_FRAME_SUBTYPE_MASK)
335 == HDD_FRAME_SUBTYPE_DISASSOC )
336 {
337 hdd_softap_sta_disassoc( pAdapter, hdr->addr1 );
338 goto mgmt_handled;
339 }
340 }
341 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
342 "%s: Sending action frame to SAP to TX, Len %d", __func__, skb->len);
343
Jeff Johnson43971f52012-07-17 12:26:56 -0700344 if (VOS_STATUS_SUCCESS !=
Jeff Johnson295189b2012-06-20 16:38:30 -0700345 WLANSAP_SendAction( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
Jeff Johnsone7245742012-09-05 17:12:55 -0700346 skb->data, skb->len, 0) )
Jeff Johnson295189b2012-06-20 16:38:30 -0700347 {
348 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
349 "%s: WLANSAP_SendAction returned fail", __func__);
350 hdd_sendActionCnf( pAdapter, FALSE );
351 }
352 return;
353
354mgmt_handled:
355 hdd_sendActionCnf( pAdapter, TRUE );
356 return;
357fail:
358 kfree_skb(pAdapter->skb_to_tx);
359 pAdapter->skb_to_tx = NULL;
360 return;
361}
362
363void hdd_mon_tx_work_queue(struct work_struct *work)
364{
365 hdd_adapter_t* pAdapter = container_of(work, hdd_adapter_t, monTxWorkQueue);
366 hdd_mon_tx_mgmt_pkt(pAdapter);
367}
368
369int hdd_mon_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
370{
371 v_U16_t rt_hdr_len;
372 struct ieee80211_hdr *hdr;
373 hdd_adapter_t *pPgBkAdapter, *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
374 struct ieee80211_radiotap_header *rtap_hdr =
375 (struct ieee80211_radiotap_header *)skb->data;
376
377 /*Supplicant sends the EAPOL packet on monitor interface*/
378 pPgBkAdapter = pAdapter->sessionCtx.monitor.pAdapterForTx;
379 if(pPgBkAdapter == NULL)
380 {
381 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
382 "%s: No Adapter to piggy back. Dropping the pkt on monitor inf",
383 __func__);
384 goto fail; /* too short to be possibly valid */
385 }
386
387 /* check if toal skb length is greater then radio tab header length of not */
388 if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
389 goto fail; /* too short to be possibly valid */
390
391 /* check if radio tap header version is correct or not */
392 if (unlikely(rtap_hdr->it_version))
393 goto fail; /* only version 0 is supported */
394
395 /*Strip off the radio tap header*/
396 rt_hdr_len = ieee80211_get_radiotap_len(skb->data);
397
398 /* check if skb length if greator then total radio tap header length ot not*/
399 if (unlikely(skb->len < rt_hdr_len))
400 goto fail;
401
402 /* Update the trans_start for this netdev */
403 dev->trans_start = jiffies;
404 /*
405 * fix up the pointers accounting for the radiotap
406 * header still being in there.
407 */
408 skb_set_mac_header(skb, rt_hdr_len);
409 skb_set_network_header(skb, rt_hdr_len);
410 skb_set_transport_header(skb, rt_hdr_len);
411
412 /* Pull rtap header out of the skb */
413 skb_pull(skb, rt_hdr_len);
414
415 /*Supplicant adds: radiotap Hdr + radiotap data + 80211 Header. So after
416 * radio tap header and 802.11 header starts
417 */
418 hdr = (struct ieee80211_hdr *)skb->data;
419
420 /* Send data frames through the normal Data path. In this path we will
421 * conver rcvd 802.11 packet to 802.3 packet */
422 if ( (hdr->frame_control & HDD_FRAME_TYPE_MASK) == HDD_FRAME_TYPE_DATA)
423 {
424 v_U8_t da[6];
425 v_U8_t sa[6];
426
427 memcpy (da, hdr->addr1, VOS_MAC_ADDR_SIZE);
428 memcpy (sa, hdr->addr2, VOS_MAC_ADDR_SIZE);
429
430 /* Pull 802.11 MAC header */
431 skb_pull(skb, HDD_80211_HEADER_LEN);
432
433 if ( HDD_FRAME_SUBTYPE_QOSDATA ==
434 (hdr->frame_control & HDD_FRAME_SUBTYPE_MASK))
435 {
436 skb_pull(skb, HDD_80211_HEADER_QOS_CTL);
437 }
438
439 /* Pull LLC header */
440 skb_pull(skb, HDD_LLC_HDR_LEN);
441
442 /* Create space for Ethernet header */
443 skb_push(skb, HDD_MAC_HDR_SIZE*2);
444 memcpy(&skb->data[0], da, HDD_MAC_HDR_SIZE);
445 memcpy(&skb->data[HDD_DEST_ADDR_OFFSET], sa, HDD_MAC_HDR_SIZE);
446
447 /* Only EAPOL Data packets are allowed through monitor interface */
448 if (vos_be16_to_cpu(
449 (*(unsigned short*)&skb->data[HDD_ETHERTYPE_802_1_X_FRAME_OFFSET]) )
450 != HDD_ETHERTYPE_802_1_X)
451 {
452 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
453 "%s: Not a Eapol packet. Drop this frame", __func__);
454 //If not EAPOL frames, drop them.
455 kfree_skb(skb);
456 return NETDEV_TX_OK;
457 }
458
459 skb->protocol = htons(HDD_ETHERTYPE_802_1_X);
460
461 hdd_hostapd_select_queue(pPgBkAdapter->dev, skb);
462 return hdd_softap_hard_start_xmit( skb, pPgBkAdapter->dev );
463 }
464 else
465 {
466 VOS_STATUS status;
467 WLANTL_ACEnumType ac = 0;
468 skb_list_node_t *pktNode = NULL;
469 v_SIZE_t pktListSize = 0;
470
471 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
472 //If we have already reached the max queue size, disable the TX queue
473 if ( pAdapter->wmm_tx_queue[ac].count == pAdapter->wmm_tx_queue[ac].max_size)
474 {
475 /* We want to process one packet at a time, so lets disable all TX queues
476 * and re-enable the queues once we get TX feedback for this packet */
477 netif_tx_stop_all_queues(pAdapter->dev);
478 pAdapter->isTxSuspended[ac] = VOS_TRUE;
479 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
480 return NETDEV_TX_BUSY;
481 }
482 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
483
484 //Use the skb->cb field to hold the list node information
485 pktNode = (skb_list_node_t *)&skb->cb;
486
487 //Stick the OS packet inside this node.
488 pktNode->skb = skb;
489
490 INIT_LIST_HEAD(&pktNode->anchor);
491
492 //Insert the OS packet into the appropriate AC queue
493 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
494 status = hdd_list_insert_back_size( &pAdapter->wmm_tx_queue[ac],
495 &pktNode->anchor, &pktListSize );
496 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
497
498 if ( !VOS_IS_STATUS_SUCCESS( status ) )
499 {
500 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700501 "%s:Insert Tx queue failed. Pkt dropped", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700502 kfree_skb(skb);
503 return NETDEV_TX_OK;
504 }
505
506 if ( pktListSize == 1 )
507 {
508 /* In this context we cannot acquire any mutex etc. And to transmit
509 * this packet we need to call SME API. So to take care of this we will
510 * schedule a workqueue
511 */
512 schedule_work(&pPgBkAdapter->monTxWorkQueue);
513 }
514 return NETDEV_TX_OK;
515 }
516
517fail:
518 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
519 "%s: Packet Rcvd at Monitor interface is not proper,"
520 " Dropping the packet",
521 __func__);
522 kfree_skb(skb);
523 return NETDEV_TX_OK;
524}
525#endif
526/**============================================================================
527 @brief hdd_hard_start_xmit() - Function registered with the Linux OS for
528 transmitting packets. There are 2 versions of this function. One that uses
529 locked queue and other that uses lockless queues. Both have been retained to
530 do some performance testing
531
532 @param skb : [in] pointer to OS packet (sk_buff)
533 @param dev : [in] pointer to Libra network device
534
535 @return : NET_XMIT_DROP if packets are dropped
536 : NET_XMIT_SUCCESS if packet is enqueued succesfully
537 ===========================================================================*/
538int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
539{
540 VOS_STATUS status;
541 WLANTL_ACEnumType ac;
542 sme_QosWmmUpType up;
543 skb_list_node_t *pktNode = NULL;
544 hdd_list_node_t *anchor = NULL;
545 v_SIZE_t pktListSize = 0;
546 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
547 v_BOOL_t granted;
548
549 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
550
551 v_BOOL_t txSuspended = VOS_FALSE;
552
553 ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled;
554
555 //Get TL AC corresponding to Qdisc queue index/AC.
556 ac = hdd_QdiscAcToTlAC[skb->queue_mapping];
557
558 //user priority from IP header, which is already extracted and set from
559 //select_queue call back function
560 up = skb->priority;
561
562 ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac];
563
564#ifdef HDD_WMM_DEBUG
565 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700566 "%s: Classified as ac %d up %d", __func__, ac, up);
Jeff Johnson295189b2012-06-20 16:38:30 -0700567#endif // HDD_WMM_DEBUG
568
569 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
Madan Mohan Koyyalamudi992cd442012-10-05 10:56:17 -0700570 /*For every increment of 10 pkts in the queue, we inform TL about pending pkts.
571 * We check for +1 in the logic,to take care of Zero count which
572 * occurs very frequently in low traffic cases */
573 if((pAdapter->wmm_tx_queue[ac].count + 1) % 10 == 0)
574 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700575 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%s:Queue is Filling up.Inform TL again about pending packets", __func__);
Madan Mohan Koyyalamudi992cd442012-10-05 10:56:17 -0700576 WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext, pHddStaCtx->conn_info.staId[0], ac );
577 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700578 //If we have already reached the max queue size, disable the TX queue
579 if ( pAdapter->wmm_tx_queue[ac].count == pAdapter->wmm_tx_queue[ac].max_size)
580 {
581 ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressured;
582 ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressuredAC[ac];
583
584 netif_tx_stop_queue(netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)));
585 pAdapter->isTxSuspended[ac] = VOS_TRUE;
586 txSuspended = VOS_TRUE;
587 }
588
589 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
590 if (VOS_TRUE == txSuspended)
591 {
592 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
593 "%s: TX queue full for AC=%d Disable OS TX queue",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700594 __func__, ac );
Jeff Johnson295189b2012-06-20 16:38:30 -0700595 return NETDEV_TX_BUSY;
596 }
597
598 //Use the skb->cb field to hold the list node information
599 pktNode = (skb_list_node_t *)&skb->cb;
600
601 //Stick the OS packet inside this node.
602 pktNode->skb = skb;
603
604 //Stick the User Priority inside this node
605 pktNode->userPriority = up;
606
607
608 INIT_LIST_HEAD(&pktNode->anchor);
609
610 //Insert the OS packet into the appropriate AC queue
611 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
612 status = hdd_list_insert_back_size( &pAdapter->wmm_tx_queue[ac], &pktNode->anchor, &pktListSize );
613 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
614
615 if ( !VOS_IS_STATUS_SUCCESS( status ) )
616 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700617 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 -0700618 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
619 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
620 ++pAdapter->stats.tx_dropped;
621 kfree_skb(skb);
622 return NETDEV_TX_OK;
623 }
624
625 ++pAdapter->hdd_stats.hddTxRxStats.txXmitQueued;
626 ++pAdapter->hdd_stats.hddTxRxStats.txXmitQueuedAC[ac];
627
628 //Make sure we have access to this access category
629 if (likely(pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed) ||
630 ( pHddStaCtx->conn_info.uIsAuthenticated == VOS_FALSE))
631 {
632 granted = VOS_TRUE;
633 }
634 else
635 {
636 status = hdd_wmm_acquire_access( pAdapter, ac, &granted );
637 }
638
639 if ( granted && ( pktListSize == 1 ))
640 {
641 //Let TL know we have a packet to send for this AC
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700642 //VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s:Indicating Packet to TL", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700643 status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext, pHddStaCtx->conn_info.staId[0], ac );
644
645 if ( !VOS_IS_STATUS_SUCCESS( status ) )
646 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700647 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 -0700648
649 //Remove the packet from queue. It must be at the back of the queue, as TX thread cannot preempt us in the middle
650 //as we are in a soft irq context. Also it must be the same packet that we just allocated.
651 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
652 status = hdd_list_remove_back( &pAdapter->wmm_tx_queue[ac], &anchor );
653 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
654 ++pAdapter->stats.tx_dropped;
655 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
656 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
657 kfree_skb(skb);
658 return NETDEV_TX_OK;
659 }
660 }
661
662 dev->trans_start = jiffies;
663
664 return NETDEV_TX_OK;
665}
666
667/**============================================================================
668 @brief hdd_tx_timeout() - Function called by OS if there is any
669 timeout during transmission. Since HDD simply enqueues packet
670 and returns control to OS right away, this would never be invoked
671
672 @param dev : [in] pointer to Libra network device
673 @return : None
674 ===========================================================================*/
675void hdd_tx_timeout(struct net_device *dev)
676{
677 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700678 "%s: Transmission timeout occurred", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700679 //Getting here implies we disabled the TX queues for too long. Queues are
680 //disabled either because of disassociation or low resource scenarios. In
681 //case of disassociation it is ok to ignore this. But if associated, we have
682 //do possible recovery here
Madan Mohan Koyyalamudiea777012012-10-31 14:22:34 -0700683
684 //testing underlying data path stall
685 sme_transportDebug(0, 1);
Jeff Johnson295189b2012-06-20 16:38:30 -0700686}
687
688
689/**============================================================================
690 @brief hdd_stats() - Function registered with the Linux OS for
691 device TX/RX statistic
692
693 @param dev : [in] pointer to Libra network device
694
695 @return : pointer to net_device_stats structure
696 ===========================================================================*/
697struct net_device_stats* hdd_stats(struct net_device *dev)
698{
699 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
700
701 return &pAdapter->stats;
702}
703
704
705/**============================================================================
706 @brief hdd_init_tx_rx() - Init function to initialize Tx/RX
707 modules in HDD
708
709 @param pAdapter : [in] pointer to adapter context
710 @return : VOS_STATUS_E_FAILURE if any errors encountered
711 : VOS_STATUS_SUCCESS otherwise
712 ===========================================================================*/
713VOS_STATUS hdd_init_tx_rx( hdd_adapter_t *pAdapter )
714{
715 VOS_STATUS status = VOS_STATUS_SUCCESS;
716 v_SINT_t i = -1;
717
718 pAdapter->isVosOutOfResource = VOS_FALSE;
719
720 //vos_mem_zero(&pAdapter->stats, sizeof(struct net_device_stats));
721 //Will be zeroed out during alloc
722
723 while (++i != NUM_TX_QUEUES)
724 {
725 pAdapter->isTxSuspended[i] = VOS_FALSE;
726 hdd_list_init( &pAdapter->wmm_tx_queue[i], HDD_TX_QUEUE_MAX_LEN);
727 }
728
729 return status;
730}
731
732
733/**============================================================================
734 @brief hdd_deinit_tx_rx() - Deinit function to clean up Tx/RX
735 modules in HDD
736
737 @param pAdapter : [in] pointer to adapter context
738 @return : VOS_STATUS_E_FAILURE if any errors encountered
739 : VOS_STATUS_SUCCESS otherwise
740 ===========================================================================*/
741VOS_STATUS hdd_deinit_tx_rx( hdd_adapter_t *pAdapter )
742{
743 VOS_STATUS status = VOS_STATUS_SUCCESS;
744 v_SINT_t i = -1;
745
746 status = hdd_flush_tx_queues(pAdapter);
747 while (++i != NUM_TX_QUEUES)
748 {
749 //Free up actual list elements in the Tx queue
750 hdd_list_destroy( &pAdapter->wmm_tx_queue[i] );
751 }
752
753 return status;
754}
755
756
757/**============================================================================
758 @brief hdd_disconnect_tx_rx() - Disconnect function to clean up Tx/RX
759 modules in HDD
760
761 @param pAdapter : [in] pointer to adapter context
762 @return : VOS_STATUS_E_FAILURE if any errors encountered
763 : VOS_STATUS_SUCCESS otherwise
764 ===========================================================================*/
765VOS_STATUS hdd_disconnect_tx_rx( hdd_adapter_t *pAdapter )
766{
767 return hdd_flush_tx_queues(pAdapter);
768}
769
770
771/**============================================================================
772 @brief hdd_IsEAPOLPacket() - Checks the packet is EAPOL or not.
773
774 @param pVosPacket : [in] pointer to vos packet
775 @return : VOS_TRUE if the packet is EAPOL
776 : VOS_FALSE otherwise
777 ===========================================================================*/
778
779v_BOOL_t hdd_IsEAPOLPacket( vos_pkt_t *pVosPacket )
780{
781 VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
782 v_BOOL_t fEAPOL = VOS_FALSE;
783 void *pBuffer = NULL;
784
785
786 vosStatus = vos_pkt_peek_data( pVosPacket, (v_SIZE_t)HDD_ETHERTYPE_802_1_X_FRAME_OFFSET,
787 &pBuffer, HDD_ETHERTYPE_802_1_X_SIZE );
788 if (VOS_IS_STATUS_SUCCESS( vosStatus ) )
789 {
790 if ( vos_be16_to_cpu( *(unsigned short*)pBuffer ) == HDD_ETHERTYPE_802_1_X )
791 {
792 fEAPOL = VOS_TRUE;
793 }
794 }
795
796 return fEAPOL;
797}
798
799
800#ifdef FEATURE_WLAN_WAPI // Need to update this function
801/**============================================================================
802 @brief hdd_IsWAIPacket() - Checks the packet is WAI or not.
803
804 @param pVosPacket : [in] pointer to vos packet
805 @return : VOS_TRUE if the packet is WAI
806 : VOS_FALSE otherwise
807 ===========================================================================*/
808
809v_BOOL_t hdd_IsWAIPacket( vos_pkt_t *pVosPacket )
810{
811 VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
812 v_BOOL_t fIsWAI = VOS_FALSE;
813 void *pBuffer = NULL;
814
815 // Need to update this function
816 vosStatus = vos_pkt_peek_data( pVosPacket, (v_SIZE_t)HDD_ETHERTYPE_802_1_X_FRAME_OFFSET,
817 &pBuffer, HDD_ETHERTYPE_802_1_X_SIZE );
818
819 if (VOS_IS_STATUS_SUCCESS( vosStatus ) )
820 {
821 if ( vos_be16_to_cpu( *(unsigned short*)pBuffer ) == HDD_ETHERTYPE_WAI)
822 {
823 fIsWAI = VOS_TRUE;
824 }
825 }
826
827 return fIsWAI;
828}
829#endif /* FEATURE_WLAN_WAPI */
830
831/**============================================================================
832 @brief hdd_tx_complete_cbk() - Callback function invoked by TL
833 to indicate that a packet has been transmitted across the SDIO bus
834 succesfully. OS packet resources can be released after this cbk.
835
836 @param vosContext : [in] pointer to VOS context
837 @param pVosPacket : [in] pointer to VOS packet (containing skb)
838 @param vosStatusIn : [in] status of the transmission
839
840 @return : VOS_STATUS_E_FAILURE if any errors encountered
841 : VOS_STATUS_SUCCESS otherwise
842 ===========================================================================*/
843VOS_STATUS hdd_tx_complete_cbk( v_VOID_t *vosContext,
844 vos_pkt_t *pVosPacket,
845 VOS_STATUS vosStatusIn )
846{
847 VOS_STATUS status = VOS_STATUS_SUCCESS;
848 hdd_adapter_t *pAdapter = NULL;
849 hdd_context_t *pHddCtx = NULL;
850 void* pOsPkt = NULL;
851
852 if( ( NULL == vosContext ) || ( NULL == pVosPacket ) )
853 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700854 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Null params being passed", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700855 return VOS_STATUS_E_FAILURE;
856 }
857
858 //Return the skb to the OS
859 status = vos_pkt_get_os_packet( pVosPacket, &pOsPkt, VOS_TRUE );
860 if(!VOS_IS_STATUS_SUCCESS( status ))
861 {
862 //This is bad but still try to free the VOSS resources if we can
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700863 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 -0700864 vos_pkt_return_packet( pVosPacket );
865 return VOS_STATUS_E_FAILURE;
866 }
867
868 //Get the HDD context.
869 pHddCtx = (hdd_context_t *)vos_get_context( VOS_MODULE_ID_HDD, vosContext );
870 //Get the Adapter context.
871 pAdapter = hdd_get_adapter(pHddCtx,WLAN_HDD_INFRA_STATION);
872 if(pAdapter == NULL)
873 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700874 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700875 }
876 else
877 {
878 ++pAdapter->hdd_stats.hddTxRxStats.txCompleted;
879 }
880
881 kfree_skb((struct sk_buff *)pOsPkt);
882
883 //Return the VOS packet resources.
884 status = vos_pkt_return_packet( pVosPacket );
885 if(!VOS_IS_STATUS_SUCCESS( status ))
886 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700887 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 -0700888 }
889
890 return status;
891}
892
893
894/**============================================================================
895 @brief hdd_tx_fetch_packet_cbk() - Callback function invoked by TL to
896 fetch a packet for transmission.
897
898 @param vosContext : [in] pointer to VOS context
899 @param staId : [in] Station for which TL is requesting a pkt
900 @param ac : [in] access category requested by TL
901 @param pVosPacket : [out] pointer to VOS packet packet pointer
902 @param pPktMetaInfo : [out] pointer to meta info for the pkt
903
904 @return : VOS_STATUS_E_EMPTY if no packets to transmit
905 : VOS_STATUS_E_FAILURE if any errors encountered
906 : VOS_STATUS_SUCCESS otherwise
907 ===========================================================================*/
908VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext,
909 v_U8_t *pStaId,
910 WLANTL_ACEnumType ac,
911 vos_pkt_t **ppVosPacket,
912 WLANTL_MetaInfoType *pPktMetaInfo )
913{
914 VOS_STATUS status = VOS_STATUS_E_FAILURE;
915 hdd_adapter_t *pAdapter = NULL;
916 hdd_context_t *pHddCtx = NULL;
917 hdd_list_node_t *anchor = NULL;
918 skb_list_node_t *pktNode = NULL;
919 struct sk_buff *skb = NULL;
920 vos_pkt_t *pVosPacket = NULL;
921 v_MACADDR_t* pDestMacAddress = NULL;
922 v_TIME_t timestamp;
923 WLANTL_ACEnumType newAc;
924 v_SIZE_t size = 0;
925 tANI_U8 acAdmitted, i;
926
927 //Sanity check on inputs
928 if ( ( NULL == vosContext ) ||
929 ( NULL == pStaId ) ||
930 ( NULL == ppVosPacket ) ||
931 ( NULL == pPktMetaInfo ) )
932 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700933 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Null Params being passed", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700934 return VOS_STATUS_E_FAILURE;
935 }
936
937 //Get the HDD context.
938 pHddCtx = (hdd_context_t *)vos_get_context( VOS_MODULE_ID_HDD, vosContext );
939 if(pHddCtx == NULL)
940 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700941 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700942 return VOS_STATUS_E_FAILURE;
943 }
944
945 pAdapter = pHddCtx->sta_to_adapter[*pStaId];
946 if( NULL == pAdapter )
947 {
948 VOS_ASSERT(0);
949 return VOS_STATUS_E_FAILURE;
950 }
951
952 ++pAdapter->hdd_stats.hddTxRxStats.txFetched;
953
954 *ppVosPacket = NULL;
955
956 //Make sure the AC being asked for is sane
957 if( ac >= WLANTL_MAX_AC || ac < 0)
958 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700959 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 -0700960 return VOS_STATUS_E_FAILURE;
961 }
962
963 ++pAdapter->hdd_stats.hddTxRxStats.txFetchedAC[ac];
964
965#ifdef HDD_WMM_DEBUG
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700966 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 -0700967#endif // HDD_WMM_DEBUG
968
969 // We find an AC with packets
970 // or we determine we have no more packets to send
971 // HDD is not allowed to change AC.
972
973 // has this AC been admitted? or
974 // To allow EAPOL packets when not authenticated
975 if (unlikely((0==pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed) &&
976 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.uIsAuthenticated))
977 {
978 ++pAdapter->hdd_stats.hddTxRxStats.txFetchEmpty;
979#ifdef HDD_WMM_DEBUG
980 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700981 "%s: no packets pending", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700982#endif // HDD_WMM_DEBUG
983 return VOS_STATUS_E_FAILURE;
984 }
985
986 // do we have any packets pending in this AC?
987 hdd_list_size( &pAdapter->wmm_tx_queue[ac], &size );
988 if( size > 0 )
989 {
990 // yes, so process it
991#ifdef HDD_WMM_DEBUG
992 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700993 "%s: AC %d has packets pending", __func__, ac);
Jeff Johnson295189b2012-06-20 16:38:30 -0700994#endif // HDD_WMM_DEBUG
995 }
996 else
997 {
998 ++pAdapter->hdd_stats.hddTxRxStats.txFetchEmpty;
999#ifdef HDD_WMM_DEBUG
1000 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001001 "%s: no packets pending", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001002#endif // HDD_WMM_DEBUG
1003 return VOS_STATUS_E_FAILURE;
1004 }
1005
1006 //Get the vos packet. I don't want to dequeue and enqueue again if we are out of VOS resources
1007 //This simplifies the locking and unlocking of Tx queue
1008 status = vos_pkt_wrap_data_packet( &pVosPacket,
1009 VOS_PKT_TYPE_TX_802_3_DATA,
1010 NULL, //OS Pkt is not being passed
1011 hdd_tx_low_resource_cbk,
1012 pAdapter );
1013
1014 if (status == VOS_STATUS_E_ALREADY || status == VOS_STATUS_E_RESOURCES)
1015 {
1016 //Remember VOS is in a low resource situation
1017 pAdapter->isVosOutOfResource = VOS_TRUE;
1018 ++pAdapter->hdd_stats.hddTxRxStats.txFetchLowResources;
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001019 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s: VOSS in Low Resource scenario", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001020 //TL will now think we have no more packets in this AC
1021 return VOS_STATUS_E_FAILURE;
1022 }
1023
1024 //Remove the packet from the queue
1025 spin_lock_bh(&pAdapter->wmm_tx_queue[ac].lock);
1026 status = hdd_list_remove_front( &pAdapter->wmm_tx_queue[ac], &anchor );
1027 spin_unlock_bh(&pAdapter->wmm_tx_queue[ac].lock);
1028
1029 if(VOS_STATUS_SUCCESS == status)
1030 {
1031 //If success then we got a valid packet from some AC
1032 pktNode = list_entry(anchor, skb_list_node_t, anchor);
1033 skb = pktNode->skb;
1034 }
1035 else
1036 {
1037 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError;
Madan Mohan Koyyalamudi60a6a8d2012-10-21 11:57:42 -07001038 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "%s: Error in de-queuing "
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001039 "skb from Tx queue status = %d", __func__, status );
Jeff Johnson295189b2012-06-20 16:38:30 -07001040 vos_pkt_return_packet(pVosPacket);
1041 return VOS_STATUS_E_FAILURE;
1042 }
1043
1044 //Attach skb to VOS packet.
1045 status = vos_pkt_set_os_packet( pVosPacket, skb );
1046 if (status != VOS_STATUS_SUCCESS)
1047 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001048 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s: Error attaching skb", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001049 vos_pkt_return_packet(pVosPacket);
1050 ++pAdapter->stats.tx_dropped;
1051 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError;
1052 kfree_skb(skb);
1053 return VOS_STATUS_E_FAILURE;
1054 }
1055
1056 //Just being paranoid. To be removed later
1057 if(pVosPacket == NULL)
1058 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001059 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 -07001060 ++pAdapter->stats.tx_dropped;
1061 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError;
1062 kfree_skb(skb);
1063 return VOS_STATUS_E_FAILURE;
1064 }
1065
Chilam NG571c65a2013-01-19 12:27:36 +05301066#ifdef FEATURE_WLAN_TDLS
1067 {
1068 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
Chilam NG571c65a2013-01-19 12:27:36 +05301069 u8 mac[6];
1070
Hoonki Lee387663d2013-02-05 18:08:43 -08001071 wlan_hdd_tdls_extract_da(skb, mac);
Chilam NG571c65a2013-01-19 12:27:36 +05301072
Hoonki Lee5fcc4582013-02-05 20:28:26 -08001073 if (vos_is_macaddr_group((v_MACADDR_t *)mac)) {
Chilam NG571c65a2013-01-19 12:27:36 +05301074 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1075 "broadcast packet, not adding to peer list");
1076 } else if (memcmp(pHddStaCtx->conn_info.bssId,
1077 mac, 6) != 0) {
1078 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1079 "extract mac:%x %x %x %x %x %x",
1080 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
1081
Hoonki Lee387663d2013-02-05 18:08:43 -08001082 wlan_hdd_tdls_increment_pkt_count(mac, 1);
Chilam NG571c65a2013-01-19 12:27:36 +05301083 } else {
1084 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1085 "packet da is bssid, not adding to peer list");
1086 }
1087 }
1088#endif
1089
Jeff Johnson295189b2012-06-20 16:38:30 -07001090 //Return VOS packet to TL;
1091 *ppVosPacket = pVosPacket;
1092
1093 //Fill out the meta information needed by TL
1094 //FIXME This timestamp is really the time stamp of wrap_data_packet
1095 vos_pkt_get_timestamp( pVosPacket, &timestamp );
1096 pPktMetaInfo->usTimeStamp = (v_U16_t)timestamp;
1097
1098 if(pAdapter->sessionCtx.station.conn_info.uIsAuthenticated == VOS_TRUE)
1099 pPktMetaInfo->ucIsEapol = 0;
1100 else
1101 pPktMetaInfo->ucIsEapol = hdd_IsEAPOLPacket( pVosPacket ) ? 1 : 0;
1102
1103#ifdef FEATURE_WLAN_WAPI
1104 // Override usIsEapol value when its zero for WAPI case
1105 pPktMetaInfo->ucIsWai = hdd_IsWAIPacket( pVosPacket ) ? 1 : 0;
1106#endif /* FEATURE_WLAN_WAPI */
1107
1108 if ((HDD_WMM_USER_MODE_NO_QOS == pHddCtx->cfg_ini->WmmMode) ||
1109 (!pAdapter->hddWmmStatus.wmmQap))
1110 {
1111 // either we don't want QoS or the AP doesn't support QoS
1112 pPktMetaInfo->ucUP = 0;
1113 pPktMetaInfo->ucTID = 0;
1114 }
1115 else
1116 {
1117 /* 1. Check if ACM is set for this AC
1118 * 2. If set, check if this AC had already admitted
1119 * 3. If not already admitted, downgrade the UP to next best UP */
1120 if(!pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessRequired ||
1121 pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcTspecValid)
1122 {
1123 pPktMetaInfo->ucUP = pktNode->userPriority;
1124 pPktMetaInfo->ucTID = pPktMetaInfo->ucUP;
1125 }
1126 else
1127 {
1128 //Downgrade the UP
1129 acAdmitted = pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcTspecValid;
1130 newAc = WLANTL_AC_BK;
1131 for (i=ac-1; i>0; i--)
1132 {
1133 if (pAdapter->hddWmmStatus.wmmAcStatus[i].wmmAcAccessRequired == 0)
1134 {
1135 newAc = i;
1136 break;
1137 }
1138 }
1139 pPktMetaInfo->ucUP = hddWmmAcToHighestUp[newAc];
1140 pPktMetaInfo->ucTID = pPktMetaInfo->ucUP;
1141 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,"Downgrading UP %d to UP %d ", pktNode->userPriority, pPktMetaInfo->ucUP);
1142 }
1143 }
1144
1145 pPktMetaInfo->ucType = 0; //FIXME Don't know what this is
1146 pPktMetaInfo->ucDisableFrmXtl = 0; //802.3 frame so we need to xlate
1147 if ( 1 < size )
1148 {
1149 pPktMetaInfo->bMorePackets = 1; //HDD has more packets to send
1150 }
1151 else
1152 {
1153 pPktMetaInfo->bMorePackets = 0;
1154 }
1155
1156 //Extract the destination address from ethernet frame
1157 pDestMacAddress = (v_MACADDR_t*)skb->data;
1158 pPktMetaInfo->ucBcast = vos_is_macaddr_broadcast( pDestMacAddress ) ? 1 : 0;
1159 pPktMetaInfo->ucMcast = vos_is_macaddr_group( pDestMacAddress ) ? 1 : 0;
1160
1161
1162
1163 // if we are in a backpressure situation see if we can turn the hose back on
1164 if ( (pAdapter->isTxSuspended[ac]) &&
1165 (size <= HDD_TX_QUEUE_LOW_WATER_MARK) )
1166 {
1167 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDePressured;
1168 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDePressuredAC[ac];
1169 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001170 "%s: TX queue[%d] re-enabled", __func__, ac);
Jeff Johnson295189b2012-06-20 16:38:30 -07001171 pAdapter->isTxSuspended[ac] = VOS_FALSE;
1172 netif_tx_wake_queue(netdev_get_tx_queue(pAdapter->dev,
1173 skb_get_queue_mapping(skb) ));
1174 }
1175
1176
1177 // We're giving the packet to TL so consider it transmitted from
1178 // a statistics perspective. We account for it here instead of
1179 // when the packet is returned for two reasons. First, TL will
1180 // manipulate the skb to the point where the len field is not
1181 // accurate, leading to inaccurate byte counts if we account for
1182 // it later. Second, TL does not provide any feedback as to
1183 // whether or not the packet was successfully sent over the air,
1184 // so the packet counts will be the same regardless of where we
1185 // account for them
1186 pAdapter->stats.tx_bytes += skb->len;
1187 ++pAdapter->stats.tx_packets;
1188 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeued;
1189 ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeuedAC[ac];
1190
1191 if(pHddCtx->cfg_ini->thermalMitigationEnable)
1192 {
1193 if(mutex_lock_interruptible(&pHddCtx->tmInfo.tmOperationLock))
1194 {
1195 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001196 "%s: Tm Lock fail", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001197 return VOS_STATUS_E_FAILURE;
1198 }
1199 if(WLAN_HDD_TM_LEVEL_1 < pHddCtx->tmInfo.currentTmLevel)
1200 {
1201 if(0 == pHddCtx->tmInfo.txFrameCount)
1202 {
1203 /* Just recovered from sleep timeout */
1204 pHddCtx->tmInfo.lastOpenTs = timestamp;
1205 }
1206
1207 if(((timestamp - pHddCtx->tmInfo.lastOpenTs) > (pHddCtx->tmInfo.tmAction.txOperationDuration / 10)) &&
1208 (pHddCtx->tmInfo.txFrameCount >= pHddCtx->tmInfo.tmAction.txBlockFrameCountThreshold))
1209 {
1210 spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
1211 /* During TX open duration, TX frame count is larger than threshold
1212 * Block TX during Sleep time */
1213 netif_tx_stop_all_queues(pAdapter->dev);
1214 spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
1215 pHddCtx->tmInfo.lastblockTs = timestamp;
1216 if(VOS_TIMER_STATE_STOPPED == vos_timer_getCurrentState(&pHddCtx->tmInfo.txSleepTimer))
1217 {
1218 vos_timer_start(&pHddCtx->tmInfo.txSleepTimer, pHddCtx->tmInfo.tmAction.txSleepDuration);
1219 }
1220 }
1221 else if(((timestamp - pHddCtx->tmInfo.lastOpenTs) > (pHddCtx->tmInfo.tmAction.txOperationDuration / 10)) &&
1222 (pHddCtx->tmInfo.txFrameCount < pHddCtx->tmInfo.tmAction.txBlockFrameCountThreshold))
1223 {
1224 /* During TX open duration, TX frame count is less than threshold
1225 * Reset count and timestamp to prepare next cycle */
1226 pHddCtx->tmInfo.lastOpenTs = timestamp;
1227 pHddCtx->tmInfo.txFrameCount = 0;
1228 }
1229 else
1230 {
1231 /* Do Nothing */
1232 }
1233 pHddCtx->tmInfo.txFrameCount++;
1234 }
1235 mutex_unlock(&pHddCtx->tmInfo.tmOperationLock);
1236 }
1237
1238
1239#ifdef HDD_WMM_DEBUG
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001240 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 -07001241#endif // HDD_WMM_DEBUG
1242
1243 return status;
1244}
1245
1246
1247/**============================================================================
1248 @brief hdd_tx_low_resource_cbk() - Callback function invoked in the
1249 case where VOS packets are not available at the time of the call to get
1250 packets. This callback function is invoked by VOS when packets are
1251 available.
1252
1253 @param pVosPacket : [in] pointer to VOS packet
1254 @param userData : [in] opaque user data that was passed initially
1255
1256 @return : VOS_STATUS_E_FAILURE if any errors encountered,
1257 : VOS_STATUS_SUCCESS otherwise
1258 =============================================================================*/
1259VOS_STATUS hdd_tx_low_resource_cbk( vos_pkt_t *pVosPacket,
1260 v_VOID_t *userData )
1261{
1262 VOS_STATUS status;
1263 v_SINT_t i = 0;
1264 v_SIZE_t size = 0;
1265 hdd_adapter_t* pAdapter = (hdd_adapter_t *)userData;
1266
1267 if(pAdapter == NULL)
1268 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001269 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001270 return VOS_STATUS_E_FAILURE;
1271 }
1272
1273 //Return the packet to VOS. We just needed to know that VOS is out of low resource
1274 //situation. Here we will only signal TL that there is a pending data for a STA.
1275 //VOS packet will be requested (if needed) when TL comes back to fetch data.
1276 vos_pkt_return_packet( pVosPacket );
1277
1278 pAdapter->isVosOutOfResource = VOS_FALSE;
1279
1280 //Indicate to TL that there is pending data if a queue is non empty
1281 for( i=NUM_TX_QUEUES-1; i>=0; --i )
1282 {
1283 size = 0;
1284 hdd_list_size( &pAdapter->wmm_tx_queue[i], &size );
1285 if ( size > 0 )
1286 {
1287 status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
1288 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId [0],
1289 (WLANTL_ACEnumType)i );
1290 if( !VOS_IS_STATUS_SUCCESS( status ) )
1291 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001292 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 -07001293 }
1294 }
1295 }
1296
1297 return VOS_STATUS_SUCCESS;
1298}
1299
1300
1301/**============================================================================
1302 @brief hdd_rx_packet_cbk() - Receive callback registered with TL.
1303 TL will call this to notify the HDD when one or more packets were
1304 received for a registered STA.
1305
1306 @param vosContext : [in] pointer to VOS context
1307 @param pVosPacketChain : [in] pointer to VOS packet chain
1308 @param staId : [in] Station Id
1309 @param pRxMetaInfo : [in] pointer to meta info for the received pkt(s)
1310
1311 @return : VOS_STATUS_E_FAILURE if any errors encountered,
1312 : VOS_STATUS_SUCCESS otherwise
1313 ===========================================================================*/
1314VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext,
1315 vos_pkt_t *pVosPacketChain,
1316 v_U8_t staId,
1317 WLANTL_RxMetaInfoType* pRxMetaInfo )
1318{
1319 hdd_adapter_t *pAdapter = NULL;
1320 hdd_context_t *pHddCtx = NULL;
1321 VOS_STATUS status = VOS_STATUS_E_FAILURE;
1322 int rxstat;
1323 struct sk_buff *skb = NULL;
1324 vos_pkt_t* pVosPacket;
1325 vos_pkt_t* pNextVosPacket;
1326
1327 //Sanity check on inputs
1328 if ( ( NULL == vosContext ) ||
1329 ( NULL == pVosPacketChain ) ||
1330 ( NULL == pRxMetaInfo ) )
1331 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001332 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Null params being passed", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001333 return VOS_STATUS_E_FAILURE;
1334 }
1335
1336 pHddCtx = (hdd_context_t *)vos_get_context( VOS_MODULE_ID_HDD, vosContext );
1337 if ( NULL == pHddCtx )
1338 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001339 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001340 return VOS_STATUS_E_FAILURE;
1341 }
1342
1343 pAdapter = pHddCtx->sta_to_adapter[staId];
1344 if( NULL == pAdapter )
1345 {
1346 VOS_ASSERT(0);
1347 return VOS_STATUS_E_FAILURE;
1348 }
1349
1350 ++pAdapter->hdd_stats.hddTxRxStats.rxChains;
1351
1352 // walk the chain until all are processed
1353 pVosPacket = pVosPacketChain;
1354 do
1355 {
1356 // get the pointer to the next packet in the chain
1357 // (but don't unlink the packet since we free the entire chain later)
1358 status = vos_pkt_walk_packet_chain( pVosPacket, &pNextVosPacket, VOS_FALSE);
1359
1360 // both "success" and "empty" are acceptable results
1361 if (!((status == VOS_STATUS_SUCCESS) || (status == VOS_STATUS_E_EMPTY)))
1362 {
1363 ++pAdapter->hdd_stats.hddTxRxStats.rxDropped;
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001364 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Failure walking packet chain", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001365 return VOS_STATUS_E_FAILURE;
1366 }
1367
1368 // Extract the OS packet (skb).
1369 // Tell VOS to detach the OS packet from the VOS packet
1370 status = vos_pkt_get_os_packet( pVosPacket, (v_VOID_t **)&skb, VOS_TRUE );
1371 if(!VOS_IS_STATUS_SUCCESS( status ))
1372 {
1373 ++pAdapter->hdd_stats.hddTxRxStats.rxDropped;
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001374 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 -07001375 return VOS_STATUS_E_FAILURE;
1376 }
Jeff Johnsone7245742012-09-05 17:12:55 -07001377
1378 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
1379 {
1380 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
1381 "Magic cookie(%x) for adapter sanity verification is invalid", pAdapter->magic);
1382 return eHAL_STATUS_FAILURE;
1383 }
1384
Chilam Ng1279e232013-01-25 15:06:52 -08001385#ifdef FEATURE_WLAN_TDLS
1386 {
1387 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
Chilam Ng1279e232013-01-25 15:06:52 -08001388 u8 mac[6];
1389
Hoonki Lee387663d2013-02-05 18:08:43 -08001390 wlan_hdd_tdls_extract_sa(skb, mac);
Chilam Ng1279e232013-01-25 15:06:52 -08001391
Hoonki Lee5fcc4582013-02-05 20:28:26 -08001392 if (vos_is_macaddr_group((v_MACADDR_t *)mac)) {
Chilam Ng1279e232013-01-25 15:06:52 -08001393 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1394 "rx broadcast packet, not adding to peer list");
1395 } else if (memcmp(pHddStaCtx->conn_info.bssId,
1396 mac, 6) != 0) {
1397 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1398 "rx extract mac:%x %x %x %x %x %x",
1399 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
1400
Hoonki Lee387663d2013-02-05 18:08:43 -08001401 wlan_hdd_tdls_increment_pkt_count(mac, 0);
Chilam Ng1279e232013-01-25 15:06:52 -08001402 } else {
1403 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
1404 "rx packet sa is bssid, not adding to peer list");
1405 }
1406 }
1407#endif
1408
Jeff Johnson295189b2012-06-20 16:38:30 -07001409 skb->dev = pAdapter->dev;
1410 skb->protocol = eth_type_trans(skb, skb->dev);
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001411 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnson295189b2012-06-20 16:38:30 -07001412 ++pAdapter->hdd_stats.hddTxRxStats.rxPackets;
1413 ++pAdapter->stats.rx_packets;
1414 pAdapter->stats.rx_bytes += skb->len;
Jeff Johnsone7245742012-09-05 17:12:55 -07001415#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1416 wake_lock_timeout(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION);
1417#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001418 rxstat = netif_rx_ni(skb);
1419 if (NET_RX_SUCCESS == rxstat)
1420 {
1421 ++pAdapter->hdd_stats.hddTxRxStats.rxDelivered;
1422 }
1423 else
1424 {
1425 ++pAdapter->hdd_stats.hddTxRxStats.rxRefused;
1426 }
1427 // now process the next packet in the chain
1428 pVosPacket = pNextVosPacket;
1429
1430 } while (pVosPacket);
1431
1432 //Return the entire VOS packet chain to the resource pool
1433 status = vos_pkt_return_packet( pVosPacketChain );
1434 if(!VOS_IS_STATUS_SUCCESS( status ))
1435 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001436 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Failure returning vos pkt", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001437 }
1438
1439 pAdapter->dev->last_rx = jiffies;
1440
1441 return status;
1442}
1443