1 /*
2 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18 /**
19 * DOC: wlan_dp_softap_txrx.c
20 * DP Soft AP TX/RX path implementation
21 *
22 *
23 */
24
25 #include <wlan_dp_priv.h>
26 #include <wlan_dp_main.h>
27 #include <wlan_dp_txrx.h>
28 #include "wlan_dp_public_struct.h"
29 #include <qdf_types.h>
30 #include <cdp_txrx_cmn.h>
31 #include <cdp_txrx_peer_ops.h>
32 #include <cdp_txrx_misc.h>
33 #include <cdp_txrx_flow_ctrl_v2.h>
34 #include "wlan_dp_rx_thread.h"
35 #include "nan_public_structs.h"
36 #include "nan_ucfg_api.h"
37 #include <wlan_cm_ucfg_api.h>
38 #include <enet.h>
39 #include <cds_utils.h>
40 #include <wlan_dp_bus_bandwidth.h>
41 #include <wlan_tdls_ucfg_api.h>
42 #include <qdf_trace.h>
43 #include <qdf_nbuf.h>
44 #include <qdf_net_stats.h>
45
46 /* Preprocessor definitions and constants */
47 #undef QCA_DP_SAP_DUMP_SK_BUFF
48
49 /* Type declarations */
50
51 /* Function definitions and documentation */
52 #ifdef QCA_DP_SAP_DUMP_SK_BUFF
53 /**
54 * dp_softap_dump_nbuf() - Dump an nbuf
55 * @nbuf: nbuf to dump
56 *
57 * Return: None
58 */
dp_softap_dump_nbuf(qdf_nbuf_t nbuf)59 static void dp_softap_dump_nbuf(qdf_nbuf_t nbuf)
60 {
61 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
62 "%s: head = %pK ", __func__, nbuf->head);
63 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
64 "%s: tail = %pK ", __func__, nbuf->tail);
65 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
66 "%s: end = %pK ", __func__, nbuf->end);
67 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
68 "%s: len = %d ", __func__, nbuf->len);
69 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
70 "%s: data_len = %d ", __func__, nbuf->data_len);
71 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
72 "%s: mac_len = %d", __func__, nbuf->mac_len);
73
74 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
75 "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ", nbuf->data[0],
76 nbuf->data[1], nbuf->data[2], nbuf->data[3], nbuf->data[4],
77 nbuf->data[5], nbuf->data[6], nbuf->data[7]);
78 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
79 "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", nbuf->data[8],
80 nbuf->data[9], nbuf->data[10], nbuf->data[11], nbuf->data[12],
81 nbuf->data[13], nbuf->data[14], nbuf->data[15]);
82 }
83 #else
dp_softap_dump_nbuf(qdf_nbuf_t nbuf)84 static inline void dp_softap_dump_nbuf(qdf_nbuf_t nbuf)
85 {
86 }
87 #endif
88
89 #define IEEE8021X_AUTH_TYPE_EAP 0
90 #define EAP_CODE_OFFSET 18
91 #define EAP_CODE_FAILURE 4
92
93 /* Wait EAP Failure frame timeout in (MS) */
94 #define EAP_FRM_TIME_OUT 80
95
96 /**
97 * dp_softap_inspect_tx_eap_pkt() - Inspect eap pkt tx/tx-completion
98 * @dp_intf: pointer to DP interface
99 * @nbuf: pointer to n/w buffer
100 * @tx_comp: tx sending or tx completion
101 *
102 * Inspect the EAP-Failure pkt tx sending and tx completion.
103 *
104 * Return: void
105 */
dp_softap_inspect_tx_eap_pkt(struct wlan_dp_intf * dp_intf,qdf_nbuf_t nbuf,bool tx_comp)106 static void dp_softap_inspect_tx_eap_pkt(struct wlan_dp_intf *dp_intf,
107 qdf_nbuf_t nbuf,
108 bool tx_comp)
109 {
110 struct qdf_mac_addr *mac_addr;
111 uint8_t *data;
112 uint8_t auth_type, eap_code;
113 struct wlan_objmgr_peer *peer;
114 struct wlan_dp_sta_info *sta_info;
115
116 if (qdf_likely(QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) !=
117 QDF_NBUF_CB_PACKET_TYPE_EAPOL) ||
118 qdf_nbuf_len(nbuf) < (EAP_CODE_OFFSET + 1))
119 return;
120
121 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state() ||
122 cds_is_load_or_unload_in_progress()) {
123 dp_debug("Recovery/(Un)load in Progress. Ignore!!!");
124 return;
125 }
126
127 if (dp_intf->device_mode != QDF_P2P_GO_MODE)
128 return;
129
130 if (dp_intf->bss_state != BSS_INTF_START) {
131 dp_debug("BSS intf state is not START");
132 return;
133 }
134 data = qdf_nbuf_data(nbuf);
135 auth_type = *(uint8_t *)(data + EAPOL_PACKET_TYPE_OFFSET);
136 if (auth_type != IEEE8021X_AUTH_TYPE_EAP)
137 return;
138 eap_code = *(uint8_t *)(data + EAP_CODE_OFFSET);
139 if (eap_code != EAP_CODE_FAILURE)
140 return;
141 mac_addr = (struct qdf_mac_addr *)qdf_nbuf_data(nbuf) +
142 QDF_NBUF_DEST_MAC_OFFSET;
143
144 peer = wlan_objmgr_get_peer_by_mac(dp_intf->dp_ctx->psoc,
145 mac_addr->bytes,
146 WLAN_DP_ID);
147 if (!peer) {
148 dp_err("Peer object not found");
149 return;
150 }
151 sta_info = dp_get_peer_priv_obj(peer);
152 if (!sta_info) {
153 wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID);
154 return;
155 }
156
157 if (tx_comp) {
158 dp_info("eap_failure frm tx done" QDF_MAC_ADDR_FMT,
159 QDF_MAC_ADDR_REF(mac_addr->bytes));
160 qdf_atomic_clear_bit(DP_PENDING_TYPE_EAP_FAILURE,
161 &sta_info->pending_eap_frm_type);
162 qdf_event_set(&dp_intf->qdf_sta_eap_frm_done_event);
163 } else {
164 dp_info("eap_failure frm tx pending" QDF_MAC_ADDR_FMT,
165 QDF_MAC_ADDR_REF(mac_addr->bytes));
166 qdf_event_reset(&dp_intf->qdf_sta_eap_frm_done_event);
167 qdf_atomic_set_bit(DP_PENDING_TYPE_EAP_FAILURE,
168 &sta_info->pending_eap_frm_type);
169 QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(nbuf) = 1;
170 }
171 wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID);
172 }
173
dp_softap_check_wait_for_tx_eap_pkt(struct wlan_dp_intf * dp_intf,struct qdf_mac_addr * mac_addr)174 void dp_softap_check_wait_for_tx_eap_pkt(struct wlan_dp_intf *dp_intf,
175 struct qdf_mac_addr *mac_addr)
176 {
177 struct wlan_objmgr_peer *peer;
178 struct wlan_dp_sta_info *sta_info;
179 QDF_STATUS qdf_status;
180
181 if (dp_intf->device_mode != QDF_P2P_GO_MODE)
182 return;
183
184 peer = wlan_objmgr_get_peer_by_mac(dp_intf->dp_ctx->psoc,
185 mac_addr->bytes,
186 WLAN_DP_ID);
187 if (!peer) {
188 dp_err("Peer object not found");
189 return;
190 }
191
192 sta_info = dp_get_peer_priv_obj(peer);
193 if (qdf_atomic_test_bit(DP_PENDING_TYPE_EAP_FAILURE,
194 &sta_info->pending_eap_frm_type)) {
195 dp_info("eap_failure frm pending" QDF_MAC_ADDR_FMT,
196 QDF_MAC_ADDR_REF(mac_addr->bytes));
197 qdf_status = qdf_wait_for_event_completion(
198 &dp_intf->qdf_sta_eap_frm_done_event,
199 EAP_FRM_TIME_OUT);
200 if (!QDF_IS_STATUS_SUCCESS(qdf_status))
201 dp_debug("eap_failure tx timeout");
202 }
203 wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID);
204 }
205
206 #ifdef SAP_DHCP_FW_IND
207 /**
208 * dp_post_dhcp_ind() - Send DHCP START/STOP indication to FW
209 * @dp_link: DP link handle
210 * @mac_addr: mac address
211 * @dhcp_start: dhcp start
212 *
213 * Return: error number
214 */
dp_post_dhcp_ind(struct wlan_dp_link * dp_link,uint8_t * mac_addr,bool dhcp_start)215 int dp_post_dhcp_ind(struct wlan_dp_link *dp_link, uint8_t *mac_addr,
216 bool dhcp_start)
217 {
218 struct wlan_dp_intf *dp_intf;
219 struct dp_dhcp_ind msg;
220 struct wlan_dp_psoc_sb_ops *sb_ops;
221 QDF_STATUS status = QDF_STATUS_SUCCESS;
222
223 dp_info("Post DHCP indication,sta_mac=" QDF_MAC_ADDR_FMT
224 " , start=%u", QDF_MAC_ADDR_REF(mac_addr), dhcp_start);
225
226 if (!is_dp_link_valid(dp_link)) {
227 dp_err("NULL DP link");
228 return QDF_STATUS_E_INVAL;
229 }
230
231 dp_intf = dp_link->dp_intf;
232 /*
233 * If DP RX thread is enabled, RX DHCP packets are enqueue into
234 * DP RX thread queue, defer DHCP inspection until host has
235 * resumed entirely, no issue to send DHCP indication MSG.
236 * If DP RX thread is disabled, DHCP inspection happens earlier,
237 * skip sending DHCP indication MSG if host has not resumed.
238 */
239 if (qdf_unlikely(!dp_intf->dp_ctx->enable_dp_rx_threads &&
240 dp_intf->dp_ctx->is_suspend)) {
241 dp_err_rl("Device is system suspended, skip DHCP Ind");
242 return QDF_STATUS_E_INVAL;
243 }
244
245 sb_ops = &dp_intf->dp_ctx->sb_ops;
246 msg.dhcp_start = dhcp_start;
247 msg.device_mode = dp_intf->device_mode;
248 qdf_mem_copy(msg.intf_mac_addr.bytes,
249 dp_intf->mac_addr.bytes,
250 QDF_MAC_ADDR_SIZE);
251 qdf_mem_copy(msg.peer_mac_addr.bytes,
252 mac_addr,
253 QDF_MAC_ADDR_SIZE);
254
255 status = sb_ops->dp_send_dhcp_ind(dp_link->link_id, &msg);
256 if (!QDF_IS_STATUS_SUCCESS(status)) {
257 dp_err("Post DHCP Ind MSG fail");
258 return QDF_STATUS_E_FAULT;
259 }
260
261 return 0;
262 }
263
264 #define DHCP_CLIENT_MAC_ADDR_OFFSET 0x46
265
266 /**
267 * dp_softap_notify_dhcp_ind() - Notify SAP for DHCP indication for tx desc
268 * @link_context: DP link context
269 * @nbuf: pointer to OS packet (sk_buff)
270 *
271 * Return: None
272 */
dp_softap_notify_dhcp_ind(void * link_context,qdf_nbuf_t nbuf)273 static void dp_softap_notify_dhcp_ind(void *link_context, qdf_nbuf_t nbuf)
274 {
275 uint8_t *dest_mac_addr;
276 struct wlan_dp_link *dp_link = link_context;
277
278 if (!is_dp_link_valid(dp_link))
279 return;
280
281 dest_mac_addr = qdf_nbuf_data(nbuf) + DHCP_CLIENT_MAC_ADDR_OFFSET;
282
283 /*stop dhcp indication*/
284 dp_post_dhcp_ind(dp_link, dest_mac_addr, false);
285 }
286
dp_softap_inspect_dhcp_packet(struct wlan_dp_link * dp_link,qdf_nbuf_t nbuf,enum qdf_proto_dir dir)287 int dp_softap_inspect_dhcp_packet(struct wlan_dp_link *dp_link,
288 qdf_nbuf_t nbuf,
289 enum qdf_proto_dir dir)
290 {
291 struct wlan_dp_intf *dp_intf = dp_link->dp_intf;
292 enum qdf_proto_subtype subtype = QDF_PROTO_INVALID;
293 struct wlan_objmgr_peer *peer;
294 struct wlan_dp_sta_info *sta_info;
295 int errno = 0;
296 struct qdf_mac_addr *src_mac;
297
298 if (((dp_intf->device_mode == QDF_SAP_MODE) ||
299 (dp_intf->device_mode == QDF_P2P_GO_MODE)) &&
300 ((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_DHCP ==
301 QDF_NBUF_CB_GET_PACKET_TYPE(nbuf)) ||
302 (dir == QDF_RX && qdf_nbuf_is_ipv4_dhcp_pkt(nbuf) == true))) {
303 src_mac = (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) +
304 DHCP_CLIENT_MAC_ADDR_OFFSET);
305
306 subtype = qdf_nbuf_get_dhcp_subtype(nbuf);
307
308 peer = wlan_objmgr_get_peer_by_mac(dp_intf->dp_ctx->psoc,
309 src_mac->bytes,
310 WLAN_DP_ID);
311 if (!peer) {
312 dp_err("Peer object not found");
313 return QDF_STATUS_E_INVAL;
314 }
315
316 sta_info = dp_get_peer_priv_obj(peer);
317 if (!sta_info) {
318 dp_err("Station not found");
319 wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID);
320 return QDF_STATUS_E_INVAL;
321 }
322
323 dp_info("ENTER: type=%d, phase=%d, nego_status=%d",
324 subtype,
325 sta_info->dhcp_phase,
326 sta_info->dhcp_nego_status);
327
328 switch (subtype) {
329 case QDF_PROTO_DHCP_DISCOVER:
330 if (dir != QDF_RX)
331 break;
332 if (sta_info->dhcp_nego_status == DHCP_NEGO_STOP)
333 errno = dp_post_dhcp_ind(
334 dp_link,
335 sta_info->sta_mac.bytes,
336 true);
337 sta_info->dhcp_phase = DHCP_PHASE_DISCOVER;
338 if (QDF_IS_STATUS_SUCCESS(errno))
339 sta_info->dhcp_nego_status =
340 DHCP_NEGO_IN_PROGRESS;
341 break;
342 case QDF_PROTO_DHCP_OFFER:
343 sta_info->dhcp_phase = DHCP_PHASE_OFFER;
344 break;
345 case QDF_PROTO_DHCP_REQUEST:
346 if (dir != QDF_RX)
347 break;
348 if (sta_info->dhcp_nego_status == DHCP_NEGO_STOP)
349 errno = dp_post_dhcp_ind(
350 dp_link,
351 sta_info->sta_mac.bytes,
352 true);
353 if (QDF_IS_STATUS_SUCCESS(errno))
354 sta_info->dhcp_nego_status =
355 DHCP_NEGO_IN_PROGRESS;
356 fallthrough;
357 case QDF_PROTO_DHCP_DECLINE:
358 if (dir == QDF_RX)
359 sta_info->dhcp_phase = DHCP_PHASE_REQUEST;
360 break;
361 case QDF_PROTO_DHCP_ACK:
362 case QDF_PROTO_DHCP_NACK:
363 sta_info->dhcp_phase = DHCP_PHASE_ACK;
364 if (sta_info->dhcp_nego_status ==
365 DHCP_NEGO_IN_PROGRESS) {
366 dp_debug("Setting NOTIFY_COMP Flag");
367 QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(nbuf) = 1;
368 }
369 sta_info->dhcp_nego_status = DHCP_NEGO_STOP;
370 break;
371 default:
372 break;
373 }
374
375 wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID);
376 dp_info("EXIT: phase=%d, nego_status=%d",
377 sta_info->dhcp_phase,
378 sta_info->dhcp_nego_status);
379 }
380
381 return errno;
382 }
383 #else
dp_softap_notify_dhcp_ind(void * context,qdf_nbuf_t nbuf)384 static void dp_softap_notify_dhcp_ind(void *context, qdf_nbuf_t nbuf)
385 {
386 }
387 #endif /* SAP_DHCP_FW_IND */
388
389 #if defined(IPA_OFFLOAD)
390 static
dp_sap_nbuf_orphan(struct wlan_dp_intf * dp_intf,qdf_nbuf_t nbuf)391 qdf_nbuf_t dp_sap_nbuf_orphan(struct wlan_dp_intf *dp_intf,
392 qdf_nbuf_t nbuf)
393 {
394 if (!qdf_nbuf_ipa_owned_get(nbuf)) {
395 nbuf = dp_nbuf_orphan(dp_intf, nbuf);
396 } else {
397 /*
398 * Clear the IPA ownership after check it to avoid ipa_free_skb
399 * is called when Tx completed for intra-BSS Tx packets
400 */
401 qdf_nbuf_ipa_owned_clear(nbuf);
402 }
403 return nbuf;
404 }
405 #else
406 static inline
dp_sap_nbuf_orphan(struct wlan_dp_intf * dp_intf,qdf_nbuf_t nbuf)407 qdf_nbuf_t dp_sap_nbuf_orphan(struct wlan_dp_intf *dp_intf,
408 qdf_nbuf_t nbuf)
409 {
410 return dp_nbuf_orphan(dp_intf, nbuf);
411 }
412 #endif /* IPA_OFFLOAD */
413
414 #ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
415 static
dp_softap_get_tx_resource(struct wlan_dp_link * dp_link,qdf_nbuf_t nbuf)416 void dp_softap_get_tx_resource(struct wlan_dp_link *dp_link,
417 qdf_nbuf_t nbuf)
418 {
419 struct wlan_dp_intf *dp_intf = dp_link->dp_intf;
420
421 if (QDF_NBUF_CB_GET_IS_BCAST(nbuf) || QDF_NBUF_CB_GET_IS_MCAST(nbuf))
422 dp_get_tx_resource(dp_link, &dp_intf->mac_addr);
423 else
424 dp_get_tx_resource(dp_link,
425 (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) +
426 QDF_NBUF_DEST_MAC_OFFSET));
427 }
428 #else
429 #define dp_softap_get_tx_resource(dp_intf, nbuf)
430 #endif
431
432 #ifdef FEATURE_WDS
433 static void
dp_wds_replace_peer_mac(void * soc,struct wlan_dp_link * dp_link,uint8_t * mac_addr)434 dp_wds_replace_peer_mac(void *soc, struct wlan_dp_link *dp_link,
435 uint8_t *mac_addr)
436 {
437 struct cdp_ast_entry_info ast_entry_info = {0};
438 cdp_config_param_type val;
439 QDF_STATUS status;
440
441 if (!cdp_find_peer_exist(soc, OL_TXRX_PDEV_ID, mac_addr)) {
442 status = cdp_txrx_get_vdev_param(soc, dp_link->link_id,
443 CDP_ENABLE_WDS, &val);
444 if (!QDF_IS_STATUS_SUCCESS(status))
445 return;
446
447 if (!val.cdp_vdev_param_wds)
448 return;
449
450 if (!cdp_peer_get_ast_info_by_soc(soc, mac_addr,
451 &ast_entry_info))
452 return;
453
454 qdf_mem_copy(mac_addr, ast_entry_info.peer_mac_addr,
455 QDF_MAC_ADDR_SIZE);
456 }
457 }
458 #else
459 static inline
dp_wds_replace_peer_mac(void * soc,struct wlan_dp_link * dp_link,uint8_t * mac_addr)460 void dp_wds_replace_peer_mac(void *soc, struct wlan_dp_link *dp_link,
461 uint8_t *mac_addr)
462 {
463 }
464 #endif /* FEATURE_WDS*/
465
dp_softap_validate_peer_state(struct wlan_dp_link * dp_link,qdf_nbuf_t nbuf)466 static QDF_STATUS dp_softap_validate_peer_state(struct wlan_dp_link *dp_link,
467 qdf_nbuf_t nbuf)
468 {
469 struct qdf_mac_addr *dest_mac_addr;
470 struct qdf_mac_addr mac_addr;
471 enum ol_txrx_peer_state peer_state;
472 void *soc;
473
474 dest_mac_addr = (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) +
475 QDF_NBUF_DEST_MAC_OFFSET);
476
477 if (QDF_NBUF_CB_GET_IS_BCAST(nbuf) || QDF_NBUF_CB_GET_IS_MCAST(nbuf))
478 return QDF_STATUS_SUCCESS;
479
480 /* for a unicast frame */
481 qdf_copy_macaddr(&mac_addr, dest_mac_addr);
482 soc = cds_get_context(QDF_MODULE_ID_SOC);
483 QDF_BUG(soc);
484 dp_wds_replace_peer_mac(soc, dp_link, mac_addr.bytes);
485 peer_state = cdp_peer_state_get(soc, dp_link->link_id,
486 mac_addr.bytes, false);
487
488 if (peer_state == OL_TXRX_PEER_STATE_INVALID) {
489 dp_debug_rl("Failed to find right station");
490 return QDF_STATUS_E_FAILURE;
491 }
492
493 if (peer_state != OL_TXRX_PEER_STATE_CONN &&
494 peer_state != OL_TXRX_PEER_STATE_AUTH) {
495 dp_debug_rl("Station not connected yet");
496 return QDF_STATUS_E_FAILURE;
497 }
498
499 if (peer_state == OL_TXRX_PEER_STATE_CONN) {
500 if (qdf_ntohs(qdf_nbuf_get_protocol(nbuf)) != ETHERTYPE_PAE &&
501 qdf_ntohs(qdf_nbuf_get_protocol(nbuf)) != ETHERTYPE_WAI) {
502 dp_debug_rl("NON-EAPOL/WAPI pkt in non-Auth state");
503 return QDF_STATUS_E_FAILURE;
504 }
505 }
506 return QDF_STATUS_SUCCESS;
507 }
508
509 static
dp_softap_validate_driver_state(struct wlan_dp_intf * dp_intf)510 QDF_STATUS dp_softap_validate_driver_state(struct wlan_dp_intf *dp_intf)
511 {
512 if (qdf_unlikely(cds_is_driver_transitioning())) {
513 dp_err_rl("driver is transitioning, drop pkt");
514 return QDF_STATUS_E_ABORTED;
515 }
516
517 /*
518 * below unified mask will take care of SAP TX block
519 * WLAN suspend state check
520 * BSS start check and
521 * DP TX function register check
522 */
523 if (qdf_unlikely(dp_intf->sap_tx_block_mask)) {
524 dp_err_rl("Softap TX blocked mask: %u",
525 dp_intf->sap_tx_block_mask);
526 return QDF_STATUS_E_ABORTED;
527 }
528
529 return QDF_STATUS_SUCCESS;
530 }
531
dp_softap_config_tx_pkt_tracing(struct wlan_dp_intf * dp_intf,qdf_nbuf_t nbuf)532 static void dp_softap_config_tx_pkt_tracing(struct wlan_dp_intf *dp_intf,
533 qdf_nbuf_t nbuf)
534 {
535 if (dp_is_current_high_throughput(dp_intf->dp_ctx))
536 return;
537
538 QDF_NBUF_CB_TX_PACKET_TRACK(nbuf) = QDF_NBUF_TX_PKT_DATA_TRACK;
539 QDF_NBUF_UPDATE_TX_PKT_COUNT(nbuf, QDF_NBUF_TX_PKT_DP);
540 qdf_dp_trace_set_track(nbuf, QDF_TX);
541 DPTRACE(qdf_dp_trace(nbuf, QDF_DP_TRACE_TX_PACKET_PTR_RECORD,
542 QDF_TRACE_DEFAULT_PDEV_ID,
543 qdf_nbuf_data_addr(nbuf),
544 sizeof(qdf_nbuf_data(nbuf)),
545 QDF_TX));
546 }
547
548 #ifdef DP_TRAFFIC_END_INDICATION
549 /**
550 * wlan_dp_traffic_end_indication_update_dscp() - Compare dscp derived from
551 * provided tos value with
552 * stored value and update if
553 * it's equal to special dscp
554 * @dp_intf: pointer to DP interface
555 * @tos: pointer to tos
556 *
557 * Return: True if tos is updated else False
558 */
559 static inline bool
wlan_dp_traffic_end_indication_update_dscp(struct wlan_dp_intf * dp_intf,uint8_t * tos)560 wlan_dp_traffic_end_indication_update_dscp(struct wlan_dp_intf *dp_intf,
561 uint8_t *tos)
562 {
563 bool update;
564 uint8_t dscp, ecn;
565
566 ecn = (*tos & ~QDF_NBUF_PKT_IPV4_DSCP_MASK);
567 dscp = (*tos & QDF_NBUF_PKT_IPV4_DSCP_MASK) >>
568 QDF_NBUF_PKT_IPV4_DSCP_SHIFT;
569 update = (dp_intf->traffic_end_ind.spl_dscp == dscp);
570 if (update)
571 *tos = ((dp_intf->traffic_end_ind.def_dscp <<
572 QDF_NBUF_PKT_IPV4_DSCP_SHIFT) | ecn);
573 return update;
574 }
575
576 /**
577 * dp_softap_inspect_traffic_end_indication_pkt() - Restore tos field for last
578 * packet in data stream
579 * @dp_intf: pointer to DP interface
580 * @nbuf: pointer to OS packet
581 *
582 * Return: None
583 */
584 static inline void
dp_softap_inspect_traffic_end_indication_pkt(struct wlan_dp_intf * dp_intf,qdf_nbuf_t nbuf)585 dp_softap_inspect_traffic_end_indication_pkt(struct wlan_dp_intf *dp_intf,
586 qdf_nbuf_t nbuf)
587 {
588 uint8_t tos, tc;
589 bool ret;
590
591 if (qdf_nbuf_data_is_ipv4_pkt(qdf_nbuf_data(nbuf))) {
592 tos = qdf_nbuf_data_get_ipv4_tos(qdf_nbuf_data(nbuf));
593 ret = wlan_dp_traffic_end_indication_update_dscp(dp_intf, &tos);
594 if (ret) {
595 qdf_nbuf_data_set_ipv4_tos(qdf_nbuf_data(nbuf), tos);
596 if (qdf_nbuf_is_ipv4_last_fragment(nbuf))
597 QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) =
598 QDF_NBUF_CB_PACKET_TYPE_END_INDICATION;
599 }
600 } else if (qdf_nbuf_is_ipv6_pkt(nbuf)) {
601 tc = qdf_nbuf_data_get_ipv6_tc(qdf_nbuf_data(nbuf));
602 ret = wlan_dp_traffic_end_indication_update_dscp(dp_intf, &tc);
603 if (ret) {
604 qdf_nbuf_data_set_ipv6_tc(qdf_nbuf_data(nbuf), tc);
605 QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) =
606 QDF_NBUF_CB_PACKET_TYPE_END_INDICATION;
607 }
608 }
609 }
610
611 /**
612 * dp_softap_traffic_end_indication_enabled() - Check if traffic end indication
613 * is enabled or not
614 * @dp_intf: pointer to DP interface
615 *
616 * Return: True or False
617 */
618 static inline bool
dp_softap_traffic_end_indication_enabled(struct wlan_dp_intf * dp_intf)619 dp_softap_traffic_end_indication_enabled(struct wlan_dp_intf *dp_intf)
620 {
621 return qdf_unlikely(dp_intf->traffic_end_ind.enabled);
622 }
623 #else
624 static inline bool
dp_softap_traffic_end_indication_enabled(struct wlan_dp_intf * dp_intf)625 dp_softap_traffic_end_indication_enabled(struct wlan_dp_intf *dp_intf)
626 {
627 return false;
628 }
629
630 static inline void
dp_softap_inspect_traffic_end_indication_pkt(struct wlan_dp_intf * dp_intf,qdf_nbuf_t nbuf)631 dp_softap_inspect_traffic_end_indication_pkt(struct wlan_dp_intf *dp_intf,
632 qdf_nbuf_t nbuf)
633 {}
634 #endif
635
636 /**
637 * dp_softap_start_xmit() - Transmit a frame
638 * @nbuf: pointer to Network buffer
639 * @dp_link: DP link handle
640 *
641 * Return: QDF_STATUS_SUCCESS on successful transmission
642 */
dp_softap_start_xmit(qdf_nbuf_t nbuf,struct wlan_dp_link * dp_link)643 QDF_STATUS dp_softap_start_xmit(qdf_nbuf_t nbuf, struct wlan_dp_link *dp_link)
644 {
645 struct wlan_dp_intf *dp_intf = dp_link->dp_intf;
646 struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx;
647 struct qdf_mac_addr *dest_mac_addr;
648 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
649 uint32_t num_seg;
650 struct dp_tx_rx_stats *stats = &dp_intf->dp_stats.tx_rx_stats;
651 int cpu = qdf_get_smp_processor_id();
652
653 dest_mac_addr = (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) +
654 QDF_NBUF_DEST_MAC_OFFSET);
655 ++stats->per_cpu[cpu].tx_called;
656 stats->cont_txtimeout_cnt = 0;
657
658 if (QDF_IS_STATUS_ERROR(dp_softap_validate_driver_state(dp_intf)))
659 goto drop_pkt;
660
661 wlan_dp_pkt_add_timestamp(dp_intf, QDF_PKT_TX_DRIVER_ENTRY, nbuf);
662
663 if (QDF_IS_STATUS_ERROR(dp_softap_validate_peer_state(dp_link, nbuf)))
664 goto drop_pkt;
665
666 dp_softap_get_tx_resource(dp_link, nbuf);
667
668 nbuf = dp_sap_nbuf_orphan(dp_intf, nbuf);
669 if (!nbuf)
670 goto drop_pkt_accounting;
671
672 qdf_net_buf_debug_acquire_skb(nbuf, __FILE__, __LINE__);
673
674 qdf_net_stats_add_tx_bytes(&dp_intf->stats, qdf_nbuf_len(nbuf));
675
676 if (qdf_nbuf_is_tso(nbuf)) {
677 num_seg = qdf_nbuf_get_tso_num_seg(nbuf);
678 qdf_net_stats_add_tx_pkts(&dp_intf->stats, num_seg);
679 } else {
680 qdf_net_stats_add_tx_pkts(&dp_intf->stats, 1);
681 dp_ctx->no_tx_offload_pkt_cnt++;
682 }
683
684 QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(nbuf) = 0;
685
686 if (qdf_unlikely(QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) ==
687 QDF_NBUF_CB_PACKET_TYPE_DHCP))
688 dp_softap_inspect_dhcp_packet(dp_link, nbuf, QDF_TX);
689
690 if (qdf_unlikely(QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) ==
691 QDF_NBUF_CB_PACKET_TYPE_EAPOL)) {
692 dp_softap_inspect_tx_eap_pkt(dp_intf, nbuf, false);
693 dp_event_eapol_log(nbuf, QDF_TX);
694 }
695
696 if (dp_softap_traffic_end_indication_enabled(dp_intf))
697 dp_softap_inspect_traffic_end_indication_pkt(dp_intf, nbuf);
698
699 dp_softap_config_tx_pkt_tracing(dp_intf, nbuf);
700
701 /* check whether need to linearize skb, like non-linear udp data */
702 if (dp_nbuf_nontso_linearize(nbuf) != QDF_STATUS_SUCCESS) {
703 dp_debug_rl("nbuf %pK linearize failed. drop the pkt", nbuf);
704 goto drop_pkt_and_release_skb;
705 }
706
707 if (dp_intf->txrx_ops.tx.tx(soc, dp_link->link_id, nbuf)) {
708 dp_debug("Failed to send packet to txrx for sta: "
709 QDF_MAC_ADDR_FMT,
710 QDF_MAC_ADDR_REF(dest_mac_addr->bytes));
711 goto drop_pkt_and_release_skb;
712 }
713
714 return QDF_STATUS_SUCCESS;
715
716 drop_pkt_and_release_skb:
717 qdf_net_buf_debug_release_skb(nbuf);
718 drop_pkt:
719 qdf_dp_trace_data_pkt(nbuf, QDF_TRACE_DEFAULT_PDEV_ID,
720 QDF_DP_TRACE_DROP_PACKET_RECORD, 0,
721 QDF_TX);
722 qdf_nbuf_kfree(nbuf);
723 drop_pkt_accounting:
724 qdf_net_stats_inc_tx_dropped(&dp_intf->stats);
725
726 return QDF_STATUS_E_FAILURE;
727 }
728
dp_softap_tx_timeout(struct wlan_dp_intf * dp_intf)729 void dp_softap_tx_timeout(struct wlan_dp_intf *dp_intf)
730 {
731 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
732
733 cdp_dump_flow_pool_info(cds_get_context(QDF_MODULE_ID_SOC));
734
735 ++dp_intf->dp_stats.tx_rx_stats.tx_timeout_cnt;
736 ++dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt;
737
738 if (dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt >
739 DP_TX_STALL_THRESHOLD) {
740 dp_err("Detected data stall due to continuous TX timeouts");
741 dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt = 0;
742
743 if (dp_is_data_stall_event_enabled(DP_HOST_SAP_TX_TIMEOUT))
744 cdp_post_data_stall_event(soc,
745 DATA_STALL_LOG_INDICATOR_HOST_DRIVER,
746 DATA_STALL_LOG_HOST_SOFTAP_TX_TIMEOUT,
747 OL_TXRX_PDEV_ID, 0xFF,
748 DATA_STALL_LOG_RECOVERY_TRIGGER_PDR);
749 }
750 }
751
752 /**
753 * dp_softap_notify_tx_compl_cbk() - callback to notify tx completion
754 * @nbuf: pointer to n/w buffer
755 * @context: pointer to DP interface
756 * @flag: tx status flag
757 *
758 * Return: None
759 */
dp_softap_notify_tx_compl_cbk(qdf_nbuf_t nbuf,void * context,uint16_t flag)760 void dp_softap_notify_tx_compl_cbk(qdf_nbuf_t nbuf,
761 void *context, uint16_t flag)
762 {
763 struct wlan_dp_link *dp_link = context;
764 struct wlan_dp_intf *dp_intf;
765
766 if (!is_dp_link_valid(dp_link))
767 return;
768
769 dp_intf = dp_link->dp_intf;
770 if (QDF_NBUF_CB_PACKET_TYPE_DHCP == QDF_NBUF_CB_GET_PACKET_TYPE(nbuf)) {
771 dp_debug("sending DHCP indication");
772 dp_softap_notify_dhcp_ind(context, nbuf);
773 } else if (QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) ==
774 QDF_NBUF_CB_PACKET_TYPE_EAPOL) {
775 dp_softap_inspect_tx_eap_pkt(dp_intf, nbuf, true);
776 }
777 }
778
779 #ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS
780 static inline
dp_softap_tsf_timestamp_rx(struct wlan_dp_psoc_context * dp_ctx,qdf_nbuf_t netbuf)781 void dp_softap_tsf_timestamp_rx(struct wlan_dp_psoc_context *dp_ctx,
782 qdf_nbuf_t netbuf)
783 {
784 dp_ctx->dp_ops.dp_tsf_timestamp_rx(dp_ctx->dp_ops.callback_ctx,
785 netbuf);
786 }
787 #else
788 static inline
dp_softap_tsf_timestamp_rx(struct wlan_dp_psoc_context * dp_ctx,qdf_nbuf_t netbuf)789 void dp_softap_tsf_timestamp_rx(struct wlan_dp_psoc_context *dp_ctx,
790 qdf_nbuf_t netbuf)
791 {
792 }
793 #endif
794
795 #ifdef WLAN_FEATURE_11BE_MLO
dp_nbuf_dst_addr_is_mld_addr(struct wlan_dp_intf * dp_intf,qdf_nbuf_t nbuf)796 static inline bool dp_nbuf_dst_addr_is_mld_addr(struct wlan_dp_intf *dp_intf,
797 qdf_nbuf_t nbuf)
798 {
799 struct qdf_mac_addr *mld_addr;
800
801 mld_addr = (struct qdf_mac_addr *)&dp_intf->mac_addr;
802
803 if (!qdf_is_macaddr_zero(mld_addr) &&
804 !qdf_mem_cmp(mld_addr->bytes,
805 (qdf_nbuf_data(nbuf) +
806 QDF_NBUF_DEST_MAC_OFFSET),
807 QDF_MAC_ADDR_SIZE))
808 return true;
809
810 return false;
811 }
812 #else
dp_nbuf_dst_addr_is_mld_addr(struct wlan_dp_intf * dp_intf,qdf_nbuf_t nbuf)813 static inline bool dp_nbuf_dst_addr_is_mld_addr(struct wlan_dp_intf *dp_intf,
814 qdf_nbuf_t nbuf)
815 {
816 return false;
817 }
818 #endif
819
dp_softap_rx_packet_cbk(void * link_ctx,qdf_nbuf_t rx_buf)820 QDF_STATUS dp_softap_rx_packet_cbk(void *link_ctx, qdf_nbuf_t rx_buf)
821 {
822 struct wlan_dp_intf *dp_intf = NULL;
823 struct wlan_dp_link *dp_link = NULL;
824 QDF_STATUS qdf_status;
825 unsigned int cpu_index;
826 qdf_nbuf_t nbuf = NULL;
827 qdf_nbuf_t next = NULL;
828 struct wlan_dp_psoc_context *dp_ctx = NULL;
829 bool is_eapol = false;
830 struct dp_tx_rx_stats *stats;
831
832 /* Sanity check on inputs */
833 if (unlikely(!link_ctx || !rx_buf)) {
834 dp_err("Null params being passed");
835 return QDF_STATUS_E_FAILURE;
836 }
837
838 dp_link = (struct wlan_dp_link *)link_ctx;
839 dp_intf = dp_link->dp_intf;
840 dp_ctx = dp_intf->dp_ctx;
841
842 stats = &dp_intf->dp_stats.tx_rx_stats;
843 /* walk the chain until all are processed */
844 next = rx_buf;
845
846 while (next) {
847 nbuf = next;
848 next = qdf_nbuf_next(nbuf);
849 qdf_nbuf_set_next(nbuf, NULL);
850
851 dp_softap_dump_nbuf(nbuf);
852
853 qdf_nbuf_set_dev(nbuf, dp_intf->dev);
854
855 cpu_index = qdf_get_cpu();
856 ++stats->per_cpu[cpu_index].rx_packets;
857 qdf_net_stats_add_rx_pkts(&dp_intf->stats, 1);
858 /* count aggregated RX frame into stats */
859 qdf_net_stats_add_rx_pkts(&dp_intf->stats,
860 qdf_nbuf_get_gso_segs(nbuf));
861 qdf_net_stats_add_rx_bytes(&dp_intf->stats,
862 qdf_nbuf_len(nbuf));
863
864 dp_softap_inspect_dhcp_packet(dp_link, nbuf, QDF_RX);
865
866 if (qdf_nbuf_is_ipv4_eapol_pkt(nbuf))
867 is_eapol = true;
868
869 if (qdf_unlikely(is_eapol &&
870 !(!qdf_mem_cmp(dp_link->mac_addr.bytes,
871 qdf_nbuf_data(nbuf) +
872 QDF_NBUF_DEST_MAC_OFFSET,
873 QDF_MAC_ADDR_SIZE) ||
874 dp_nbuf_dst_addr_is_mld_addr(dp_intf, nbuf)))) {
875 qdf_nbuf_free(nbuf);
876 continue;
877 }
878
879 wlan_dp_pkt_add_timestamp(dp_intf,
880 QDF_PKT_RX_DRIVER_EXIT, nbuf);
881
882 dp_event_eapol_log(nbuf, QDF_RX);
883 qdf_dp_trace_log_pkt(dp_link->link_id,
884 nbuf, QDF_RX, QDF_TRACE_DEFAULT_PDEV_ID,
885 dp_intf->device_mode);
886 DPTRACE(qdf_dp_trace(nbuf,
887 QDF_DP_TRACE_RX_PACKET_PTR_RECORD,
888 QDF_TRACE_DEFAULT_PDEV_ID,
889 qdf_nbuf_data_addr(nbuf),
890 sizeof(qdf_nbuf_data(nbuf)), QDF_RX));
891 DPTRACE(qdf_dp_trace_data_pkt(nbuf, QDF_TRACE_DEFAULT_PDEV_ID,
892 QDF_DP_TRACE_RX_PACKET_RECORD,
893 0, QDF_RX));
894
895 if (dp_rx_pkt_tracepoints_enabled())
896 qdf_trace_dp_packet(nbuf, QDF_RX, NULL, 0);
897
898 qdf_nbuf_set_protocol_eth_tye_trans(nbuf);
899
900 /* hold configurable wakelock for unicast traffic */
901 if (!dp_is_current_high_throughput(dp_ctx) &&
902 dp_ctx->dp_cfg.rx_wakelock_timeout &&
903 !qdf_nbuf_pkt_type_is_mcast(nbuf) &&
904 !qdf_nbuf_pkt_type_is_bcast(nbuf)) {
905 cds_host_diag_log_work(&dp_ctx->rx_wake_lock,
906 dp_ctx->dp_cfg.rx_wakelock_timeout,
907 WIFI_POWER_EVENT_WAKELOCK_HOLD_RX);
908 qdf_wake_lock_timeout_acquire(&dp_ctx->rx_wake_lock,
909 dp_ctx->dp_cfg.rx_wakelock_timeout);
910 }
911
912 /* Remove SKB from internal tracking table before submitting
913 * it to stack
914 */
915 qdf_net_buf_debug_release_skb(nbuf);
916
917 dp_softap_tsf_timestamp_rx(dp_ctx, nbuf);
918
919 if (is_eapol && dp_ctx->dp_ops.dp_send_rx_pkt_over_nl) {
920 if (dp_ctx->dp_ops.dp_send_rx_pkt_over_nl(dp_intf->dev,
921 (u8 *)&dp_link->conn_info.peer_macaddr,
922 nbuf, false))
923 qdf_status = QDF_STATUS_SUCCESS;
924 else
925 qdf_status = QDF_STATUS_E_INVAL;
926 qdf_nbuf_dev_kfree(nbuf);
927 } else {
928 qdf_status = wlan_dp_rx_deliver_to_stack(dp_intf, nbuf);
929 }
930
931 if (QDF_IS_STATUS_SUCCESS(qdf_status))
932 ++stats->per_cpu[cpu_index].rx_delivered;
933 else
934 ++stats->per_cpu[cpu_index].rx_refused;
935 }
936
937 return QDF_STATUS_SUCCESS;
938 }
939