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