1 /*
2 * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: nan_datapath.c
22 *
23 * MAC NAN Data path API implementation
24 */
25
26 #include "lim_utils.h"
27 #include "lim_api.h"
28 #include "lim_assoc_utils.h"
29 #include "nan_datapath.h"
30 #include "lim_types.h"
31 #include "lim_send_messages.h"
32 #include "wma_nan_datapath.h"
33 #include "os_if_nan.h"
34 #include "nan_public_structs.h"
35 #include "nan_ucfg_api.h"
36
37 /**
38 * lim_add_ndi_peer() - Function to add ndi peer
39 * @mac_ctx: handle to mac structure
40 * @vdev_id: vdev id on which peer is added
41 * @peer_mac_addr: peer to be added
42 *
43 * Return: QDF_STATUS_SUCCESS on success; error number otherwise
44 */
lim_add_ndi_peer(struct mac_context * mac_ctx,uint32_t vdev_id,struct qdf_mac_addr peer_mac_addr)45 static QDF_STATUS lim_add_ndi_peer(struct mac_context *mac_ctx,
46 uint32_t vdev_id, struct qdf_mac_addr peer_mac_addr)
47 {
48 struct pe_session *session;
49 tpDphHashNode sta_ds;
50 uint16_t assoc_id, peer_idx;
51 QDF_STATUS status;
52 uint8_t zero_mac_addr[QDF_MAC_ADDR_SIZE] = { 0, 0, 0, 0, 0, 0 };
53
54 if (!wlan_is_vdev_id_up(mac_ctx->pdev, vdev_id)) {
55 pe_err_rl("NDI vdev is not up");
56 return QDF_STATUS_E_FAILURE;
57 }
58
59 if (!qdf_mem_cmp(&zero_mac_addr, &peer_mac_addr.bytes[0],
60 QDF_MAC_ADDR_SIZE)) {
61 pe_err("Failing to add peer with all zero mac addr");
62 return QDF_STATUS_E_FAILURE;
63 }
64
65 session = pe_find_session_by_vdev_id(mac_ctx, vdev_id);
66 if (!session) {
67 /* couldn't find session */
68 pe_err("Session not found for vdev_id: %d", vdev_id);
69 return QDF_STATUS_E_FAILURE;
70 }
71
72 sta_ds = dph_lookup_hash_entry(mac_ctx,
73 peer_mac_addr.bytes,
74 &assoc_id, &session->dph.dphHashTable);
75 /* peer exists, don't do anything */
76 if (sta_ds) {
77 pe_err("NDI Peer already exists!!");
78 return QDF_STATUS_SUCCESS;
79 }
80 pe_info("Need to create NDI Peer :" QDF_MAC_ADDR_FMT,
81 QDF_MAC_ADDR_REF(peer_mac_addr.bytes));
82
83 ucfg_nan_set_peer_mc_list(session->vdev, peer_mac_addr);
84
85 peer_idx = lim_assign_peer_idx(mac_ctx, session);
86 if (!peer_idx) {
87 pe_err("Invalid peer_idx: %d", peer_idx);
88 return QDF_STATUS_SUCCESS;
89 }
90
91 sta_ds = dph_add_hash_entry(mac_ctx, peer_mac_addr.bytes, peer_idx,
92 &session->dph.dphHashTable);
93 if (!sta_ds) {
94 pe_err("Couldn't add dph entry");
95 /* couldn't add dph entry */
96 return QDF_STATUS_E_FAILURE;
97 }
98
99 /* wma decides NDI mode from wma->interface struct */
100 sta_ds->staType = STA_ENTRY_NDI_PEER;
101 status = lim_add_sta(mac_ctx, sta_ds, false, session);
102 if (QDF_STATUS_SUCCESS != status) {
103 /* couldn't add peer */
104 pe_err("limAddSta failed status: %d",
105 status);
106 return QDF_STATUS_E_FAILURE;
107 }
108
109 return QDF_STATUS_SUCCESS;
110 }
111
lim_add_ndi_peer_converged(uint32_t vdev_id,struct qdf_mac_addr peer_mac_addr)112 QDF_STATUS lim_add_ndi_peer_converged(uint32_t vdev_id,
113 struct qdf_mac_addr peer_mac_addr)
114 {
115 struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
116
117 if (!mac_ctx)
118 return QDF_STATUS_E_NULL_VALUE;
119
120 return lim_add_ndi_peer(mac_ctx, vdev_id, peer_mac_addr);
121 }
122
123 /**
124 * lim_ndp_delete_peer_by_addr() - Delete NAN data peer, given addr and vdev_id
125 * @mac_ctx: handle to mac context
126 * @vdev_id: vdev_id on which peer was added
127 * @peer_ndi_mac_addr: mac addr of peer
128 * This function deletes a peer if there was NDP_Confirm with REJECT
129 *
130 * Return: None
131 */
lim_ndp_delete_peer_by_addr(struct mac_context * mac_ctx,uint8_t vdev_id,struct qdf_mac_addr peer_ndi_mac_addr)132 static void lim_ndp_delete_peer_by_addr(struct mac_context *mac_ctx, uint8_t vdev_id,
133 struct qdf_mac_addr peer_ndi_mac_addr)
134 {
135 struct pe_session *session;
136 tpDphHashNode sta_ds;
137 uint16_t peer_idx;
138 uint8_t zero_mac_addr[QDF_MAC_ADDR_SIZE] = { 0, 0, 0, 0, 0, 0 };
139
140 if (!qdf_mem_cmp(&zero_mac_addr, &peer_ndi_mac_addr.bytes[0],
141 QDF_MAC_ADDR_SIZE)) {
142 pe_err("Failing to delete the peer with all zero mac addr");
143 return;
144 }
145
146 pe_info("deleting peer: "QDF_MAC_ADDR_FMT" confirm rejected",
147 QDF_MAC_ADDR_REF(peer_ndi_mac_addr.bytes));
148
149 session = pe_find_session_by_vdev_id(mac_ctx, vdev_id);
150 if (!session || (session->bssType != eSIR_NDI_MODE)) {
151 pe_err("PE session is NULL or non-NDI for sme session %d",
152 vdev_id);
153 return;
154 }
155
156 sta_ds = dph_lookup_hash_entry(mac_ctx, peer_ndi_mac_addr.bytes,
157 &peer_idx, &session->dph.dphHashTable);
158 if (!sta_ds) {
159 pe_err("Unknown NDI Peer");
160 return;
161 }
162 if (sta_ds->staType != STA_ENTRY_NDI_PEER) {
163 pe_err("Non-NDI Peer ignored");
164 return;
165 }
166 /*
167 * Call lim_del_sta() with response required set true. Hence
168 * DphHashEntry will be deleted after receiving that response.
169 */
170
171 lim_del_sta(mac_ctx, sta_ds, true, session);
172 }
173
lim_ndp_delete_peers_by_addr_converged(uint8_t vdev_id,struct qdf_mac_addr peer_ndi_mac_addr)174 void lim_ndp_delete_peers_by_addr_converged(uint8_t vdev_id,
175 struct qdf_mac_addr peer_ndi_mac_addr)
176 {
177 struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
178
179 if (!mac_ctx)
180 return;
181
182 lim_ndp_delete_peer_by_addr(mac_ctx, vdev_id, peer_ndi_mac_addr);
183 }
184
185 /**
186 * lim_ndp_delete_peers() - Delete NAN data peers
187 * @mac_ctx: handle to mac context
188 * @ndp_map: NDP instance/peer map
189 * @num_peers: number of peers entries in peer_map
190 * This function deletes a peer if there are no active NDPs left with that peer
191 *
192 * Return: None
193 */
lim_ndp_delete_peers(struct mac_context * mac_ctx,struct peer_ndp_map * ndp_map,uint8_t num_peers)194 static void lim_ndp_delete_peers(struct mac_context *mac_ctx,
195 struct peer_ndp_map *ndp_map, uint8_t num_peers)
196 {
197 tpDphHashNode sta_ds = NULL;
198 uint16_t deleted_num = 0;
199 int i, j;
200 struct pe_session *session;
201 struct qdf_mac_addr *deleted_peers;
202 uint16_t peer_idx;
203 bool found;
204
205 deleted_peers = qdf_mem_malloc(num_peers * sizeof(*deleted_peers));
206 if (!deleted_peers)
207 return;
208
209 for (i = 0; i < num_peers; i++) {
210 pe_debug("ndp_map[%d]: MAC: " QDF_MAC_ADDR_FMT " num_active %d",
211 i,
212 QDF_MAC_ADDR_REF(ndp_map[i].peer_ndi_mac_addr.bytes),
213 ndp_map[i].num_active_ndp_sessions);
214
215 /* Do not delete a peer with active NDPs */
216 if (ndp_map[i].num_active_ndp_sessions > 0)
217 continue;
218
219 session = pe_find_session_by_vdev_id(mac_ctx,
220 ndp_map[i].vdev_id);
221 if (!session || (session->bssType != eSIR_NDI_MODE)) {
222 pe_err("PE session is NULL or non-NDI for sme session %d",
223 ndp_map[i].vdev_id);
224 continue;
225 }
226
227 /* Check if this peer is already in the deleted list */
228 found = false;
229 for (j = 0; j < deleted_num && !found; j++) {
230 if (!qdf_mem_cmp(
231 &deleted_peers[j].bytes,
232 &ndp_map[i].peer_ndi_mac_addr.bytes,
233 QDF_MAC_ADDR_SIZE)) {
234 found = true;
235 break;
236 }
237 }
238 if (found)
239 continue;
240
241 sta_ds = dph_lookup_hash_entry(mac_ctx,
242 ndp_map[i].peer_ndi_mac_addr.bytes,
243 &peer_idx, &session->dph.dphHashTable);
244 if (!sta_ds) {
245 pe_err("Unknown NDI Peer");
246 continue;
247 }
248 if (sta_ds->staType != STA_ENTRY_NDI_PEER) {
249 pe_err("Non-NDI Peer ignored");
250 continue;
251 }
252 /*
253 * Call lim_del_sta() with response required set true.
254 * Hence DphHashEntry will be deleted after receiving
255 * that response.
256 */
257 lim_del_sta(mac_ctx, sta_ds, true, session);
258 qdf_copy_macaddr(&deleted_peers[deleted_num++],
259 &ndp_map[i].peer_ndi_mac_addr);
260 }
261 qdf_mem_free(deleted_peers);
262 }
263
lim_ndp_delete_peers_converged(struct peer_nan_datapath_map * ndp_map,uint8_t num_peers)264 void lim_ndp_delete_peers_converged(struct peer_nan_datapath_map *ndp_map,
265 uint8_t num_peers)
266 {
267 struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
268
269 if (!mac_ctx)
270 return;
271
272 lim_ndp_delete_peers(mac_ctx, (struct peer_ndp_map *)ndp_map,
273 num_peers);
274 }
275
276 /**
277 * lim_process_ndi_del_sta_rsp() - Handle WDA_DELETE_STA_RSP in eLIM_NDI_ROLE
278 * @mac_ctx: Global MAC context
279 * @lim_msg: LIM message
280 * @pe_session: PE session
281 *
282 * Return: None
283 */
lim_process_ndi_del_sta_rsp(struct mac_context * mac_ctx,struct scheduler_msg * lim_msg,struct pe_session * pe_session)284 void lim_process_ndi_del_sta_rsp(struct mac_context *mac_ctx,
285 struct scheduler_msg *lim_msg,
286 struct pe_session *pe_session)
287 {
288 tpDphHashNode sta_ds;
289 tpDeleteStaParams del_sta_params = (tpDeleteStaParams) lim_msg->bodyptr;
290 struct wlan_objmgr_vdev *vdev;
291 struct wlan_objmgr_psoc *psoc = mac_ctx->psoc;
292 struct nan_datapath_peer_ind peer_ind;
293
294 if (!del_sta_params) {
295 pe_err("del_sta_params is NULL");
296 return;
297 }
298 if (!LIM_IS_NDI_ROLE(pe_session)) {
299 pe_err("Session %d is not NDI role", del_sta_params->assocId);
300 goto skip_event;
301 }
302
303 sta_ds = dph_get_hash_entry(mac_ctx, del_sta_params->assocId,
304 &pe_session->dph.dphHashTable);
305 if (!sta_ds) {
306 pe_err("DPH Entry for STA %X is missing",
307 del_sta_params->assocId);
308 goto skip_event;
309 }
310
311 if (QDF_STATUS_SUCCESS != del_sta_params->status) {
312 pe_err("DEL STA failed!");
313 goto skip_event;
314 }
315 pe_info("Deleted STA AssocID %d MAC " QDF_MAC_ADDR_FMT,
316 sta_ds->assocId,
317 QDF_MAC_ADDR_REF(sta_ds->staAddr));
318
319 qdf_mem_copy(&peer_ind.peer_mac_addr.bytes,
320 sta_ds->staAddr, sizeof(tSirMacAddr));
321 lim_release_peer_idx(mac_ctx, sta_ds->assocId, pe_session);
322 lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr, sta_ds->assocId,
323 pe_session);
324 pe_session->limMlmState = eLIM_MLM_IDLE_STATE;
325
326 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
327 pe_session->smeSessionId,
328 WLAN_NAN_ID);
329 if (!vdev) {
330 pe_err("Failed to get vdev from id");
331 goto skip_event;
332 }
333 ucfg_nan_datapath_event_handler(psoc, vdev, NDP_PEER_DEPARTED,
334 &peer_ind);
335 wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID);
336
337 skip_event:
338 qdf_mem_free(del_sta_params);
339 lim_msg->bodyptr = NULL;
340 }
341
lim_process_ndi_mlm_add_bss_rsp(struct mac_context * mac_ctx,struct add_bss_rsp * add_bss_rsp,struct pe_session * session_entry)342 void lim_process_ndi_mlm_add_bss_rsp(struct mac_context *mac_ctx,
343 struct add_bss_rsp *add_bss_rsp,
344 struct pe_session *session_entry)
345 {
346 tLimMlmStartCnf mlm_start_cnf;
347
348 if (!add_bss_rsp) {
349 pe_err("add_bss_rsp is NULL");
350 return;
351 }
352 pe_debug("Status %d", add_bss_rsp->status);
353 if (QDF_IS_STATUS_SUCCESS(add_bss_rsp->status)) {
354 pe_debug("WDA_ADD_BSS_RSP returned QDF_STATUS_SUCCESS");
355 session_entry->limMlmState = eLIM_MLM_BSS_STARTED_STATE;
356 MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE,
357 session_entry->peSessionId,
358 session_entry->limMlmState));
359 session_entry->vdev_id = add_bss_rsp->vdev_id;
360 session_entry->limSystemRole = eLIM_NDI_ROLE;
361 session_entry->statypeForBss = STA_ENTRY_SELF;
362 /* Apply previously set configuration at HW */
363 lim_apply_configuration(mac_ctx, session_entry);
364 mlm_start_cnf.resultCode = eSIR_SME_SUCCESS;
365
366 /* Initialize peer ID pool */
367 lim_init_peer_idxpool(mac_ctx, session_entry);
368 } else {
369 pe_err("WDA_ADD_BSS_REQ failed with status %d",
370 add_bss_rsp->status);
371 mlm_start_cnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL;
372 }
373 mlm_start_cnf.sessionId = session_entry->peSessionId;
374 lim_send_start_bss_confirm(mac_ctx, &mlm_start_cnf);
375 }
376
lim_ndi_del_bss_rsp(struct mac_context * mac_ctx,struct del_bss_resp * del_bss,struct pe_session * session_entry)377 void lim_ndi_del_bss_rsp(struct mac_context * mac_ctx,
378 struct del_bss_resp *del_bss,
379 struct pe_session *session_entry)
380 {
381 tSirResultCodes rc = eSIR_SME_SUCCESS;
382
383 SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true);
384 if (!del_bss) {
385 pe_err("NDI: DEL_BSS_RSP with no body!");
386 rc = eSIR_SME_STOP_BSS_FAILURE;
387 goto end;
388 }
389 session_entry = pe_find_session_by_vdev_id(mac_ctx, del_bss->vdev_id);
390 if (!session_entry) {
391 pe_err("Session Does not exist for given sessionID");
392 goto end;
393 }
394
395 if (del_bss->status != QDF_STATUS_SUCCESS) {
396 pe_err("NDI: DEL_BSS_RSP error (%x)", del_bss->status);
397 rc = eSIR_SME_STOP_BSS_FAILURE;
398 goto end;
399 }
400
401 session_entry->limMlmState = eLIM_MLM_IDLE_STATE;
402
403 end:
404 /* Delete PE session once BSS is deleted */
405 if (session_entry) {
406 lim_send_stop_bss_response(mac_ctx,
407 session_entry->vdev_id,
408 rc);
409 pe_delete_session(mac_ctx, session_entry);
410 session_entry = NULL;
411 }
412 }
413
lim_send_sme_ndp_add_sta_rsp(struct mac_context * mac_ctx,struct pe_session * session,tAddStaParams * add_sta_rsp)414 static QDF_STATUS lim_send_sme_ndp_add_sta_rsp(struct mac_context *mac_ctx,
415 struct pe_session *session,
416 tAddStaParams *add_sta_rsp)
417 {
418 struct nan_datapath_peer_ind *new_peer_ind;
419 struct wlan_objmgr_psoc *psoc = mac_ctx->psoc;
420 struct wlan_objmgr_vdev *vdev;
421
422 if (!add_sta_rsp) {
423 pe_debug("Invalid add_sta_rsp");
424 return QDF_STATUS_E_INVAL;
425 }
426
427 if (!psoc) {
428 pe_debug("Invalid psoc");
429 return QDF_STATUS_E_INVAL;
430 }
431
432 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
433 add_sta_rsp->smesessionId,
434 WLAN_NAN_ID);
435 if (!vdev) {
436 pe_err("Failed to get vdev from id");
437 return QDF_STATUS_E_INVAL;
438 }
439
440 new_peer_ind = qdf_mem_malloc(sizeof(*new_peer_ind));
441 if (!new_peer_ind) {
442 wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID);
443 return QDF_STATUS_E_NOMEM;
444 }
445
446 qdf_mem_copy(new_peer_ind->peer_mac_addr.bytes, add_sta_rsp->staMac,
447 sizeof(tSirMacAddr));
448
449 ucfg_nan_datapath_event_handler(psoc, vdev, NDP_NEW_PEER, new_peer_ind);
450 qdf_mem_free(new_peer_ind);
451 wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID);
452 return QDF_STATUS_SUCCESS;
453 }
454
455 /**
456 * lim_ndp_add_sta_rsp() - handles add sta rsp for NDP from WMA
457 * @mac_ctx: handle to mac structure
458 * @session: session pointer
459 * @add_sta_rsp: add sta response struct
460 *
461 * Return: None
462 */
lim_ndp_add_sta_rsp(struct mac_context * mac_ctx,struct pe_session * session,tAddStaParams * add_sta_rsp)463 void lim_ndp_add_sta_rsp(struct mac_context *mac_ctx, struct pe_session *session,
464 tAddStaParams *add_sta_rsp)
465 {
466 tpDphHashNode sta_ds;
467 uint16_t peer_idx;
468
469 if (!add_sta_rsp) {
470 pe_err("Invalid add_sta_rsp");
471 qdf_mem_free(add_sta_rsp);
472 return;
473 }
474
475 SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true);
476 sta_ds = dph_lookup_hash_entry(mac_ctx, add_sta_rsp->staMac, &peer_idx,
477 &session->dph.dphHashTable);
478 if (!sta_ds) {
479 pe_err("NAN: ADD_STA_RSP for unknown MAC addr "
480 QDF_MAC_ADDR_FMT,
481 QDF_MAC_ADDR_REF(add_sta_rsp->staMac));
482 qdf_mem_free(add_sta_rsp);
483 return;
484 }
485
486 if (add_sta_rsp->status != QDF_STATUS_SUCCESS) {
487 pe_err("NAN: ADD_STA_RSP error %x for MAC addr: "QDF_MAC_ADDR_FMT,
488 add_sta_rsp->status,
489 QDF_MAC_ADDR_REF(add_sta_rsp->staMac));
490 /* delete the sta_ds allocated during ADD STA */
491 lim_delete_dph_hash_entry(mac_ctx, add_sta_rsp->staMac,
492 peer_idx, session);
493 qdf_mem_free(add_sta_rsp);
494 return;
495 }
496 sta_ds->valid = 1;
497 sta_ds->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE;
498 lim_send_sme_ndp_add_sta_rsp(mac_ctx, session, add_sta_rsp);
499 qdf_mem_free(add_sta_rsp);
500 }
501