blob: 8f98dcf8436669b9148544c700e51a4fc846d9b3 [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/* Include files */
29#include <linux/semaphore.h>
30#include <wlan_hdd_tx_rx.h>
31#include <wlan_hdd_softap_tx_rx.h>
32#include <linux/netdevice.h>
33#include <linux/skbuff.h>
34#include <linux/etherdevice.h>
35#include <cdf_types.h>
36#include <ani_global.h>
37#include <cdf_types.h>
38#include <net/ieee80211_radiotap.h>
39#include <cds_sched.h>
40#include <wlan_hdd_napi.h>
41
42#ifdef IPA_OFFLOAD
43#include <wlan_hdd_ipa.h>
44#endif
45
46/* Preprocessor definitions and constants */
47#undef QCA_HDD_SAP_DUMP_SK_BUFF
48
49/* Type declarations */
50
51/* Function definitions and documenation */
52#ifdef QCA_HDD_SAP_DUMP_SK_BUFF
53/**
54 * hdd_softap_dump_sk_buff() - Dump an skb
55 * @skb: skb to dump
56 *
57 * Return: None
58 */
59static void hdd_softap_dump_sk_buff(struct sk_buff *skb)
60{
61 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
62 "%s: head = %p ", __func__, skb->head);
63 /* CDF_TRACE( CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,"%s: data = %p ", __func__, skb->data); */
64 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
65 "%s: tail = %p ", __func__, skb->tail);
66 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
67 "%s: end = %p ", __func__, skb->end);
68 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
69 "%s: len = %d ", __func__, skb->len);
70 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
71 "%s: data_len = %d ", __func__, skb->data_len);
72 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
73 "%s: mac_len = %d", __func__, skb->mac_len);
74
75 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
76 "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ", skb->data[0],
77 skb->data[1], skb->data[2], skb->data[3], skb->data[4],
78 skb->data[5], skb->data[6], skb->data[7]);
79 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
80 "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", skb->data[8],
81 skb->data[9], skb->data[10], skb->data[11], skb->data[12],
82 skb->data[13], skb->data[14], skb->data[15]);
83}
84#else
85static void hdd_softap_dump_sk_buff(struct sk_buff *skb)
86{
87}
88#endif
89
90#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
91/**
92 * hdd_softap_tx_resume_timer_expired_handler() - TX Q resume timer handler
93 * @adapter_context: pointer to vdev adapter
94 *
95 * TX Q resume timer handler for SAP and P2P GO interface. If Blocked
96 * OS Q is not resumed during timeout period, to prevent permanent
97 * stall, resume OS Q forcefully for SAP and P2P GO interface.
98 *
99 * Return: None
100 */
101void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context)
102{
103 hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context;
104
105 if (!pAdapter) {
106 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
107 "%s: INV ARG", __func__);
108 /* INVALID ARG */
109 return;
110 }
111
112 hddLog(LOG1, FL("Enabling queues"));
113 wlan_hdd_netif_queue_control(pAdapter, WLAN_WAKE_ALL_NETIF_QUEUE,
114 WLAN_CONTROL_PATH);
115 return;
116}
117
118/**
119 * hdd_softap_tx_resume_cb() - Resume OS TX Q.
120 * @adapter_context: pointer to vdev apdapter
121 * @tx_resume: TX Q resume trigger
122 *
123 * Q was stopped due to WLAN TX path low resource condition
124 *
125 * Return: None
126 */
127void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume)
128{
129 hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context;
130
131 if (!pAdapter) {
132 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
133 "%s: INV ARG", __func__);
134 /* INVALID ARG */
135 return;
136 }
137
138 /* Resume TX */
139 if (true == tx_resume) {
140 if (CDF_TIMER_STATE_STOPPED !=
141 cdf_mc_timer_get_current_state(&pAdapter->
142 tx_flow_control_timer)) {
143 cdf_mc_timer_stop(&pAdapter->tx_flow_control_timer);
144 }
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 }
151#if defined(CONFIG_PER_VDEV_TX_DESC_POOL)
152 else if (false == tx_resume) { /* Pause TX */
153 hddLog(LOG1, FL("Disabling queues"));
154 wlan_hdd_netif_queue_control(pAdapter,
155 WLAN_STOP_ALL_NETIF_QUEUE,
156 WLAN_DATA_FLOW_CONTROL);
157 if (CDF_TIMER_STATE_STOPPED ==
158 cdf_mc_timer_get_current_state(&pAdapter->
159 tx_flow_control_timer)) {
160 CDF_STATUS status;
161 status =
162 cdf_mc_timer_start(&pAdapter->tx_flow_control_timer,
163 WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME);
164 if (!CDF_IS_STATUS_SUCCESS(status))
165 CDF_TRACE(CDF_MODULE_ID_HDD,
166 CDF_TRACE_LEVEL_ERROR,
167 "%s: Failed to start tx_flow_control_timer",
168 __func__);
169 else
170 pAdapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++;
171 }
172 }
173#endif
174
175 return;
176}
177#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
178
179/**
180 * hdd_softap_hard_start_xmit() - Transmit a frame
181 * @skb: pointer to OS packet (sk_buff)
182 * @dev: pointer to network device
183 *
184 * Function registered with the Linux OS for transmitting
185 * packets. This version of the function directly passes
186 * the packet to Transport Layer.
187 *
188 * Return: Always returns NETDEV_TX_OK
189 */
190int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
191{
192 sme_ac_enum_type ac = SME_AC_BE;
193 hdd_adapter_t *pAdapter = (hdd_adapter_t *) netdev_priv(dev);
194 hdd_ap_ctx_t *pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pAdapter);
195 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
196 struct cdf_mac_addr *pDestMacAddress;
197 uint8_t STAId;
198 uint8_t proto_type = 0;
199#ifdef QCA_PKT_PROTO_TRACE
200 hdd_context_t *hddCtxt = (hdd_context_t *) pAdapter->pHddCtx;
201#endif /* QCA_PKT_PROTO_TRACE */
202
203 ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled;
204 /* Prevent this function from being called during SSR since TL
205 * context may not be reinitialized at this time which may
206 * lead to a crash.
207 */
208 if (pHddCtx->isLogpInProgress) {
209 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
210 "%s: LOGP in Progress. Ignore!!!", __func__);
211 goto drop_pkt;
212 }
213
214 /*
215 * If the device is operating on a DFS Channel
216 * then check if SAP is in CAC WAIT state and
217 * drop the packets. In CAC WAIT state device
218 * is expected not to transmit any frames.
219 * SAP starts Tx only after the BSS START is
220 * done.
221 */
222 if (pHddApCtx->dfs_cac_block_tx) {
223 goto drop_pkt;
224 }
225
226 pDestMacAddress = (struct cdf_mac_addr *) skb->data;
227
228 if (cdf_is_macaddr_broadcast(pDestMacAddress) ||
229 cdf_is_macaddr_group(pDestMacAddress)) {
230 /* The BC/MC station ID is assigned during BSS
231 * starting phase. SAP will return the station ID
232 * used for BC/MC traffic.
233 */
234 STAId = pHddApCtx->uBCStaId;
235 } else {
236 if (CDF_STATUS_SUCCESS !=
237 hdd_softap_get_sta_id(pAdapter,
238 pDestMacAddress, &STAId)) {
239 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
240 CDF_TRACE_LEVEL_WARN,
241 "%s: Failed to find right station", __func__);
242 goto drop_pkt;
243 }
244
245 if (STAId == HDD_WLAN_INVALID_STA_ID) {
246 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
247 CDF_TRACE_LEVEL_WARN,
248 "%s: Failed to find right station", __func__);
249 goto drop_pkt;
250 } else if (false == pAdapter->aStaInfo[STAId].isUsed) {
251 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
252 CDF_TRACE_LEVEL_WARN,
253 "%s: STA %d is unregistered", __func__,
254 STAId);
255 goto drop_pkt;
256 }
257
258 if ((ol_txrx_peer_state_conn !=
259 pAdapter->aStaInfo[STAId].tlSTAState)
260 && (ol_txrx_peer_state_auth !=
261 pAdapter->aStaInfo[STAId].tlSTAState)) {
262 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
263 CDF_TRACE_LEVEL_WARN,
264 "%s: Station not connected yet", __func__);
265 goto drop_pkt;
266 } else if (ol_txrx_peer_state_conn ==
267 pAdapter->aStaInfo[STAId].tlSTAState) {
268 if (ntohs(skb->protocol) != HDD_ETHERTYPE_802_1_X) {
269 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
270 CDF_TRACE_LEVEL_WARN,
271 "%s: NON-EAPOL packet in non-Authenticated state",
272 __func__);
273 goto drop_pkt;
274 }
275 }
276 }
277
278 hdd_get_tx_resource(pAdapter, STAId,
279 WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME);
280
281 /* Get TL AC corresponding to Qdisc queue index/AC. */
282 ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping];
283 ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac];
284
285#if defined (IPA_OFFLOAD)
286 if (!(NBUF_OWNER_ID(skb) == IPA_NBUF_OWNER_ID)) {
287#endif
288 /* Check if the buffer has enough header room */
289 skb = skb_unshare(skb, GFP_ATOMIC);
290 if (!skb)
Jeff Johnsonedeff232015-11-11 17:19:42 -0800291 goto drop_pkt_accounting;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800292
293 if (skb_headroom(skb) < dev->hard_header_len) {
294 struct sk_buff *tmp;
295 tmp = skb;
296 skb = skb_realloc_headroom(tmp, dev->hard_header_len);
297 dev_kfree_skb(tmp);
298 if (!skb)
Jeff Johnsonedeff232015-11-11 17:19:42 -0800299 goto drop_pkt_accounting;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800300 }
301#if defined (IPA_OFFLOAD)
302 }
303#endif
304
305 wlan_hdd_log_eapol(skb,
306 WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED);
307
308#ifdef QCA_PKT_PROTO_TRACE
309 if ((hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) ||
310 (hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) {
311 /* Proto Trace enabled */
312 proto_type = cds_pkt_get_proto_type(skb,
313 hddCtxt->config->
314 gEnableDebugLog, 0);
315 if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) {
316 cds_pkt_trace_buf_update("HA:T:EPL");
317 } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) {
318 cds_pkt_trace_buf_update("HA:T:DHC");
319 }
320 }
321#endif /* QCA_PKT_PROTO_TRACE */
322 pAdapter->stats.tx_bytes += skb->len;
323 ++pAdapter->stats.tx_packets;
324
325 /* Zero out skb's context buffer for the driver to use */
326 cdf_mem_set(skb->cb, sizeof(skb->cb), 0);
327 NBUF_SET_PACKET_TRACK(skb, NBUF_TX_PKT_DATA_TRACK);
328 NBUF_UPDATE_TX_PKT_COUNT(skb, NBUF_TX_PKT_HDD);
329
330 cdf_dp_trace_set_track(skb);
331 DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_PTR_RECORD,
332 (uint8_t *)skb->data, sizeof(skb->data)));
333 DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_RECORD,
334 (uint8_t *)skb->data, cdf_nbuf_len(skb)));
335 if (cdf_nbuf_len(skb) > CDF_DP_TRACE_RECORD_SIZE)
336 DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_RECORD,
337 (uint8_t *)&skb->data[CDF_DP_TRACE_RECORD_SIZE],
338 (cdf_nbuf_len(skb)-CDF_DP_TRACE_RECORD_SIZE)));
339
340 if (ol_tx_send_data_frame(STAId, skb,
341 proto_type) != NULL) {
342 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_WARN,
343 "%s: Failed to send packet to txrx for staid:%d",
344 __func__, STAId);
345 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
346 goto drop_pkt;
347 }
348 dev->trans_start = jiffies;
349
350 return NETDEV_TX_OK;
351
352drop_pkt:
353
354 DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_DROP_PACKET_RECORD,
355 (uint8_t *)skb->data, cdf_nbuf_len(skb)));
356 if (cdf_nbuf_len(skb) > CDF_DP_TRACE_RECORD_SIZE)
357 DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_DROP_PACKET_RECORD,
358 (uint8_t *)&skb->data[CDF_DP_TRACE_RECORD_SIZE],
359 (cdf_nbuf_len(skb)-CDF_DP_TRACE_RECORD_SIZE)));
Jeff Johnsonedeff232015-11-11 17:19:42 -0800360 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800361
Jeff Johnsonedeff232015-11-11 17:19:42 -0800362drop_pkt_accounting:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800363 ++pAdapter->stats.tx_dropped;
364 ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800365
366 return NETDEV_TX_OK;
367}
368
369/**
370 * __hdd_softap_tx_timeout() - TX timeout handler
371 * @dev: pointer to network device
372 *
373 * This function is registered as a netdev ndo_tx_timeout method, and
374 * is invoked by the kernel if the driver takes too long to transmit a
375 * frame.
376 *
377 * Return: None
378 */
379static void __hdd_softap_tx_timeout(struct net_device *dev)
380{
381 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
382 hdd_context_t *hdd_ctx;
383
384 DPTRACE(cdf_dp_trace(NULL, CDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT,
385 NULL, 0));
386 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
387 "%s: Transmission timeout occurred", __func__);
388 /* Getting here implies we disabled the TX queues for too
389 * long. Queues are disabled either because of disassociation
390 * or low resource scenarios. In case of disassociation it is
391 * ok to ignore this. But if associated, we have do possible
392 * recovery here
393 */
394 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
395 if (hdd_ctx->isLogpInProgress) {
396 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
397 "%s: LOGP in Progress. Ignore!!!", __func__);
398 return;
399 }
400}
401
402/**
403 * hdd_softap_tx_timeout() - SSR wrapper for __hdd_softap_tx_timeout
404 * @dev: pointer to net_device
405 *
406 * Return: none
407 */
408void hdd_softap_tx_timeout(struct net_device *dev)
409{
410 cds_ssr_protect(__func__);
411 __hdd_softap_tx_timeout(dev);
412 cds_ssr_unprotect(__func__);
413}
414
415/**
416 * @hdd_softap_init_tx_rx() - Initialize Tx/RX module
417 * @pAdapter: pointer to adapter context
418 *
419 * Return: CDF_STATUS_E_FAILURE if any errors encountered,
420 * CDF_STATUS_SUCCESS otherwise
421 */
422CDF_STATUS hdd_softap_init_tx_rx(hdd_adapter_t *pAdapter)
423{
424 CDF_STATUS status = CDF_STATUS_SUCCESS;
425
426 uint8_t STAId = 0;
427
428 cdf_mem_zero(&pAdapter->stats, sizeof(struct net_device_stats));
429
430 spin_lock_init(&pAdapter->staInfo_lock);
431
432 for (STAId = 0; STAId < WLAN_MAX_STA_COUNT; STAId++) {
433 cdf_mem_zero(&pAdapter->aStaInfo[STAId],
434 sizeof(hdd_station_info_t));
435 }
436
437 return status;
438}
439
440/**
441 * @hdd_softap_deinit_tx_rx() - Deinitialize Tx/RX module
442 * @pAdapter: pointer to adapter context
443 *
444 * Return: CDF_STATUS_E_FAILURE if any errors encountered,
445 * CDF_STATUS_SUCCESS otherwise
446 */
447CDF_STATUS hdd_softap_deinit_tx_rx(hdd_adapter_t *pAdapter)
448{
449 CDF_STATUS status = CDF_STATUS_SUCCESS;
450
451 return status;
452}
453
454/**
455 * hdd_softap_init_tx_rx_sta() - Initialize tx/rx for a softap station
456 * @pAdapter: pointer to adapter context
457 * @STAId: Station ID to initialize
458 * @pmacAddrSTA: pointer to the MAC address of the station
459 *
460 * Return: CDF_STATUS_E_FAILURE if any errors encountered,
461 * CDF_STATUS_SUCCESS otherwise
462 */
463CDF_STATUS hdd_softap_init_tx_rx_sta(hdd_adapter_t *pAdapter, uint8_t STAId,
464 struct cdf_mac_addr *pmacAddrSTA)
465{
466 spin_lock_bh(&pAdapter->staInfo_lock);
467 if (pAdapter->aStaInfo[STAId].isUsed) {
468 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
469 "%s: Reinit station %d", __func__, STAId);
470 spin_unlock_bh(&pAdapter->staInfo_lock);
471 return CDF_STATUS_E_FAILURE;
472 }
473
474 cdf_mem_zero(&pAdapter->aStaInfo[STAId], sizeof(hdd_station_info_t));
475
476 pAdapter->aStaInfo[STAId].isUsed = true;
477 pAdapter->aStaInfo[STAId].isDeauthInProgress = false;
478 cdf_copy_macaddr(&pAdapter->aStaInfo[STAId].macAddrSTA, pmacAddrSTA);
479
480 spin_unlock_bh(&pAdapter->staInfo_lock);
481 return CDF_STATUS_SUCCESS;
482}
483
484/**
485 * hdd_softap_deinit_tx_rx_sta() - Deinitialize tx/rx for a softap station
486 * @pAdapter: pointer to adapter context
487 * @STAId: Station ID to deinitialize
488 *
489 * Return: CDF_STATUS_E_FAILURE if any errors encountered,
490 * CDF_STATUS_SUCCESS otherwise
491 */
492CDF_STATUS hdd_softap_deinit_tx_rx_sta(hdd_adapter_t *pAdapter, uint8_t STAId)
493{
494 CDF_STATUS status = CDF_STATUS_SUCCESS;
495 hdd_hostapd_state_t *pHostapdState;
496
497 pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter);
498
499 spin_lock_bh(&pAdapter->staInfo_lock);
500
501 if (false == pAdapter->aStaInfo[STAId].isUsed) {
502 spin_unlock_bh(&pAdapter->staInfo_lock);
503 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
504 "%s: Deinit station not inited %d", __func__, STAId);
505 return CDF_STATUS_E_FAILURE;
506 }
507
508 pAdapter->aStaInfo[STAId].isUsed = false;
509 pAdapter->aStaInfo[STAId].isDeauthInProgress = false;
510
511 spin_unlock_bh(&pAdapter->staInfo_lock);
512 return status;
513}
514
515/**
516 * hdd_softap_rx_packet_cbk() - Receive packet handler
517 * @cds_context: pointer to CDS context
518 * @rxBuf: pointer to rx cdf_nbuf
519 * @staId: Station Id
520 *
521 * Receive callback registered with TL. TL will call this to notify
522 * the HDD when one or more packets were received for a registered
523 * STA.
524 *
525 * Return: CDF_STATUS_E_FAILURE if any errors encountered,
526 * CDF_STATUS_SUCCESS otherwise
527 */
528CDF_STATUS hdd_softap_rx_packet_cbk(void *cds_context,
529 cdf_nbuf_t rxBuf, uint8_t staId)
530{
531 hdd_adapter_t *pAdapter = NULL;
532 int rxstat;
533 unsigned int cpu_index;
534 struct sk_buff *skb = NULL;
535 hdd_context_t *pHddCtx = NULL;
536#ifdef QCA_PKT_PROTO_TRACE
537 uint8_t proto_type;
538#endif /* QCA_PKT_PROTO_TRACE */
539
540 /* Sanity check on inputs */
541 if ((NULL == cds_context) || (NULL == rxBuf)) {
542 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
543 "%s: Null params being passed", __func__);
544 return CDF_STATUS_E_FAILURE;
545 }
546
547 pHddCtx = cds_get_context(CDF_MODULE_ID_HDD);
548 if (NULL == pHddCtx) {
549 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
550 "%s: HDD context is Null", __func__);
551 return CDF_STATUS_E_FAILURE;
552 }
553
554 pAdapter = pHddCtx->sta_to_adapter[staId];
555 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
556 hddLog(LOGE,
557 FL("invalid adapter %p or adapter has invalid magic"),
558 pAdapter);
559 return CDF_STATUS_E_FAILURE;
560 }
561
562 /* walk the chain until all are processed */
563 skb = (struct sk_buff *)rxBuf;
564
565 hdd_softap_dump_sk_buff(skb);
566
567 skb->dev = pAdapter->dev;
568
569 if (skb->dev == NULL) {
570
571 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
572 "%s: ERROR!!Invalid netdevice", __func__);
573 return CDF_STATUS_E_FAILURE;
574 }
575 cpu_index = wlan_hdd_get_cpu();
576 ++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
577 ++pAdapter->stats.rx_packets;
578 pAdapter->stats.rx_bytes += skb->len;
579
580 wlan_hdd_log_eapol(skb, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED);
581
582#ifdef QCA_PKT_PROTO_TRACE
583 if ((pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) ||
584 (pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) {
585 proto_type = cds_pkt_get_proto_type(skb,
586 pHddCtx->config->
587 gEnableDebugLog, 0);
588 if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) {
589 cds_pkt_trace_buf_update("HA:R:EPL");
590 } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) {
591 cds_pkt_trace_buf_update("HA:R:DHC");
592 }
593 }
594#endif /* QCA_PKT_PROTO_TRACE */
595
596 skb->protocol = eth_type_trans(skb, skb->dev);
597#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
598 cdf_wake_lock_timeout_acquire(&pHddCtx->rx_wake_lock,
599 HDD_WAKE_LOCK_DURATION,
600 WIFI_POWER_EVENT_WAKELOCK_HOLD_RX);
601#endif
602
603 /* Remove SKB from internal tracking table before submitting
604 * it to stack
605 */
606 cdf_net_buf_debug_release_skb(rxBuf);
607
608 if (hdd_napi_enabled(HDD_NAPI_ANY))
609 rxstat = netif_receive_skb(skb);
610 else
611 rxstat = netif_rx_ni(skb);
612 if (NET_RX_SUCCESS == rxstat) {
613 ++pAdapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
614 } else {
615 ++pAdapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
616 }
617
618 pAdapter->dev->last_rx = jiffies;
619
620 return CDF_STATUS_SUCCESS;
621}
622
623/**
624 * hdd_softap_deregister_sta(hdd_adapter_t *pAdapter, uint8_t staId)
625 * @pAdapter: pointer to adapter context
626 * @staId: Station ID to deregister
627 *
628 * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
629 */
630CDF_STATUS hdd_softap_deregister_sta(hdd_adapter_t *pAdapter, uint8_t staId)
631{
632 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
633 hdd_context_t *pHddCtx;
634
635 if (NULL == pAdapter) {
636 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
637 "%s: pAdapter is NULL", __func__);
638 return CDF_STATUS_E_INVAL;
639 }
640
641 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) {
642 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
643 "%s: Invalid pAdapter magic", __func__);
644 return CDF_STATUS_E_INVAL;
645 }
646
647 pHddCtx = (hdd_context_t *) (pAdapter->pHddCtx);
648 /* Clear station in TL and then update HDD data
649 * structures. This helps to block RX frames from other
650 * station to this station.
651 */
652 cdf_status = ol_txrx_clear_peer(staId);
653 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
654 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
655 "ol_txrx_clear_peer() failed to for staID %d. "
656 "Status= %d [0x%08X]", staId, cdf_status, cdf_status);
657 }
658
659 if (pAdapter->aStaInfo[staId].isUsed) {
660 spin_lock_bh(&pAdapter->staInfo_lock);
661 cdf_mem_zero(&pAdapter->aStaInfo[staId],
662 sizeof(hdd_station_info_t));
663 spin_unlock_bh(&pAdapter->staInfo_lock);
664 }
665 pHddCtx->sta_to_adapter[staId] = NULL;
666
667 return cdf_status;
668}
669
670/**
671 * hdd_softap_register_sta() - Register a SoftAP STA
672 * @pAdapter: pointer to adapter context
673 * @fAuthRequired: is additional authentication required?
674 * @fPrivacyBit: should 802.11 privacy bit be set?
675 * @staId: station ID assigned to this station
676 * @ucastSig: unicast security signature
677 * @bcastSig: broadcast security signature
678 * @pPeerMacAddress: station MAC address
679 * @fWmmEnabled: is WMM enabled for this STA?
680 *
681 * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
682 */
683CDF_STATUS hdd_softap_register_sta(hdd_adapter_t *pAdapter,
684 bool fAuthRequired,
685 bool fPrivacyBit,
686 uint8_t staId,
687 uint8_t ucastSig,
688 uint8_t bcastSig,
689 struct cdf_mac_addr *pPeerMacAddress,
690 bool fWmmEnabled)
691{
692 CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE;
693 struct ol_txrx_desc_type staDesc = { 0 };
694 hdd_context_t *pHddCtx = pAdapter->pHddCtx;
695
696 /*
697 * Clean up old entry if it is not cleaned up properly
698 */
699 if (pAdapter->aStaInfo[staId].isUsed) {
700 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
701 "clean up old entry for STA %d", staId);
702 hdd_softap_deregister_sta(pAdapter, staId);
703 }
704 /* Get the Station ID from the one saved during the assocation. */
705
706 staDesc.sta_id = staId;
707
708 /*Save the pAdapter Pointer for this staId */
709 pHddCtx->sta_to_adapter[staId] = pAdapter;
710
711 cdf_status =
712 hdd_softap_init_tx_rx_sta(pAdapter, staId,
713 pPeerMacAddress);
714
715 staDesc.is_qos_enabled = fWmmEnabled;
716 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
717 "HDD SOFTAP register TL QoS_enabled=%d",
718 staDesc.is_qos_enabled);
719
720
721 cdf_status =
722 ol_txrx_register_peer(hdd_softap_rx_packet_cbk,
723 &staDesc);
724 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
725 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
726 "SOFTAP ol_txrx_register_peer() failed to register. Status= %d [0x%08X]",
727 cdf_status, cdf_status);
728 return cdf_status;
729 }
730
731 /* if ( WPA ), tell TL to go to 'connected' and after keys come to the
732 * driver then go to 'authenticated'. For all other authentication
733 * types (those that do not require upper layer authentication) we can
734 * put TL directly into 'authenticated' state
735 */
736
737 pAdapter->aStaInfo[staId].ucSTAId = staId;
738 pAdapter->aStaInfo[staId].isQosEnabled = fWmmEnabled;
739
740 if (!fAuthRequired) {
741 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
742 "open/shared auth StaId= %d. Changing TL state to AUTHENTICATED at Join time",
743 pAdapter->aStaInfo[staId].ucSTAId);
744
745 /* Connections that do not need Upper layer auth,
746 * transition TL directly to 'Authenticated' state.
747 */
748 cdf_status = hdd_change_peer_state(pAdapter, staDesc.sta_id,
749 ol_txrx_peer_state_auth, false);
750
751 pAdapter->aStaInfo[staId].tlSTAState = ol_txrx_peer_state_auth;
752 pAdapter->sessionCtx.ap.uIsAuthenticated = true;
753 } else {
754
755 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
756 "ULA auth StaId= %d. Changing TL state to CONNECTED at Join time",
757 pAdapter->aStaInfo[staId].ucSTAId);
758
759 cdf_status = hdd_change_peer_state(pAdapter, staDesc.sta_id,
760 ol_txrx_peer_state_conn, false);
761 pAdapter->aStaInfo[staId].tlSTAState = ol_txrx_peer_state_conn;
762
763 pAdapter->sessionCtx.ap.uIsAuthenticated = false;
764
765 }
766
767 /* Enable Tx queue */
768 hddLog(LOG1, FL("Enabling queues"));
769 wlan_hdd_netif_queue_control(pAdapter,
770 WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
771 WLAN_CONTROL_PATH);
772
773 return cdf_status;
774}
775
776/**
777 * hdd_softap_register_bc_sta() - Register the SoftAP broadcast STA
778 * @pAdapter: pointer to adapter context
779 * @fPrivacyBit: should 802.11 privacy bit be set?
780 *
781 * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
782 */
783CDF_STATUS hdd_softap_register_bc_sta(hdd_adapter_t *pAdapter,
784 bool fPrivacyBit)
785{
786 CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE;
787 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
788 struct cdf_mac_addr broadcastMacAddr =
789 CDF_MAC_ADDR_BROADCAST_INITIALIZER;
790 hdd_ap_ctx_t *pHddApCtx;
791
792 pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pAdapter);
793
794 pHddCtx->sta_to_adapter[WLAN_RX_BCMC_STA_ID] = pAdapter;
795#ifdef WLAN_FEATURE_MBSSID
796 pHddCtx->sta_to_adapter[pHddApCtx->uBCStaId] = pAdapter;
797#else
798 pHddCtx->sta_to_adapter[WLAN_RX_SAP_SELF_STA_ID] = pAdapter;
799#endif
800 cdf_status =
801 hdd_softap_register_sta(pAdapter, false, fPrivacyBit,
802 (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->
803 uBCStaId, 0, 1, &broadcastMacAddr, 0);
804
805 return cdf_status;
806}
807
808/**
809 * hdd_softap_deregister_bc_sta() - Deregister the SoftAP broadcast STA
810 * @pAdapter: pointer to adapter context
811 *
812 * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
813 */
814CDF_STATUS hdd_softap_deregister_bc_sta(hdd_adapter_t *pAdapter)
815{
816 return hdd_softap_deregister_sta(pAdapter,
817 (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->
818 uBCStaId);
819}
820
821/**
822 * hdd_softap_stop_bss() - Stop the BSS
823 * @pAdapter: pointer to adapter context
824 *
825 * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
826 */
827CDF_STATUS hdd_softap_stop_bss(hdd_adapter_t *pAdapter)
828{
829 CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE;
830 uint8_t staId = 0;
831 hdd_context_t *pHddCtx;
832 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
833
834 /* bss deregister is not allowed during wlan driver loading or
835 * unloading
836 */
837 if ((pHddCtx->isLoadInProgress) || (pHddCtx->isUnloadInProgress)) {
838 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
839 "%s:Loading_unloading in Progress. Ignore!!!",
840 __func__);
841 return CDF_STATUS_E_PERM;
842 }
843
844 cdf_status = hdd_softap_deregister_bc_sta(pAdapter);
845
846 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
847 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
848 "%s: Failed to deregister BC sta Id %d", __func__,
849 (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->uBCStaId);
850 }
851
852 for (staId = 0; staId < WLAN_MAX_STA_COUNT; staId++) {
853 /* This excludes BC sta as it is already deregistered */
854 if (pAdapter->aStaInfo[staId].isUsed) {
855 cdf_status = hdd_softap_deregister_sta(pAdapter, staId);
856 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
857 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA,
858 CDF_TRACE_LEVEL_ERROR,
859 "%s: Failed to deregister sta Id %d",
860 __func__, staId);
861 }
862 }
863 }
864 return cdf_status;
865}
866
867/**
868 * hdd_softap_change_sta_state() - Change the state of a SoftAP station
869 * @pAdapter: pointer to adapter context
870 * @pDestMacAddress: MAC address of the station
871 * @state: new state of the station
872 *
873 * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
874 */
875CDF_STATUS hdd_softap_change_sta_state(hdd_adapter_t *pAdapter,
876 struct cdf_mac_addr *pDestMacAddress,
877 enum ol_txrx_peer_state state)
878{
879 uint8_t ucSTAId = WLAN_MAX_STA_COUNT;
880 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
881
882 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
883 "%s: enter", __func__);
884
885 if (CDF_STATUS_SUCCESS !=
886 hdd_softap_get_sta_id(pAdapter,
887 pDestMacAddress, &ucSTAId)) {
888 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
889 "%s: Failed to find right station", __func__);
890 return CDF_STATUS_E_FAILURE;
891 }
892
893 if (false ==
894 cdf_is_macaddr_equal(&pAdapter->aStaInfo[ucSTAId].macAddrSTA,
895 pDestMacAddress)) {
896 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,
897 "%s: Station MAC address does not matching",
898 __func__);
899 return CDF_STATUS_E_FAILURE;
900 }
901
902 cdf_status =
903 hdd_change_peer_state(pAdapter, ucSTAId, state, false);
904 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
905 "%s: change station to state %d succeed", __func__, state);
906
907 if (CDF_STATUS_SUCCESS == cdf_status) {
908 pAdapter->aStaInfo[ucSTAId].tlSTAState =
909 ol_txrx_peer_state_auth;
910 }
911
912 CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO,
913 "%s exit", __func__);
914
915 return cdf_status;
916}
917
918/*
919 * hdd_softap_get_sta_id() - Find station ID from MAC address
920 * @pAdapter: pointer to adapter context
921 * @pDestMacAddress: MAC address of the destination
922 * @staId: Station ID associated with the MAC address
923 *
924 * Return: CDF_STATUS_SUCCESS if a match was found, in which case
925 * staId is populated, CDF_STATUS_E_FAILURE if a match is
926 * not found
927 */
928CDF_STATUS hdd_softap_get_sta_id(hdd_adapter_t *pAdapter,
929 struct cdf_mac_addr *pMacAddress,
930 uint8_t *staId)
931{
932 uint8_t i;
933
934 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
935 if (cdf_mem_compare
936 (&pAdapter->aStaInfo[i].macAddrSTA, pMacAddress,
937 CDF_MAC_ADDR_SIZE) && pAdapter->aStaInfo[i].isUsed) {
938 *staId = i;
939 return CDF_STATUS_SUCCESS;
940 }
941 }
942
943 return CDF_STATUS_E_FAILURE;
944}