blob: 3ea2d855eda8cce74ee526619a2bbd8356b15a68 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2012-2015 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
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_tx_rx.c
30 *
31 * Linux HDD Tx/RX APIs
32 */
33
34#include <wlan_hdd_tx_rx.h>
35#include <wlan_hdd_softap_tx_rx.h>
36#include <wlan_hdd_napi.h>
37#include <linux/netdevice.h>
38#include <linux/skbuff.h>
39#include <linux/etherdevice.h>
40#include <cds_sched.h>
41
42#include <wlan_hdd_p2p.h>
43#include <linux/wireless.h>
44#include <net/cfg80211.h>
45#include <net/ieee80211_radiotap.h>
46#include "sap_api.h"
47#include "wlan_hdd_wmm.h"
48
49#ifdef FEATURE_WLAN_TDLS
50#include "wlan_hdd_tdls.h"
51#endif
52#include <wlan_hdd_ipa.h>
53
54#include "wlan_hdd_ocb.h"
55
56#include "wlan_hdd_lro.h"
57
58#ifdef FEATURE_WLAN_DIAG_SUPPORT
59#define HDD_EAPOL_ETHER_TYPE (0x888E)
60#define HDD_EAPOL_ETHER_TYPE_OFFSET (12)
61#define HDD_EAPOL_PACKET_TYPE_OFFSET (15)
62#define HDD_EAPOL_KEY_INFO_OFFSET (19)
63#define HDD_EAPOL_DEST_MAC_OFFSET (0)
64#define HDD_EAPOL_SRC_MAC_OFFSET (6)
65#endif /* FEATURE_WLAN_DIAG_SUPPORT */
66
67const uint8_t hdd_wmm_ac_to_highest_up[] = {
68 SME_QOS_WMM_UP_RESV,
69 SME_QOS_WMM_UP_EE,
70 SME_QOS_WMM_UP_VI,
71 SME_QOS_WMM_UP_NC
72};
73
74/* Mapping Linux AC interpretation to SME AC. */
75const uint8_t hdd_qdisc_ac_to_tl_ac[] = {
76 SME_AC_VO,
77 SME_AC_VI,
78 SME_AC_BE,
79 SME_AC_BK,
80};
81
82#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
83/**
84 * hdd_tx_resume_timer_expired_handler() - TX Q resume timer handler
85 * @adapter_context: pointer to vdev adapter
86 *
87 * If Blocked OS Q is not resumed during timeout period, to prevent
88 * permanent stall, resume OS Q forcefully.
89 *
90 * Return: None
91 */
92void hdd_tx_resume_timer_expired_handler(void *adapter_context)
93{
94 hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context;
95
96 if (!pAdapter) {
97 /* INVALID ARG */
98 return;
99 }
100
101 hddLog(LOG1, FL("Enabling queues"));
102 wlan_hdd_netif_queue_control(pAdapter, WLAN_WAKE_ALL_NETIF_QUEUE,
103 WLAN_CONTROL_PATH);
104 return;
105}
106
107/**
108 * hdd_tx_resume_cb() - Resume OS TX Q.
109 * @adapter_context: pointer to vdev apdapter
110 * @tx_resume: TX Q resume trigger
111 *
112 * Q was stopped due to WLAN TX path low resource condition
113 *
114 * Return: None
115 */
116void hdd_tx_resume_cb(void *adapter_context, bool tx_resume)
117{
118 hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context;
119 hdd_station_ctx_t *hdd_sta_ctx = NULL;
120
121 if (!pAdapter) {
122 /* INVALID ARG */
123 return;
124 }
125
126 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
127
128 /* Resume TX */
129 if (true == tx_resume) {
130 if (CDF_TIMER_STATE_STOPPED !=
131 cdf_mc_timer_get_current_state(&pAdapter->
132 tx_flow_control_timer)) {
133 cdf_mc_timer_stop(&pAdapter->tx_flow_control_timer);
134 }
135 if (cdf_unlikely(hdd_sta_ctx->hdd_ReassocScenario)) {
136 hddLog(LOGW,
137 FL("flow control, tx queues un-pause avoided as we are in REASSOCIATING state"));
138 return;
139 }
140 hddLog(LOG1, FL("Enabling queues"));
141 wlan_hdd_netif_queue_control(pAdapter,
142 WLAN_WAKE_ALL_NETIF_QUEUE,
143 WLAN_DATA_FLOW_CONTROL);
144 }
145#if defined(CONFIG_PER_VDEV_TX_DESC_POOL)
146 else if (false == tx_resume) { /* Pause TX */
147 hddLog(LOG1, FL("Disabling queues"));
148 wlan_hdd_netif_queue_control(pAdapter,
149 WLAN_STOP_ALL_NETIF_QUEUE,
150 WLAN_DATA_FLOW_CONTROL);
151 if (CDF_TIMER_STATE_STOPPED ==
152 cdf_mc_timer_get_current_state(&pAdapter->
153 tx_flow_control_timer)) {
154 CDF_STATUS status;
155 status =
156 cdf_mc_timer_start(&pAdapter->tx_flow_control_timer,
157 WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME);
158 if (!CDF_IS_STATUS_SUCCESS(status))
159 CDF_TRACE(CDF_MODULE_ID_HDD,
160 CDF_TRACE_LEVEL_ERROR,
161 "%s: Failed to start tx_flow_control_timer",
162 __func__);
163 else
164 pAdapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++;
165 }
166 pAdapter->hdd_stats.hddTxRxStats.txflow_pause_cnt++;
167 pAdapter->hdd_stats.hddTxRxStats.is_txflow_paused = true;
168 }
169#endif
170
171 return;
172}
173
174/**
175 * hdd_register_tx_flow_control() - Register TX Flow control
176 * @adapter: adapter handle
177 * @timer_callback: timer callback
178 * @flow_control_fp: txrx flow control
179 *
180 * Return: none
181 */
182void hdd_register_tx_flow_control(hdd_adapter_t *adapter,
183 cdf_mc_timer_callback_t timer_callback,
184 ol_txrx_tx_flow_control_fp flow_control_fp)
185{
186 if (adapter->tx_flow_timer_initialized == false) {
187 cdf_mc_timer_init(&adapter->tx_flow_control_timer,
188 CDF_TIMER_TYPE_SW,
189 timer_callback,
190 adapter);
191 adapter->tx_flow_timer_initialized = true;
192 }
193 ol_txrx_register_tx_flow_control(adapter->sessionId,
194 flow_control_fp,
195 adapter);
196
197}
198
199/**
200 * hdd_deregister_tx_flow_control() - Deregister TX Flow control
201 * @adapter: adapter handle
202 *
203 * Return: none
204 */
205void hdd_deregister_tx_flow_control(hdd_adapter_t *adapter)
206{
207 ol_txrx_deregister_tx_flow_control_cb(adapter->sessionId);
208 if (adapter->tx_flow_timer_initialized == true) {
209 cdf_mc_timer_stop(&adapter->tx_flow_control_timer);
210 cdf_mc_timer_destroy(&adapter->tx_flow_control_timer);
211 adapter->tx_flow_timer_initialized = false;
212 }
213}
214
215/**
216 * hdd_get_tx_resource() - check tx resources and take action
217 * @adapter: adapter handle
218 * @STAId: station id
219 * @timer_value: timer value
220 *
221 * Return: none
222 */
223void hdd_get_tx_resource(hdd_adapter_t *adapter,
224 uint8_t STAId, uint16_t timer_value)
225{
226 if (false ==
227 ol_txrx_get_tx_resource(STAId,
228 adapter->tx_flow_low_watermark,
229 adapter->tx_flow_high_watermark_offset)) {
230 hdd_info("Disabling queues lwm %d hwm offset %d",
231 adapter->tx_flow_low_watermark,
232 adapter->tx_flow_high_watermark_offset);
233 wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE,
234 WLAN_DATA_FLOW_CONTROL);
235 if ((adapter->tx_flow_timer_initialized == true) &&
236 (CDF_TIMER_STATE_STOPPED ==
237 cdf_mc_timer_get_current_state(&adapter->
238 tx_flow_control_timer))) {
239 cdf_mc_timer_start(&adapter->tx_flow_control_timer,
240 timer_value);
241 adapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++;
242 adapter->hdd_stats.hddTxRxStats.txflow_pause_cnt++;
243 adapter->hdd_stats.hddTxRxStats.is_txflow_paused = true;
244 }
245 }
246}
247
248#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
249
250/**
251 * wlan_hdd_is_eapol() - Function to check if frame is EAPOL or not
252 * @skb: skb data
253 *
254 * This function checks if the frame is an EAPOL frame or not
255 *
256 * Return: true (1) if packet is EAPOL
257 *
258 */
259static bool wlan_hdd_is_eapol(struct sk_buff *skb)
260{
261 uint16_t ether_type;
262
263 if (!skb) {
264 hdd_err(FL("skb is NULL"));
265 return false;
266 }
267
268 ether_type = (uint16_t)(*(uint16_t *)
269 (skb->data + HDD_ETHERTYPE_802_1_X_FRAME_OFFSET));
270
271 if (ether_type == CDF_SWAP_U16(HDD_ETHERTYPE_802_1_X))
272 return true;
273
274 return false;
275}
276
277/**
278 * wlan_hdd_is_eapol_or_wai() - Check if frame is EAPOL or WAPI
279 * @skb: skb data
280 *
281 * This function checks if the frame is EAPOL or WAPI.
282 * single routine call will check for both types, thus avoiding
283 * data path performance penalty.
284 *
285 * Return: true (1) if packet is EAPOL or WAPI
286 *
287 */
288static bool wlan_hdd_is_eapol_or_wai(struct sk_buff *skb)
289{
290 uint16_t ether_type;
291
292 if (!skb) {
293 hdd_err(FL("skb is NULL"));
294 return false;
295 }
296
297 ether_type = (uint16_t)(*(uint16_t *)
298 (skb->data + HDD_ETHERTYPE_802_1_X_FRAME_OFFSET));
299
300 if (ether_type == CDF_SWAP_U16(HDD_ETHERTYPE_802_1_X) ||
301 ether_type == CDF_SWAP_U16(HDD_ETHERTYPE_WAI))
302 return true;
303
304 /* No error msg handled since this will happen often */
305 return false;
306}
307
308/**
309 * hdd_hard_start_xmit() - Transmit a frame
310 * @skb: pointer to OS packet (sk_buff)
311 * @dev: pointer to network device
312 *
313 * Function registered with the Linux OS for transmitting
314 * packets. This version of the function directly passes
315 * the packet to Transport Layer.
316 *
317 * Return: Always returns NETDEV_TX_OK
318 */
319int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
320{
321 CDF_STATUS status;
322 sme_ac_enum_type ac;
323 sme_QosWmmUpType up;
324 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
325 bool granted;
326 uint8_t STAId = WLAN_MAX_STA_COUNT;
327 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
328 uint8_t proto_type = 0;
329#ifdef QCA_PKT_PROTO_TRACE
330 hdd_context_t *hddCtxt = WLAN_HDD_GET_CTX(pAdapter);
331#endif /* QCA_PKT_PROTO_TRACE */
332
333#ifdef QCA_WIFI_FTM
334 if (hdd_get_conparam() == CDF_FTM_MODE) {
335 kfree_skb(skb);
336 return NETDEV_TX_OK;
337 }
338#endif
339
340 ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled;
341
342 if (WLAN_HDD_IBSS == pAdapter->device_mode) {
343 struct cdf_mac_addr *pDestMacAddress =
344 (struct cdf_mac_addr *) skb->data;
345
346 if (CDF_STATUS_SUCCESS !=
347 hdd_ibss_get_sta_id(&pAdapter->sessionCtx.station,
348 pDestMacAddress, &STAId))
349 STAId = HDD_WLAN_INVALID_STA_ID;
350
351 if ((STAId == HDD_WLAN_INVALID_STA_ID) &&
352 (cdf_is_macaddr_broadcast(pDestMacAddress) ||
353 cdf_is_macaddr_group(pDestMacAddress))) {
354 STAId = IBSS_BROADCAST_STAID;
355 CDF_TRACE(CDF_MODULE_ID_HDD_DATA,
356 CDF_TRACE_LEVEL_INFO_LOW, "%s: BC/MC packet",
357 __func__);
358 } else if (STAId == HDD_WLAN_INVALID_STA_ID) {
359 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_WARN,
360 "%s: Received Unicast frame with invalid staID",
361 __func__);
362 ++pAdapter->stats.tx_dropped;
363 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
364 kfree_skb(skb);
365 return NETDEV_TX_OK;
366 }
367 } else {
368 STAId = pHddStaCtx->conn_info.staId[0];
369 }
370
371
372 hdd_get_tx_resource(pAdapter, STAId,
373 WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME);
374
375 /* Get TL AC corresponding to Qdisc queue index/AC. */
376 ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping];
377
378 if (!(NBUF_OWNER_ID(skb) == IPA_NBUF_OWNER_ID)) {
379 /* Check if the buffer has enough header room */
380 skb = skb_unshare(skb, GFP_ATOMIC);
381 if (!skb)
382 goto drop_pkt;
383
384 if (skb_headroom(skb) < dev->hard_header_len) {
385 struct sk_buff *tmp;
386 tmp = skb;
387 skb = skb_realloc_headroom(tmp, dev->hard_header_len);
388 dev_kfree_skb(tmp);
389 if (!skb)
390 goto drop_pkt;
391 }
392 }
393
394 /* user priority from IP header, which is already extracted and set from
395 * select_queue call back function
396 */
397 up = skb->priority;
398
399 ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac];
400#ifdef HDD_WMM_DEBUG
401 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_FATAL,
402 "%s: Classified as ac %d up %d", __func__, ac, up);
403#endif /* HDD_WMM_DEBUG */
404
405 if (HDD_PSB_CHANGED == pAdapter->psbChanged) {
406 /* Function which will determine acquire admittance for a
407 * WMM AC is required or not based on psb configuration done
408 * in the framework
409 */
410 hdd_wmm_acquire_access_required(pAdapter, ac);
411 }
412 /*
413 * Make sure we already have access to this access category
414 * or it is EAPOL or WAPI frame during initial authentication which
415 * can have artifically boosted higher qos priority.
416 */
417
418 if (((pAdapter->psbChanged & (1 << ac)) &&
419 likely(pAdapter->hddWmmStatus.wmmAcStatus[ac].
420 wmmAcAccessAllowed)) ||
421 ((pHddStaCtx->conn_info.uIsAuthenticated == false) &&
422 wlan_hdd_is_eapol_or_wai(skb))) {
423 granted = true;
424 } else {
425 status = hdd_wmm_acquire_access(pAdapter, ac, &granted);
426 pAdapter->psbChanged |= (1 << ac);
427 }
428
429 if (!granted) {
430 bool isDefaultAc = false;
431 /* ADDTS request for this AC is sent, for now
432 * send this packet through next avaiable lower
433 * Access category until ADDTS negotiation completes.
434 */
435 while (!likely
436 (pAdapter->hddWmmStatus.wmmAcStatus[ac].
437 wmmAcAccessAllowed)) {
438 switch (ac) {
439 case SME_AC_VO:
440 ac = SME_AC_VI;
441 up = SME_QOS_WMM_UP_VI;
442 break;
443 case SME_AC_VI:
444 ac = SME_AC_BE;
445 up = SME_QOS_WMM_UP_BE;
446 break;
447 case SME_AC_BE:
448 ac = SME_AC_BK;
449 up = SME_QOS_WMM_UP_BK;
450 break;
451 default:
452 ac = SME_AC_BK;
453 up = SME_QOS_WMM_UP_BK;
454 isDefaultAc = true;
455 break;
456 }
457 if (isDefaultAc)
458 break;
459 }
460 skb->priority = up;
461 skb->queue_mapping = hdd_linux_up_to_ac_map[up];
462 }
463
464 wlan_hdd_log_eapol(skb,
465 WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED);
466
467#ifdef QCA_PKT_PROTO_TRACE
468 if ((hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) ||
469 (hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) {
470 proto_type = cds_pkt_get_proto_type(skb,
471 hddCtxt->config->
472 gEnableDebugLog, 0);
473 if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) {
474 cds_pkt_trace_buf_update("ST:T:EPL");
475 } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) {
476 cds_pkt_trace_buf_update("ST:T:DHC");
477 }
478 }
479#endif /* QCA_PKT_PROTO_TRACE */
480
481 pAdapter->stats.tx_bytes += skb->len;
482 ++pAdapter->stats.tx_packets;
483
484 /* Zero out skb's context buffer for the driver to use */
485 cdf_mem_set(skb->cb, sizeof(skb->cb), 0);
486 NBUF_SET_PACKET_TRACK(skb, NBUF_TX_PKT_DATA_TRACK);
487 NBUF_UPDATE_TX_PKT_COUNT(skb, NBUF_TX_PKT_HDD);
488
489 cdf_dp_trace_set_track(skb);
490 DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_PTR_RECORD,
491 (uint8_t *)skb->data, sizeof(skb->data)));
492 DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_RECORD,
493 (uint8_t *)skb->data, cdf_nbuf_len(skb)));
494 if (cdf_nbuf_len(skb) > CDF_DP_TRACE_RECORD_SIZE)
495 DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_RECORD,
496 (uint8_t *)&skb->data[CDF_DP_TRACE_RECORD_SIZE],
497 (cdf_nbuf_len(skb)-CDF_DP_TRACE_RECORD_SIZE)));
498
499 if (ol_tx_send_data_frame(STAId, (cdf_nbuf_t) skb,
500 proto_type) != NULL) {
501 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_WARN,
502 "%s: Failed to send packet to txrx for staid:%d",
503 __func__, STAId);
504 goto drop_pkt;
505 }
506 dev->trans_start = jiffies;
507
508 return NETDEV_TX_OK;
509
510drop_pkt:
511
512 DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_DROP_PACKET_RECORD,
513 (uint8_t *)skb->data, cdf_nbuf_len(skb)));
514 if (cdf_nbuf_len(skb) > CDF_DP_TRACE_RECORD_SIZE)
515 DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_DROP_PACKET_RECORD,
516 (uint8_t *)&skb->data[CDF_DP_TRACE_RECORD_SIZE],
517 (cdf_nbuf_len(skb)-CDF_DP_TRACE_RECORD_SIZE)));
518
519 ++pAdapter->stats.tx_dropped;
520 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
521 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
522 kfree_skb(skb);
523 return NETDEV_TX_OK;
524}
525
526/**
527 * hdd_ibss_get_sta_id() - Get the StationID using the Peer Mac address
528 * @pHddStaCtx: pointer to HDD Station Context
529 * @pMacAddress: pointer to Peer Mac address
530 * @staID: pointer to returned Station Index
531 *
532 * Return: CDF_STATUS_SUCCESS/CDF_STATUS_E_FAILURE
533 */
534
535CDF_STATUS hdd_ibss_get_sta_id(hdd_station_ctx_t *pHddStaCtx,
536 struct cdf_mac_addr *pMacAddress, uint8_t *staId)
537{
538 uint8_t idx;
539
540 for (idx = 0; idx < MAX_IBSS_PEERS; idx++) {
541 if (cdf_mem_compare(&pHddStaCtx->conn_info.peerMacAddress[idx],
542 pMacAddress, CDF_MAC_ADDR_SIZE)) {
543 *staId = pHddStaCtx->conn_info.staId[idx];
544 return CDF_STATUS_SUCCESS;
545 }
546 }
547
548 return CDF_STATUS_E_FAILURE;
549}
550
551/**
552 * __hdd_tx_timeout() - TX timeout handler
553 * @dev: pointer to network device
554 *
555 * This function is registered as a netdev ndo_tx_timeout method, and
556 * is invoked by the kernel if the driver takes too long to transmit a
557 * frame.
558 *
559 * Return: None
560 */
561static void __hdd_tx_timeout(struct net_device *dev)
562{
563 struct netdev_queue *txq;
564 int i = 0;
565
566 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_ERROR,
567 "%s: Transmission timeout occurred jiffies %lu trans_start %lu",
568 __func__, jiffies, dev->trans_start);
569 DPTRACE(cdf_dp_trace(NULL, CDF_DP_TRACE_HDD_TX_TIMEOUT,
570 NULL, 0));
571
572 /* Getting here implies we disabled the TX queues for too
573 * long. Queues are disabled either because of disassociation
574 * or low resource scenarios. In case of disassociation it is
575 * ok to ignore this. But if associated, we have do possible
576 * recovery here
577 */
578
579 for (i = 0; i < NUM_TX_QUEUES; i++) {
580 txq = netdev_get_tx_queue(dev, i);
581 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_INFO,
582 "Queue%d status: %d txq->trans_start %lu",
583 i, netif_tx_queue_stopped(txq), txq->trans_start);
584 }
585
586 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_INFO,
587 "carrier state: %d", netif_carrier_ok(dev));
588}
589
590/**
591 * hdd_tx_timeout() - Wrapper function to protect __hdd_tx_timeout from SSR
592 * @dev: pointer to net_device structure
593 *
594 * Function called by OS if there is any timeout during transmission.
595 * Since HDD simply enqueues packet and returns control to OS right away,
596 * this would never be invoked
597 *
598 * Return: none
599 */
600void hdd_tx_timeout(struct net_device *dev)
601{
602 cds_ssr_protect(__func__);
603 __hdd_tx_timeout(dev);
604 cds_ssr_unprotect(__func__);
605}
606
607/**
608 * @hdd_init_tx_rx() - Initialize Tx/RX module
609 * @pAdapter: pointer to adapter context
610 *
611 * Return: CDF_STATUS_E_FAILURE if any errors encountered,
612 * CDF_STATUS_SUCCESS otherwise
613 */
614CDF_STATUS hdd_init_tx_rx(hdd_adapter_t *pAdapter)
615{
616 CDF_STATUS status = CDF_STATUS_SUCCESS;
617
618 if (NULL == pAdapter) {
619 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_ERROR,
620 FL("pAdapter is NULL"));
621 CDF_ASSERT(0);
622 return CDF_STATUS_E_FAILURE;
623 }
624
625 return status;
626}
627
628/**
629 * @hdd_deinit_tx_rx() - Deinitialize Tx/RX module
630 * @pAdapter: pointer to adapter context
631 *
632 * Return: CDF_STATUS_E_FAILURE if any errors encountered,
633 * CDF_STATUS_SUCCESS otherwise
634 */
635CDF_STATUS hdd_deinit_tx_rx(hdd_adapter_t *pAdapter)
636{
637 CDF_STATUS status = CDF_STATUS_SUCCESS;
638
639 if (NULL == pAdapter) {
640 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_ERROR,
641 FL("pAdapter is NULL"));
642 CDF_ASSERT(0);
643 return CDF_STATUS_E_FAILURE;
644 }
645
646 return status;
647}
648
649/**
650 * hdd_rx_packet_cbk() - Receive packet handler
651 * @cds_context: pointer to CDS context
652 * @rxBuf: pointer to rx cdf_nbuf
653 * @staId: Station Id
654 *
655 * Receive callback registered with TL. TL will call this to notify
656 * the HDD when one or more packets were received for a registered
657 * STA.
658 *
659 * Return: CDF_STATUS_E_FAILURE if any errors encountered,
660 * CDF_STATUS_SUCCESS otherwise
661 */
662CDF_STATUS hdd_rx_packet_cbk(void *cds_context, cdf_nbuf_t rxBuf, uint8_t staId)
663{
664 hdd_adapter_t *pAdapter = NULL;
665 hdd_context_t *pHddCtx = NULL;
666 int rxstat;
667 struct sk_buff *skb = NULL;
668#ifdef QCA_PKT_PROTO_TRACE
669 uint8_t proto_type;
670#endif /* QCA_PKT_PROTO_TRACE */
671 hdd_station_ctx_t *pHddStaCtx = NULL;
672 unsigned int cpu_index;
673
674 /* Sanity check on inputs */
675 if ((NULL == cds_context) || (NULL == rxBuf)) {
676 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_ERROR,
677 "%s: Null params being passed", __func__);
678 return CDF_STATUS_E_FAILURE;
679 }
680
681 pHddCtx = cds_get_context(CDF_MODULE_ID_HDD);
682 if (NULL == pHddCtx) {
683 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_ERROR,
684 "%s: HDD context is Null", __func__);
685 return CDF_STATUS_E_FAILURE;
686 }
687
688 pAdapter = pHddCtx->sta_to_adapter[staId];
689 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
690 hddLog(LOGE,
691 FL("invalid adapter %p or adapter has invalid magic"),
692 pAdapter);
693 return CDF_STATUS_E_FAILURE;
694 }
695 cpu_index = wlan_hdd_get_cpu();
696
697 skb = (struct sk_buff *)rxBuf;
698
699 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) {
700 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_FATAL,
701 "Magic cookie(%x) for adapter sanity verification is invalid",
702 pAdapter->magic);
703 return CDF_STATUS_E_FAILURE;
704 }
705
706 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
707 if ((pHddStaCtx->conn_info.proxyARPService) &&
708 cfg80211_is_gratuitous_arp_unsolicited_na(skb)) {
709 ++pAdapter->hdd_stats.hddTxRxStats.rxDropped[cpu_index];
710 CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_INFO,
711 "%s: Dropping HS 2.0 Gratuitous ARP or Unsolicited NA",
712 __func__);
713 /* Remove SKB from internal tracking table before submitting
714 * it to stack
715 */
716 cdf_nbuf_free(skb);
717 return CDF_STATUS_SUCCESS;
718 }
719
720 wlan_hdd_log_eapol(skb, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED);
721
722#ifdef QCA_PKT_PROTO_TRACE
723 if ((pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) ||
724 (pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) {
725 proto_type = cds_pkt_get_proto_type(skb,
726 pHddCtx->config->
727 gEnableDebugLog, 0);
728 if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) {
729 cds_pkt_trace_buf_update("ST:R:EPL");
730 } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) {
731 cds_pkt_trace_buf_update("ST:R:DHC");
732 }
733 }
734#endif /* QCA_PKT_PROTO_TRACE */
735
736 skb->dev = pAdapter->dev;
737 skb->protocol = eth_type_trans(skb, skb->dev);
738 ++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
739 ++pAdapter->stats.rx_packets;
740 pAdapter->stats.rx_bytes += skb->len;
741#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
742 cdf_wake_lock_timeout_acquire(&pHddCtx->rx_wake_lock,
743 HDD_WAKE_LOCK_DURATION,
744 WIFI_POWER_EVENT_WAKELOCK_HOLD_RX);
745#endif
746
747 /* Remove SKB from internal tracking table before submitting
748 * it to stack
749 */
750 cdf_net_buf_debug_release_skb(rxBuf);
751
752 if (HDD_LRO_NO_RX ==
753 hdd_lro_rx(pHddCtx, pAdapter, skb)) {
754 if (hdd_napi_enabled(HDD_NAPI_ANY))
755 rxstat = netif_receive_skb(skb);
756 else
757 rxstat = netif_rx_ni(skb);
758
759 if (NET_RX_SUCCESS == rxstat)
760 ++pAdapter->hdd_stats.hddTxRxStats.
761 rxDelivered[cpu_index];
762 else
763 ++pAdapter->hdd_stats.hddTxRxStats.
764 rxRefused[cpu_index];
765
766 } else {
767 ++pAdapter->hdd_stats.hddTxRxStats.
768 rxDelivered[cpu_index];
769 }
770
771 pAdapter->dev->last_rx = jiffies;
772
773 return CDF_STATUS_SUCCESS;
774}
775
776#ifdef FEATURE_WLAN_DIAG_SUPPORT
777
778/**
779 * wlan_hdd_get_eapol_params() - Function to extract EAPOL params
780 * @skb: sbb data
781 * @eapol_params: Pointer to hold the parsed EAPOL params
782 * @event_type: Event type to indicate Tx/Rx
783 *
784 * This function parses the input skb data and return the EAPOL parameters if
785 * the packet is an eapol packet.
786 *
787 * Return: -EINVAL if the packet is not an EAPOL packet and 0 on success
788 *
789 */
790static int wlan_hdd_get_eapol_params(struct sk_buff *skb,
791 struct host_event_wlan_eapol *eapol_params,
792 uint8_t event_type)
793{
794 bool ret;
795 uint8_t packet_type;
796
797 ret = wlan_hdd_is_eapol(skb);
798
799 if (!ret)
800 return -EINVAL;
801
802 packet_type = (uint8_t)(*(uint8_t *)
803 (skb->data + HDD_EAPOL_PACKET_TYPE_OFFSET));
804
805 eapol_params->eapol_packet_type = packet_type;
806 eapol_params->eapol_key_info = (uint16_t)(*(uint16_t *)
807 (skb->data + HDD_EAPOL_KEY_INFO_OFFSET));
808 eapol_params->event_sub_type = event_type;
809 eapol_params->eapol_rate = 0;/* As of now, zero */
810
811 cdf_mem_copy(eapol_params->dest_addr,
812 (skb->data + HDD_EAPOL_DEST_MAC_OFFSET),
813 sizeof(eapol_params->dest_addr));
814 cdf_mem_copy(eapol_params->src_addr,
815 (skb->data + HDD_EAPOL_SRC_MAC_OFFSET),
816 sizeof(eapol_params->src_addr));
817 return 0;
818}
819
820/**
821 * wlan_hdd_event_eapol_log() - Function to log EAPOL events
822 * @eapol_params: Structure containing EAPOL params
823 *
824 * This function logs the parsed EAPOL params
825 *
826 * Return: None
827 *
828 */
829static void wlan_hdd_event_eapol_log(struct host_event_wlan_eapol eapol_params)
830{
831 WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct host_event_wlan_eapol);
832
833 wlan_diag_event.event_sub_type = eapol_params.event_sub_type;
834 wlan_diag_event.eapol_packet_type = eapol_params.eapol_packet_type;
835 wlan_diag_event.eapol_key_info = eapol_params.eapol_key_info;
836 wlan_diag_event.eapol_rate = eapol_params.eapol_rate;
837 cdf_mem_copy(wlan_diag_event.dest_addr,
838 eapol_params.dest_addr,
839 sizeof(wlan_diag_event.dest_addr));
840 cdf_mem_copy(wlan_diag_event.src_addr,
841 eapol_params.src_addr,
842 sizeof(wlan_diag_event.src_addr));
843
844 WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_EAPOL);
845}
846
847/**
848 * wlan_hdd_log_eapol() - Logs the EAPOL parameters of a packet
849 * @skb: skb data
850 * @event_type: One of enum wifi_connectivity_events to indicate Tx/Rx
851 *
852 * This function parses the input skb data to get the EAPOL params and log
853 * them to user space, if the packet is EAPOL
854 *
855 * Return: None
856 *
857 */
858void wlan_hdd_log_eapol(struct sk_buff *skb,
859 uint8_t event_type)
860{
861 int ret;
862 struct host_event_wlan_eapol eapol_params;
863
864 ret = wlan_hdd_get_eapol_params(skb, &eapol_params, event_type);
865 if (!ret)
866 wlan_hdd_event_eapol_log(eapol_params);
867}
868#endif /* FEATURE_WLAN_DIAG_SUPPORT */
869
870/**
871 * hdd_reason_type_to_string() - return string conversion of reason type
872 * @reason: reason type
873 *
874 * This utility function helps log string conversion of reason type.
875 *
876 * Return: string conversion of device mode, if match found;
877 * "Unknown" otherwise.
878 */
879const char *hdd_reason_type_to_string(enum netif_reason_type reason)
880{
881 switch (reason) {
882 CASE_RETURN_STRING(WLAN_CONTROL_PATH);
883 CASE_RETURN_STRING(WLAN_DATA_FLOW_CONTROL);
884 CASE_RETURN_STRING(WLAN_FW_PAUSE);
885 CASE_RETURN_STRING(WLAN_TX_ABORT);
886 CASE_RETURN_STRING(WLAN_VDEV_STOP);
887 CASE_RETURN_STRING(WLAN_PEER_UNAUTHORISED);
888 CASE_RETURN_STRING(WLAN_THERMAL_MITIGATION);
889 default:
890 return "Unknown";
891 }
892}
893
894/**
895 * hdd_action_type_to_string() - return string conversion of action type
896 * @action: action type
897 *
898 * This utility function helps log string conversion of action_type.
899 *
900 * Return: string conversion of device mode, if match found;
901 * "Unknown" otherwise.
902 */
903const char *hdd_action_type_to_string(enum netif_action_type action)
904{
905
906 switch (action) {
907 CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE);
908 CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE);
909 CASE_RETURN_STRING(WLAN_WAKE_ALL_NETIF_QUEUE);
910 CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER);
911 CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE_N_CARRIER);
912 CASE_RETURN_STRING(WLAN_NETIF_TX_DISABLE);
913 CASE_RETURN_STRING(WLAN_NETIF_TX_DISABLE_N_CARRIER);
914 CASE_RETURN_STRING(WLAN_NETIF_CARRIER_ON);
915 CASE_RETURN_STRING(WLAN_NETIF_CARRIER_OFF);
916 default:
917 return "Unknown";
918 }
919}
920
921/**
922 * wlan_hdd_update_queue_oper_stats - update queue operation statistics
923 * @adapter: adapter handle
924 * @action: action type
925 * @reason: reason type
926 */
927static void wlan_hdd_update_queue_oper_stats(hdd_adapter_t *adapter,
928 enum netif_action_type action, enum netif_reason_type reason)
929{
930 switch (action) {
931 case WLAN_STOP_ALL_NETIF_QUEUE:
932 case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER:
933 case WLAN_NETIF_TX_DISABLE:
934 case WLAN_NETIF_TX_DISABLE_N_CARRIER:
935 adapter->queue_oper_stats[reason].pause_count++;
936 break;
937 case WLAN_START_ALL_NETIF_QUEUE:
938 case WLAN_WAKE_ALL_NETIF_QUEUE:
939 case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER:
940 adapter->queue_oper_stats[reason].unpause_count++;
941 break;
942 default:
943 break;
944 }
945
946 return;
947}
948
949/**
950 * wlan_hdd_netif_queue_control() - Use for netif_queue related actions
951 * @adapter: adapter handle
952 * @action: action type
953 * @reason: reason type
954 *
955 * This is single function which is used for netif_queue related
956 * actions like start/stop of network queues and on/off carrier
957 * option.
958 *
959 * Return: None
960 */
961void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter,
962 enum netif_action_type action, enum netif_reason_type reason)
963{
964
965 if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) ||
966 (!adapter->dev)) {
967 hdd_err("adapter is invalid");
968 return;
969 }
970
971 switch (action) {
972
973 case WLAN_NETIF_CARRIER_ON:
974 netif_carrier_on(adapter->dev);
975 break;
976
977 case WLAN_NETIF_CARRIER_OFF:
978 netif_carrier_off(adapter->dev);
979 break;
980
981 case WLAN_STOP_ALL_NETIF_QUEUE:
982 spin_lock_bh(&adapter->pause_map_lock);
983 if (!adapter->pause_map)
984 netif_tx_stop_all_queues(adapter->dev);
985 adapter->pause_map |= (1 << reason);
986 spin_unlock_bh(&adapter->pause_map_lock);
987 break;
988
989 case WLAN_START_ALL_NETIF_QUEUE:
990 spin_lock_bh(&adapter->pause_map_lock);
991 adapter->pause_map &= ~(1 << reason);
992 if (!adapter->pause_map)
993 netif_tx_start_all_queues(adapter->dev);
994 spin_unlock_bh(&adapter->pause_map_lock);
995 break;
996
997 case WLAN_WAKE_ALL_NETIF_QUEUE:
998 spin_lock_bh(&adapter->pause_map_lock);
999 adapter->pause_map &= ~(1 << reason);
1000 if (!adapter->pause_map)
1001 netif_tx_wake_all_queues(adapter->dev);
1002 spin_unlock_bh(&adapter->pause_map_lock);
1003 break;
1004
1005 case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER:
1006 spin_lock_bh(&adapter->pause_map_lock);
1007 if (!adapter->pause_map)
1008 netif_tx_stop_all_queues(adapter->dev);
1009 adapter->pause_map |= (1 << reason);
1010 netif_carrier_off(adapter->dev);
1011 spin_unlock_bh(&adapter->pause_map_lock);
1012 break;
1013
1014 case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER:
1015 spin_lock_bh(&adapter->pause_map_lock);
1016 netif_carrier_on(adapter->dev);
1017 adapter->pause_map &= ~(1 << reason);
1018 if (!adapter->pause_map)
1019 netif_tx_start_all_queues(adapter->dev);
1020 spin_unlock_bh(&adapter->pause_map_lock);
1021 break;
1022
1023 case WLAN_NETIF_TX_DISABLE:
1024 spin_lock_bh(&adapter->pause_map_lock);
1025 if (!adapter->pause_map)
1026 netif_tx_disable(adapter->dev);
1027 adapter->pause_map |= (1 << reason);
1028 spin_unlock_bh(&adapter->pause_map_lock);
1029 break;
1030
1031 case WLAN_NETIF_TX_DISABLE_N_CARRIER:
1032 spin_lock_bh(&adapter->pause_map_lock);
1033 if (!adapter->pause_map)
1034 netif_tx_disable(adapter->dev);
1035 adapter->pause_map |= (1 << reason);
1036 netif_carrier_off(adapter->dev);
1037 spin_unlock_bh(&adapter->pause_map_lock);
1038 break;
1039
1040 default:
1041 hdd_err("unsupported action %d", action);
1042 }
1043
1044 spin_lock_bh(&adapter->pause_map_lock);
1045 if (adapter->pause_map & (1 << WLAN_PEER_UNAUTHORISED))
1046 wlan_hdd_process_peer_unauthorised_pause(adapter);
1047 spin_unlock_bh(&adapter->pause_map_lock);
1048
1049
1050 wlan_hdd_update_queue_oper_stats(adapter, action, reason);
1051
1052 adapter->queue_oper_history[adapter->history_index].time =
1053 cdf_system_ticks();
1054 adapter->queue_oper_history[adapter->history_index].netif_action =
1055 action;
1056 adapter->queue_oper_history[adapter->history_index].netif_reason =
1057 reason;
1058 adapter->queue_oper_history[adapter->history_index].pause_map =
1059 adapter->pause_map;
1060 if (++adapter->history_index == WLAN_HDD_MAX_HISTORY_ENTRY)
1061 adapter->history_index = 0;
1062
1063 return;
1064}
1065