blob: 68b3fa7ea6c9bc6cf03dba2392d30e2c61088ebe [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"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080055#include "wlan_hdd_lro.h"
56
Dhanashri Atreb08959a2016-03-01 17:28:03 -080057#include "cdp_txrx_peer_ops.h"
58
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059#ifdef FEATURE_WLAN_DIAG_SUPPORT
60#define HDD_EAPOL_ETHER_TYPE (0x888E)
61#define HDD_EAPOL_ETHER_TYPE_OFFSET (12)
62#define HDD_EAPOL_PACKET_TYPE_OFFSET (15)
63#define HDD_EAPOL_KEY_INFO_OFFSET (19)
64#define HDD_EAPOL_DEST_MAC_OFFSET (0)
65#define HDD_EAPOL_SRC_MAC_OFFSET (6)
Gupta, Kapil3e617072016-02-08 16:58:00 +053066#define EAPOL_MASK 0x8013
67#define EAPOL_M1_BIT_MASK 0x8000
68#define EAPOL_M2_BIT_MASK 0x0001
69#define EAPOL_M3_BIT_MASK 0x8013
70#define EAPOL_M4_BIT_MASK 0x0003
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071#endif /* FEATURE_WLAN_DIAG_SUPPORT */
72
73const uint8_t hdd_wmm_ac_to_highest_up[] = {
74 SME_QOS_WMM_UP_RESV,
75 SME_QOS_WMM_UP_EE,
76 SME_QOS_WMM_UP_VI,
77 SME_QOS_WMM_UP_NC
78};
79
80/* Mapping Linux AC interpretation to SME AC. */
81const uint8_t hdd_qdisc_ac_to_tl_ac[] = {
82 SME_AC_VO,
83 SME_AC_VI,
84 SME_AC_BE,
85 SME_AC_BK,
86};
87
88#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
89/**
90 * hdd_tx_resume_timer_expired_handler() - TX Q resume timer handler
91 * @adapter_context: pointer to vdev adapter
92 *
93 * If Blocked OS Q is not resumed during timeout period, to prevent
94 * permanent stall, resume OS Q forcefully.
95 *
96 * Return: None
97 */
98void hdd_tx_resume_timer_expired_handler(void *adapter_context)
99{
100 hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context;
101
102 if (!pAdapter) {
103 /* INVALID ARG */
104 return;
105 }
106
107 hddLog(LOG1, FL("Enabling queues"));
108 wlan_hdd_netif_queue_control(pAdapter, WLAN_WAKE_ALL_NETIF_QUEUE,
109 WLAN_CONTROL_PATH);
110 return;
111}
112
113/**
114 * hdd_tx_resume_cb() - Resume OS TX Q.
115 * @adapter_context: pointer to vdev apdapter
116 * @tx_resume: TX Q resume trigger
117 *
118 * Q was stopped due to WLAN TX path low resource condition
119 *
120 * Return: None
121 */
122void hdd_tx_resume_cb(void *adapter_context, bool tx_resume)
123{
124 hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context;
125 hdd_station_ctx_t *hdd_sta_ctx = NULL;
126
127 if (!pAdapter) {
128 /* INVALID ARG */
129 return;
130 }
131
132 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
133
134 /* Resume TX */
135 if (true == tx_resume) {
Anurag Chouhan210db072016-02-22 18:42:15 +0530136 if (QDF_TIMER_STATE_STOPPED !=
137 qdf_mc_timer_get_current_state(&pAdapter->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800138 tx_flow_control_timer)) {
Anurag Chouhan210db072016-02-22 18:42:15 +0530139 qdf_mc_timer_stop(&pAdapter->tx_flow_control_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140 }
Anurag Chouhanc5548422016-02-24 18:33:27 +0530141 if (qdf_unlikely(hdd_sta_ctx->hdd_ReassocScenario)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800142 hddLog(LOGW,
143 FL("flow control, tx queues un-pause avoided as we are in REASSOCIATING state"));
144 return;
145 }
146 hddLog(LOG1, FL("Enabling queues"));
147 wlan_hdd_netif_queue_control(pAdapter,
148 WLAN_WAKE_ALL_NETIF_QUEUE,
149 WLAN_DATA_FLOW_CONTROL);
150 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800151 return;
152}
153
154/**
155 * hdd_register_tx_flow_control() - Register TX Flow control
156 * @adapter: adapter handle
157 * @timer_callback: timer callback
158 * @flow_control_fp: txrx flow control
159 *
160 * Return: none
161 */
162void hdd_register_tx_flow_control(hdd_adapter_t *adapter,
Anurag Chouhan210db072016-02-22 18:42:15 +0530163 qdf_mc_timer_callback_t timer_callback,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800164 ol_txrx_tx_flow_control_fp flow_control_fp)
165{
166 if (adapter->tx_flow_timer_initialized == false) {
Anurag Chouhan210db072016-02-22 18:42:15 +0530167 qdf_mc_timer_init(&adapter->tx_flow_control_timer,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530168 QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800169 timer_callback,
170 adapter);
171 adapter->tx_flow_timer_initialized = true;
172 }
173 ol_txrx_register_tx_flow_control(adapter->sessionId,
174 flow_control_fp,
175 adapter);
176
177}
178
179/**
180 * hdd_deregister_tx_flow_control() - Deregister TX Flow control
181 * @adapter: adapter handle
182 *
183 * Return: none
184 */
185void hdd_deregister_tx_flow_control(hdd_adapter_t *adapter)
186{
187 ol_txrx_deregister_tx_flow_control_cb(adapter->sessionId);
188 if (adapter->tx_flow_timer_initialized == true) {
Anurag Chouhan210db072016-02-22 18:42:15 +0530189 qdf_mc_timer_stop(&adapter->tx_flow_control_timer);
190 qdf_mc_timer_destroy(&adapter->tx_flow_control_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800191 adapter->tx_flow_timer_initialized = false;
192 }
193}
194
195/**
196 * hdd_get_tx_resource() - check tx resources and take action
197 * @adapter: adapter handle
198 * @STAId: station id
199 * @timer_value: timer value
200 *
201 * Return: none
202 */
203void hdd_get_tx_resource(hdd_adapter_t *adapter,
204 uint8_t STAId, uint16_t timer_value)
205{
206 if (false ==
207 ol_txrx_get_tx_resource(STAId,
208 adapter->tx_flow_low_watermark,
209 adapter->tx_flow_high_watermark_offset)) {
210 hdd_info("Disabling queues lwm %d hwm offset %d",
211 adapter->tx_flow_low_watermark,
212 adapter->tx_flow_high_watermark_offset);
213 wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE,
214 WLAN_DATA_FLOW_CONTROL);
215 if ((adapter->tx_flow_timer_initialized == true) &&
Anurag Chouhan210db072016-02-22 18:42:15 +0530216 (QDF_TIMER_STATE_STOPPED ==
217 qdf_mc_timer_get_current_state(&adapter->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800218 tx_flow_control_timer))) {
Anurag Chouhan210db072016-02-22 18:42:15 +0530219 qdf_mc_timer_start(&adapter->tx_flow_control_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800220 timer_value);
221 adapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++;
222 adapter->hdd_stats.hddTxRxStats.txflow_pause_cnt++;
223 adapter->hdd_stats.hddTxRxStats.is_txflow_paused = true;
224 }
225 }
226}
227
228#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
229
230/**
231 * wlan_hdd_is_eapol() - Function to check if frame is EAPOL or not
232 * @skb: skb data
233 *
234 * This function checks if the frame is an EAPOL frame or not
235 *
236 * Return: true (1) if packet is EAPOL
237 *
238 */
239static bool wlan_hdd_is_eapol(struct sk_buff *skb)
240{
241 uint16_t ether_type;
242
243 if (!skb) {
244 hdd_err(FL("skb is NULL"));
245 return false;
246 }
247
248 ether_type = (uint16_t)(*(uint16_t *)
249 (skb->data + HDD_ETHERTYPE_802_1_X_FRAME_OFFSET));
250
Anurag Chouhan6d760662016-02-20 16:05:43 +0530251 if (ether_type == QDF_SWAP_U16(HDD_ETHERTYPE_802_1_X))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800252 return true;
253
254 return false;
255}
256
257/**
258 * wlan_hdd_is_eapol_or_wai() - Check if frame is EAPOL or WAPI
259 * @skb: skb data
260 *
261 * This function checks if the frame is EAPOL or WAPI.
262 * single routine call will check for both types, thus avoiding
263 * data path performance penalty.
264 *
265 * Return: true (1) if packet is EAPOL or WAPI
266 *
267 */
268static bool wlan_hdd_is_eapol_or_wai(struct sk_buff *skb)
269{
270 uint16_t ether_type;
271
272 if (!skb) {
273 hdd_err(FL("skb is NULL"));
274 return false;
275 }
276
277 ether_type = (uint16_t)(*(uint16_t *)
278 (skb->data + HDD_ETHERTYPE_802_1_X_FRAME_OFFSET));
279
Anurag Chouhan6d760662016-02-20 16:05:43 +0530280 if (ether_type == QDF_SWAP_U16(HDD_ETHERTYPE_802_1_X) ||
281 ether_type == QDF_SWAP_U16(HDD_ETHERTYPE_WAI))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800282 return true;
283
284 /* No error msg handled since this will happen often */
285 return false;
286}
287
288/**
289 * hdd_hard_start_xmit() - Transmit a frame
290 * @skb: pointer to OS packet (sk_buff)
291 * @dev: pointer to network device
292 *
293 * Function registered with the Linux OS for transmitting
294 * packets. This version of the function directly passes
295 * the packet to Transport Layer.
296 *
297 * Return: Always returns NETDEV_TX_OK
298 */
299int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
300{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530301 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800302 sme_ac_enum_type ac;
303 sme_QosWmmUpType up;
304 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
305 bool granted;
306 uint8_t STAId = WLAN_MAX_STA_COUNT;
307 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800308#ifdef QCA_PKT_PROTO_TRACE
Dhanashri Atre168d2b42016-02-22 14:43:06 -0800309 uint8_t proto_type = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800310 hdd_context_t *hddCtxt = WLAN_HDD_GET_CTX(pAdapter);
311#endif /* QCA_PKT_PROTO_TRACE */
312
313#ifdef QCA_WIFI_FTM
Anurag Chouhan6d760662016-02-20 16:05:43 +0530314 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800315 kfree_skb(skb);
316 return NETDEV_TX_OK;
317 }
318#endif
319
320 ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled;
Prashanth Bhatta9e143052015-12-04 11:56:47 -0800321 if (cds_is_driver_recovering()) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530322 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_WARN,
Prashanth Bhatta9e143052015-12-04 11:56:47 -0800323 "Recovery in progress, dropping the packet");
Govind Singhede435f2015-12-01 16:16:36 +0530324 ++pAdapter->stats.tx_dropped;
325 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
326 kfree_skb(skb);
327 return NETDEV_TX_OK;
328 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800329
Krunal Sonif07bb382016-03-10 13:02:11 -0800330 if (QDF_IBSS_MODE == pAdapter->device_mode) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530331 struct qdf_mac_addr *pDestMacAddress =
332 (struct qdf_mac_addr *) skb->data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800333
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530334 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800335 hdd_ibss_get_sta_id(&pAdapter->sessionCtx.station,
336 pDestMacAddress, &STAId))
337 STAId = HDD_WLAN_INVALID_STA_ID;
338
339 if ((STAId == HDD_WLAN_INVALID_STA_ID) &&
Anurag Chouhanc5548422016-02-24 18:33:27 +0530340 (qdf_is_macaddr_broadcast(pDestMacAddress) ||
341 qdf_is_macaddr_group(pDestMacAddress))) {
Chandrasekaran, Manishekar34e325a2015-12-18 12:07:22 +0530342 STAId = pHddStaCtx->broadcast_ibss_staid;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530343 QDF_TRACE(QDF_MODULE_ID_HDD_DATA,
344 QDF_TRACE_LEVEL_INFO_LOW, "%s: BC/MC packet",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800345 __func__);
346 } else if (STAId == HDD_WLAN_INVALID_STA_ID) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530347 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800348 "%s: Received Unicast frame with invalid staID",
349 __func__);
350 ++pAdapter->stats.tx_dropped;
351 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
352 kfree_skb(skb);
353 return NETDEV_TX_OK;
354 }
355 } else {
Krunal Sonif07bb382016-03-10 13:02:11 -0800356 if (QDF_OCB_MODE != pAdapter->device_mode &&
Samuel Ahn563506a2015-10-05 13:38:39 +0530357 eConnectionState_Associated !=
358 pHddStaCtx->conn_info.connState) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530359 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO,
Hanumantha Reddy Pothula45323022015-06-23 17:14:08 +0530360 FL("Tx frame in not associated state in %d context"),
361 pAdapter->device_mode);
362 ++pAdapter->stats.tx_dropped;
363 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
364 kfree_skb(skb);
365 return NETDEV_TX_OK;
366 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800367 STAId = pHddStaCtx->conn_info.staId[0];
368 }
369
370
371 hdd_get_tx_resource(pAdapter, STAId,
372 WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME);
373
374 /* Get TL AC corresponding to Qdisc queue index/AC. */
375 ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping];
376
Nirav Shahcbc6d722016-03-01 16:24:53 +0530377 if (!qdf_nbuf_ipa_owned_get(skb)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800378 /* Check if the buffer has enough header room */
379 skb = skb_unshare(skb, GFP_ATOMIC);
380 if (!skb)
381 goto drop_pkt;
382
383 if (skb_headroom(skb) < dev->hard_header_len) {
384 struct sk_buff *tmp;
385 tmp = skb;
386 skb = skb_realloc_headroom(tmp, dev->hard_header_len);
387 dev_kfree_skb(tmp);
388 if (!skb)
389 goto drop_pkt;
390 }
391 }
392
393 /* user priority from IP header, which is already extracted and set from
394 * select_queue call back function
395 */
396 up = skb->priority;
397
398 ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac];
399#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530400 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800401 "%s: Classified as ac %d up %d", __func__, ac, up);
402#endif /* HDD_WMM_DEBUG */
403
404 if (HDD_PSB_CHANGED == pAdapter->psbChanged) {
405 /* Function which will determine acquire admittance for a
406 * WMM AC is required or not based on psb configuration done
407 * in the framework
408 */
409 hdd_wmm_acquire_access_required(pAdapter, ac);
410 }
411 /*
412 * Make sure we already have access to this access category
413 * or it is EAPOL or WAPI frame during initial authentication which
414 * can have artifically boosted higher qos priority.
415 */
416
417 if (((pAdapter->psbChanged & (1 << ac)) &&
418 likely(pAdapter->hddWmmStatus.wmmAcStatus[ac].
419 wmmAcAccessAllowed)) ||
420 ((pHddStaCtx->conn_info.uIsAuthenticated == false) &&
421 wlan_hdd_is_eapol_or_wai(skb))) {
422 granted = true;
423 } else {
424 status = hdd_wmm_acquire_access(pAdapter, ac, &granted);
425 pAdapter->psbChanged |= (1 << ac);
426 }
427
428 if (!granted) {
429 bool isDefaultAc = false;
430 /* ADDTS request for this AC is sent, for now
431 * send this packet through next avaiable lower
432 * Access category until ADDTS negotiation completes.
433 */
434 while (!likely
435 (pAdapter->hddWmmStatus.wmmAcStatus[ac].
436 wmmAcAccessAllowed)) {
437 switch (ac) {
438 case SME_AC_VO:
439 ac = SME_AC_VI;
440 up = SME_QOS_WMM_UP_VI;
441 break;
442 case SME_AC_VI:
443 ac = SME_AC_BE;
444 up = SME_QOS_WMM_UP_BE;
445 break;
446 case SME_AC_BE:
447 ac = SME_AC_BK;
448 up = SME_QOS_WMM_UP_BK;
449 break;
450 default:
451 ac = SME_AC_BK;
452 up = SME_QOS_WMM_UP_BK;
453 isDefaultAc = true;
454 break;
455 }
456 if (isDefaultAc)
457 break;
458 }
459 skb->priority = up;
460 skb->queue_mapping = hdd_linux_up_to_ac_map[up];
461 }
462
463 wlan_hdd_log_eapol(skb,
464 WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED);
465
466#ifdef QCA_PKT_PROTO_TRACE
467 if ((hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) ||
468 (hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) {
469 proto_type = cds_pkt_get_proto_type(skb,
470 hddCtxt->config->
471 gEnableDebugLog, 0);
472 if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) {
473 cds_pkt_trace_buf_update("ST:T:EPL");
474 } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) {
475 cds_pkt_trace_buf_update("ST:T:DHC");
476 }
477 }
478#endif /* QCA_PKT_PROTO_TRACE */
479
480 pAdapter->stats.tx_bytes += skb->len;
481 ++pAdapter->stats.tx_packets;
482
483 /* Zero out skb's context buffer for the driver to use */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530484 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +0530485 QDF_NBUF_CB_TX_PACKET_TRACK(skb) = QDF_NBUF_TX_PKT_DATA_TRACK;
486 QDF_NBUF_UPDATE_TX_PKT_COUNT(skb, QDF_NBUF_TX_PKT_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800487
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530488 qdf_dp_trace_set_track(skb);
489 DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_PACKET_PTR_RECORD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800490 (uint8_t *)skb->data, sizeof(skb->data)));
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530491 DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_PACKET_RECORD,
Nirav Shahcbc6d722016-03-01 16:24:53 +0530492 (uint8_t *)skb->data, qdf_nbuf_len(skb)));
493 if (qdf_nbuf_len(skb) > QDF_DP_TRACE_RECORD_SIZE)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530494 DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_PACKET_RECORD,
495 (uint8_t *)&skb->data[QDF_DP_TRACE_RECORD_SIZE],
Nirav Shahcbc6d722016-03-01 16:24:53 +0530496 (qdf_nbuf_len(skb)-QDF_DP_TRACE_RECORD_SIZE)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800497
Dhanashri Atre168d2b42016-02-22 14:43:06 -0800498 /* Check if station is connected */
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800499 if (OL_TXRX_PEER_STATE_CONN ==
Dhanashri Atre168d2b42016-02-22 14:43:06 -0800500 pAdapter->aStaInfo[STAId].tlSTAState) {
501 QDF_TRACE(QDF_MODULE_ID_HDD_DATA,
502 QDF_TRACE_LEVEL_WARN,
503 "%s: station is not connected..dropping pkt",
504 __func__);
505 goto drop_pkt;
506 }
507
508#ifdef QCA_PKT_PROTO_TRACE
509 qdf_nbuf_trace_set_proto_type(skb, proto_type);
510#endif
511
512 /*
513 * If a transmit function is not registered, drop packet
514 */
515 if (!pAdapter->tx_fn) {
516 QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH,
517 "%s: TX function not registered by the data path",
518 __func__);
519 goto drop_pkt;
520 }
521
522 if (pAdapter->tx_fn(ol_txrx_get_vdev_by_sta_id(STAId),
523 (qdf_nbuf_t) skb) != NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530524 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800525 "%s: Failed to send packet to txrx for staid:%d",
526 __func__, STAId);
527 goto drop_pkt;
528 }
529 dev->trans_start = jiffies;
530
531 return NETDEV_TX_OK;
532
533drop_pkt:
534
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530535 DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_DROP_PACKET_RECORD,
Nirav Shahcbc6d722016-03-01 16:24:53 +0530536 (uint8_t *)skb->data, qdf_nbuf_len(skb)));
537 if (qdf_nbuf_len(skb) > QDF_DP_TRACE_RECORD_SIZE)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530538 DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_DROP_PACKET_RECORD,
539 (uint8_t *)&skb->data[QDF_DP_TRACE_RECORD_SIZE],
Nirav Shahcbc6d722016-03-01 16:24:53 +0530540 (qdf_nbuf_len(skb)-QDF_DP_TRACE_RECORD_SIZE)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800541
542 ++pAdapter->stats.tx_dropped;
543 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
544 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
545 kfree_skb(skb);
546 return NETDEV_TX_OK;
547}
548
549/**
550 * hdd_ibss_get_sta_id() - Get the StationID using the Peer Mac address
551 * @pHddStaCtx: pointer to HDD Station Context
552 * @pMacAddress: pointer to Peer Mac address
553 * @staID: pointer to returned Station Index
554 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530555 * Return: QDF_STATUS_SUCCESS/QDF_STATUS_E_FAILURE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800556 */
557
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530558QDF_STATUS hdd_ibss_get_sta_id(hdd_station_ctx_t *pHddStaCtx,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530559 struct qdf_mac_addr *pMacAddress, uint8_t *staId)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800560{
561 uint8_t idx;
562
563 for (idx = 0; idx < MAX_IBSS_PEERS; idx++) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530564 if (!qdf_mem_cmp(&pHddStaCtx->conn_info.peerMacAddress[idx],
Anurag Chouhan6d760662016-02-20 16:05:43 +0530565 pMacAddress, QDF_MAC_ADDR_SIZE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800566 *staId = pHddStaCtx->conn_info.staId[idx];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530567 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800568 }
569 }
570
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530571 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800572}
573
574/**
575 * __hdd_tx_timeout() - TX timeout handler
576 * @dev: pointer to network device
577 *
578 * This function is registered as a netdev ndo_tx_timeout method, and
579 * is invoked by the kernel if the driver takes too long to transmit a
580 * frame.
581 *
582 * Return: None
583 */
584static void __hdd_tx_timeout(struct net_device *dev)
585{
Nirav Shah89223f72016-03-01 18:10:38 +0530586 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
587 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800588 struct netdev_queue *txq;
589 int i = 0;
590
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530591 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800592 "%s: Transmission timeout occurred jiffies %lu trans_start %lu",
593 __func__, jiffies, dev->trans_start);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530594 DPTRACE(qdf_dp_trace(NULL, QDF_DP_TRACE_HDD_TX_TIMEOUT,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800595 NULL, 0));
596
597 /* Getting here implies we disabled the TX queues for too
598 * long. Queues are disabled either because of disassociation
599 * or low resource scenarios. In case of disassociation it is
600 * ok to ignore this. But if associated, we have do possible
601 * recovery here
602 */
603
604 for (i = 0; i < NUM_TX_QUEUES; i++) {
605 txq = netdev_get_tx_queue(dev, i);
Nirav Shah89223f72016-03-01 18:10:38 +0530606 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800607 "Queue%d status: %d txq->trans_start %lu",
608 i, netif_tx_queue_stopped(txq), txq->trans_start);
609 }
610
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530611 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800612 "carrier state: %d", netif_carrier_ok(dev));
Nirav Shah89223f72016-03-01 18:10:38 +0530613 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
614 wlan_hdd_display_netif_queue_history(hdd_ctx);
615 ol_tx_dump_flow_pool_info();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800616}
617
618/**
619 * hdd_tx_timeout() - Wrapper function to protect __hdd_tx_timeout from SSR
620 * @dev: pointer to net_device structure
621 *
622 * Function called by OS if there is any timeout during transmission.
623 * Since HDD simply enqueues packet and returns control to OS right away,
624 * this would never be invoked
625 *
626 * Return: none
627 */
628void hdd_tx_timeout(struct net_device *dev)
629{
630 cds_ssr_protect(__func__);
631 __hdd_tx_timeout(dev);
632 cds_ssr_unprotect(__func__);
633}
634
635/**
636 * @hdd_init_tx_rx() - Initialize Tx/RX module
637 * @pAdapter: pointer to adapter context
638 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530639 * Return: QDF_STATUS_E_FAILURE if any errors encountered,
640 * QDF_STATUS_SUCCESS otherwise
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800641 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530642QDF_STATUS hdd_init_tx_rx(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800643{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530644 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800645
646 if (NULL == pAdapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530647 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800648 FL("pAdapter is NULL"));
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530649 QDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530650 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800651 }
652
653 return status;
654}
655
656/**
657 * @hdd_deinit_tx_rx() - Deinitialize Tx/RX module
658 * @pAdapter: pointer to adapter context
659 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530660 * Return: QDF_STATUS_E_FAILURE if any errors encountered,
661 * QDF_STATUS_SUCCESS otherwise
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800662 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530663QDF_STATUS hdd_deinit_tx_rx(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800664{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530665 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800666
667 if (NULL == pAdapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530668 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800669 FL("pAdapter is NULL"));
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530670 QDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530671 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800672 }
673
674 return status;
675}
676
677/**
678 * hdd_rx_packet_cbk() - Receive packet handler
Dhanashri Atre182b0272016-02-17 15:35:07 -0800679 * @context: pointer to HDD context
Nirav Shahcbc6d722016-03-01 16:24:53 +0530680 * @rxBuf: pointer to rx qdf_nbuf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800681 *
682 * Receive callback registered with TL. TL will call this to notify
683 * the HDD when one or more packets were received for a registered
684 * STA.
685 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530686 * Return: QDF_STATUS_E_FAILURE if any errors encountered,
687 * QDF_STATUS_SUCCESS otherwise
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800688 */
Dhanashri Atre182b0272016-02-17 15:35:07 -0800689QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800690{
691 hdd_adapter_t *pAdapter = NULL;
692 hdd_context_t *pHddCtx = NULL;
693 int rxstat;
694 struct sk_buff *skb = NULL;
695#ifdef QCA_PKT_PROTO_TRACE
696 uint8_t proto_type;
697#endif /* QCA_PKT_PROTO_TRACE */
698 hdd_station_ctx_t *pHddStaCtx = NULL;
699 unsigned int cpu_index;
700
701 /* Sanity check on inputs */
Dhanashri Atre182b0272016-02-17 15:35:07 -0800702 if (unlikely((NULL == context) || (NULL == rxBuf))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530703 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800704 "%s: Null params being passed", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530705 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800706 }
707
Dhanashri Atre182b0272016-02-17 15:35:07 -0800708 pAdapter = (hdd_adapter_t *)context;
709 if (unlikely(WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530710 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800711 "Magic cookie(%x) for adapter sanity verification is invalid",
712 pAdapter->magic);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530713 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800714 }
715
Dhanashri Atre182b0272016-02-17 15:35:07 -0800716 pHddCtx = pAdapter->pHddCtx;
717 if (unlikely(NULL == pHddCtx)) {
718 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
719 "%s: HDD context is Null", __func__);
720 return QDF_STATUS_E_FAILURE;
721 }
722
723 cpu_index = wlan_hdd_get_cpu();
724
725 skb = (struct sk_buff *)rxBuf;
726
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800727 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
728 if ((pHddStaCtx->conn_info.proxyARPService) &&
729 cfg80211_is_gratuitous_arp_unsolicited_na(skb)) {
730 ++pAdapter->hdd_stats.hddTxRxStats.rxDropped[cpu_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530731 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732 "%s: Dropping HS 2.0 Gratuitous ARP or Unsolicited NA",
733 __func__);
734 /* Remove SKB from internal tracking table before submitting
735 * it to stack
736 */
Nirav Shahcbc6d722016-03-01 16:24:53 +0530737 qdf_nbuf_free(skb);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530738 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800739 }
740
741 wlan_hdd_log_eapol(skb, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED);
742
743#ifdef QCA_PKT_PROTO_TRACE
744 if ((pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) ||
745 (pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) {
746 proto_type = cds_pkt_get_proto_type(skb,
747 pHddCtx->config->
748 gEnableDebugLog, 0);
749 if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) {
750 cds_pkt_trace_buf_update("ST:R:EPL");
751 } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) {
752 cds_pkt_trace_buf_update("ST:R:DHC");
753 }
754 }
755#endif /* QCA_PKT_PROTO_TRACE */
756
757 skb->dev = pAdapter->dev;
758 skb->protocol = eth_type_trans(skb, skb->dev);
759 ++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
760 ++pAdapter->stats.rx_packets;
761 pAdapter->stats.rx_bytes += skb->len;
762#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530763 qdf_wake_lock_timeout_acquire(&pHddCtx->rx_wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800764 HDD_WAKE_LOCK_DURATION,
765 WIFI_POWER_EVENT_WAKELOCK_HOLD_RX);
766#endif
767
768 /* Remove SKB from internal tracking table before submitting
769 * it to stack
770 */
Nirav Shahcbc6d722016-03-01 16:24:53 +0530771 qdf_net_buf_debug_release_skb(rxBuf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800772
773 if (HDD_LRO_NO_RX ==
774 hdd_lro_rx(pHddCtx, pAdapter, skb)) {
Orhan K AKYILDIZ4f20db52015-12-30 12:35:44 -0800775 if (hdd_napi_enabled(HDD_NAPI_ANY) &&
776 !pHddCtx->config->enableRxThread)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800777 rxstat = netif_receive_skb(skb);
778 else
779 rxstat = netif_rx_ni(skb);
780
781 if (NET_RX_SUCCESS == rxstat)
782 ++pAdapter->hdd_stats.hddTxRxStats.
783 rxDelivered[cpu_index];
784 else
785 ++pAdapter->hdd_stats.hddTxRxStats.
786 rxRefused[cpu_index];
787
788 } else {
789 ++pAdapter->hdd_stats.hddTxRxStats.
790 rxDelivered[cpu_index];
791 }
792
793 pAdapter->dev->last_rx = jiffies;
794
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530795 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800796}
797
798#ifdef FEATURE_WLAN_DIAG_SUPPORT
799
800/**
801 * wlan_hdd_get_eapol_params() - Function to extract EAPOL params
802 * @skb: sbb data
803 * @eapol_params: Pointer to hold the parsed EAPOL params
804 * @event_type: Event type to indicate Tx/Rx
805 *
806 * This function parses the input skb data and return the EAPOL parameters if
807 * the packet is an eapol packet.
808 *
809 * Return: -EINVAL if the packet is not an EAPOL packet and 0 on success
810 *
811 */
812static int wlan_hdd_get_eapol_params(struct sk_buff *skb,
813 struct host_event_wlan_eapol *eapol_params,
814 uint8_t event_type)
815{
816 bool ret;
817 uint8_t packet_type;
818
819 ret = wlan_hdd_is_eapol(skb);
820
821 if (!ret)
822 return -EINVAL;
823
824 packet_type = (uint8_t)(*(uint8_t *)
825 (skb->data + HDD_EAPOL_PACKET_TYPE_OFFSET));
826
827 eapol_params->eapol_packet_type = packet_type;
828 eapol_params->eapol_key_info = (uint16_t)(*(uint16_t *)
829 (skb->data + HDD_EAPOL_KEY_INFO_OFFSET));
830 eapol_params->event_sub_type = event_type;
831 eapol_params->eapol_rate = 0;/* As of now, zero */
832
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530833 qdf_mem_copy(eapol_params->dest_addr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800834 (skb->data + HDD_EAPOL_DEST_MAC_OFFSET),
835 sizeof(eapol_params->dest_addr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530836 qdf_mem_copy(eapol_params->src_addr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800837 (skb->data + HDD_EAPOL_SRC_MAC_OFFSET),
838 sizeof(eapol_params->src_addr));
839 return 0;
840}
841
842/**
843 * wlan_hdd_event_eapol_log() - Function to log EAPOL events
844 * @eapol_params: Structure containing EAPOL params
845 *
846 * This function logs the parsed EAPOL params
847 *
848 * Return: None
849 *
850 */
851static void wlan_hdd_event_eapol_log(struct host_event_wlan_eapol eapol_params)
852{
853 WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct host_event_wlan_eapol);
854
855 wlan_diag_event.event_sub_type = eapol_params.event_sub_type;
856 wlan_diag_event.eapol_packet_type = eapol_params.eapol_packet_type;
857 wlan_diag_event.eapol_key_info = eapol_params.eapol_key_info;
858 wlan_diag_event.eapol_rate = eapol_params.eapol_rate;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530859 qdf_mem_copy(wlan_diag_event.dest_addr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800860 eapol_params.dest_addr,
861 sizeof(wlan_diag_event.dest_addr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530862 qdf_mem_copy(wlan_diag_event.src_addr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800863 eapol_params.src_addr,
864 sizeof(wlan_diag_event.src_addr));
865
866 WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_EAPOL);
867}
868
869/**
870 * wlan_hdd_log_eapol() - Logs the EAPOL parameters of a packet
871 * @skb: skb data
872 * @event_type: One of enum wifi_connectivity_events to indicate Tx/Rx
873 *
874 * This function parses the input skb data to get the EAPOL params and log
875 * them to user space, if the packet is EAPOL
876 *
877 * Return: None
878 *
879 */
880void wlan_hdd_log_eapol(struct sk_buff *skb,
881 uint8_t event_type)
882{
883 int ret;
884 struct host_event_wlan_eapol eapol_params;
Gupta, Kapil3e617072016-02-08 16:58:00 +0530885 uint16_t key_info;
886 const char *packet_type = "UND";
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800887
888 ret = wlan_hdd_get_eapol_params(skb, &eapol_params, event_type);
889 if (!ret)
Gupta, Kapil3e617072016-02-08 16:58:00 +0530890 return;
891
892 wlan_hdd_event_eapol_log(eapol_params);
893 key_info = eapol_params.eapol_key_info & EAPOL_MASK;
894 if (key_info == EAPOL_M1_BIT_MASK)
895 packet_type = "M1";
896 else if (key_info == EAPOL_M2_BIT_MASK)
897 packet_type = "M2";
898 else if (key_info == EAPOL_M3_BIT_MASK)
899 packet_type = "M3";
900 else if (key_info == EAPOL_M4_BIT_MASK)
901 packet_type = "M4";
902
903 hdd_notice("%s: %s packet", eapol_params.event_sub_type ==
904 WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED ?
905 "RX" : "TX", packet_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800906}
907#endif /* FEATURE_WLAN_DIAG_SUPPORT */
908
909/**
910 * hdd_reason_type_to_string() - return string conversion of reason type
911 * @reason: reason type
912 *
913 * This utility function helps log string conversion of reason type.
914 *
915 * Return: string conversion of device mode, if match found;
916 * "Unknown" otherwise.
917 */
918const char *hdd_reason_type_to_string(enum netif_reason_type reason)
919{
920 switch (reason) {
921 CASE_RETURN_STRING(WLAN_CONTROL_PATH);
922 CASE_RETURN_STRING(WLAN_DATA_FLOW_CONTROL);
923 CASE_RETURN_STRING(WLAN_FW_PAUSE);
924 CASE_RETURN_STRING(WLAN_TX_ABORT);
925 CASE_RETURN_STRING(WLAN_VDEV_STOP);
926 CASE_RETURN_STRING(WLAN_PEER_UNAUTHORISED);
927 CASE_RETURN_STRING(WLAN_THERMAL_MITIGATION);
928 default:
929 return "Unknown";
930 }
931}
932
933/**
934 * hdd_action_type_to_string() - return string conversion of action type
935 * @action: action type
936 *
937 * This utility function helps log string conversion of action_type.
938 *
939 * Return: string conversion of device mode, if match found;
940 * "Unknown" otherwise.
941 */
942const char *hdd_action_type_to_string(enum netif_action_type action)
943{
944
945 switch (action) {
946 CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE);
947 CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE);
948 CASE_RETURN_STRING(WLAN_WAKE_ALL_NETIF_QUEUE);
949 CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER);
950 CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE_N_CARRIER);
951 CASE_RETURN_STRING(WLAN_NETIF_TX_DISABLE);
952 CASE_RETURN_STRING(WLAN_NETIF_TX_DISABLE_N_CARRIER);
953 CASE_RETURN_STRING(WLAN_NETIF_CARRIER_ON);
954 CASE_RETURN_STRING(WLAN_NETIF_CARRIER_OFF);
955 default:
956 return "Unknown";
957 }
958}
959
960/**
961 * wlan_hdd_update_queue_oper_stats - update queue operation statistics
962 * @adapter: adapter handle
963 * @action: action type
964 * @reason: reason type
965 */
966static void wlan_hdd_update_queue_oper_stats(hdd_adapter_t *adapter,
967 enum netif_action_type action, enum netif_reason_type reason)
968{
969 switch (action) {
970 case WLAN_STOP_ALL_NETIF_QUEUE:
971 case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER:
972 case WLAN_NETIF_TX_DISABLE:
973 case WLAN_NETIF_TX_DISABLE_N_CARRIER:
974 adapter->queue_oper_stats[reason].pause_count++;
975 break;
976 case WLAN_START_ALL_NETIF_QUEUE:
977 case WLAN_WAKE_ALL_NETIF_QUEUE:
978 case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER:
979 adapter->queue_oper_stats[reason].unpause_count++;
980 break;
981 default:
982 break;
983 }
984
985 return;
986}
987
988/**
Nirav Shah89223f72016-03-01 18:10:38 +0530989 * wlan_hdd_update_txq_timestamp() - update txq timestamp
990 * @dev: net device
991 *
992 * Return: none
993 */
994void wlan_hdd_update_txq_timestamp(struct net_device *dev)
995{
996 struct netdev_queue *txq;
997 int i;
998 bool unlock;
999
1000 for (i = 0; i < NUM_TX_QUEUES; i++) {
1001 txq = netdev_get_tx_queue(dev, i);
1002 unlock = __netif_tx_trylock(txq);
1003 txq_trans_update(txq);
1004 if (unlock == true)
1005 __netif_tx_unlock(txq);
1006 }
1007}
1008
1009/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001010 * wlan_hdd_netif_queue_control() - Use for netif_queue related actions
1011 * @adapter: adapter handle
1012 * @action: action type
1013 * @reason: reason type
1014 *
1015 * This is single function which is used for netif_queue related
1016 * actions like start/stop of network queues and on/off carrier
1017 * option.
1018 *
1019 * Return: None
1020 */
1021void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter,
1022 enum netif_action_type action, enum netif_reason_type reason)
1023{
1024
1025 if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) ||
1026 (!adapter->dev)) {
1027 hdd_err("adapter is invalid");
1028 return;
1029 }
1030
1031 switch (action) {
1032
1033 case WLAN_NETIF_CARRIER_ON:
1034 netif_carrier_on(adapter->dev);
1035 break;
1036
1037 case WLAN_NETIF_CARRIER_OFF:
1038 netif_carrier_off(adapter->dev);
1039 break;
1040
1041 case WLAN_STOP_ALL_NETIF_QUEUE:
1042 spin_lock_bh(&adapter->pause_map_lock);
Nirav Shah89223f72016-03-01 18:10:38 +05301043 if (!adapter->pause_map) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001044 netif_tx_stop_all_queues(adapter->dev);
Nirav Shah89223f72016-03-01 18:10:38 +05301045 wlan_hdd_update_txq_timestamp(adapter->dev);
1046 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001047 adapter->pause_map |= (1 << reason);
1048 spin_unlock_bh(&adapter->pause_map_lock);
1049 break;
1050
1051 case WLAN_START_ALL_NETIF_QUEUE:
1052 spin_lock_bh(&adapter->pause_map_lock);
1053 adapter->pause_map &= ~(1 << reason);
1054 if (!adapter->pause_map)
1055 netif_tx_start_all_queues(adapter->dev);
1056 spin_unlock_bh(&adapter->pause_map_lock);
1057 break;
1058
1059 case WLAN_WAKE_ALL_NETIF_QUEUE:
1060 spin_lock_bh(&adapter->pause_map_lock);
1061 adapter->pause_map &= ~(1 << reason);
1062 if (!adapter->pause_map)
1063 netif_tx_wake_all_queues(adapter->dev);
1064 spin_unlock_bh(&adapter->pause_map_lock);
1065 break;
1066
1067 case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER:
1068 spin_lock_bh(&adapter->pause_map_lock);
Nirav Shah89223f72016-03-01 18:10:38 +05301069 if (!adapter->pause_map) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001070 netif_tx_stop_all_queues(adapter->dev);
Nirav Shah89223f72016-03-01 18:10:38 +05301071 wlan_hdd_update_txq_timestamp(adapter->dev);
1072 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001073 adapter->pause_map |= (1 << reason);
1074 netif_carrier_off(adapter->dev);
1075 spin_unlock_bh(&adapter->pause_map_lock);
1076 break;
1077
1078 case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER:
1079 spin_lock_bh(&adapter->pause_map_lock);
1080 netif_carrier_on(adapter->dev);
1081 adapter->pause_map &= ~(1 << reason);
1082 if (!adapter->pause_map)
1083 netif_tx_start_all_queues(adapter->dev);
1084 spin_unlock_bh(&adapter->pause_map_lock);
1085 break;
1086
1087 case WLAN_NETIF_TX_DISABLE:
1088 spin_lock_bh(&adapter->pause_map_lock);
Nirav Shah89223f72016-03-01 18:10:38 +05301089 if (!adapter->pause_map) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001090 netif_tx_disable(adapter->dev);
Nirav Shah89223f72016-03-01 18:10:38 +05301091 wlan_hdd_update_txq_timestamp(adapter->dev);
1092 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001093 adapter->pause_map |= (1 << reason);
1094 spin_unlock_bh(&adapter->pause_map_lock);
1095 break;
1096
1097 case WLAN_NETIF_TX_DISABLE_N_CARRIER:
1098 spin_lock_bh(&adapter->pause_map_lock);
Nirav Shah89223f72016-03-01 18:10:38 +05301099 if (!adapter->pause_map) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001100 netif_tx_disable(adapter->dev);
Nirav Shah89223f72016-03-01 18:10:38 +05301101 wlan_hdd_update_txq_timestamp(adapter->dev);
1102 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001103 adapter->pause_map |= (1 << reason);
1104 netif_carrier_off(adapter->dev);
1105 spin_unlock_bh(&adapter->pause_map_lock);
1106 break;
1107
1108 default:
1109 hdd_err("unsupported action %d", action);
1110 }
1111
1112 spin_lock_bh(&adapter->pause_map_lock);
1113 if (adapter->pause_map & (1 << WLAN_PEER_UNAUTHORISED))
1114 wlan_hdd_process_peer_unauthorised_pause(adapter);
1115 spin_unlock_bh(&adapter->pause_map_lock);
1116
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117 wlan_hdd_update_queue_oper_stats(adapter, action, reason);
1118
1119 adapter->queue_oper_history[adapter->history_index].time =
Anurag Chouhan50220ce2016-02-18 20:11:33 +05301120 qdf_system_ticks();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001121 adapter->queue_oper_history[adapter->history_index].netif_action =
1122 action;
1123 adapter->queue_oper_history[adapter->history_index].netif_reason =
1124 reason;
1125 adapter->queue_oper_history[adapter->history_index].pause_map =
1126 adapter->pause_map;
1127 if (++adapter->history_index == WLAN_HDD_MAX_HISTORY_ENTRY)
1128 adapter->history_index = 0;
1129
1130 return;
1131}
1132