blob: d6cdb4ffecaafc8b9e88d603d332b3bfeceebe3a [file] [log] [blame]
Frank Liuc3aad432017-03-13 21:30:21 +08001/*
Jeff Johnson067f2372019-02-07 12:52:39 -08002 * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
Frank Liuc3aad432017-03-13 21:30:21 +08003 *
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/**
20 * DOC: wlan_tdls_peer.c
21 *
22 * TDLS peer basic operations
23 */
24#include "wlan_tdls_main.h"
25#include "wlan_tdls_peer.h"
26#include <wlan_reg_services_api.h>
27#include <wlan_utility.h>
28#include <wlan_policy_mgr_api.h>
Bala Venkatesh36c69752019-08-20 18:32:03 +053029#include "wlan_reg_ucfg_api.h"
Frank Liuc3aad432017-03-13 21:30:21 +080030
31static uint8_t calculate_hash_key(const uint8_t *macaddr)
32{
33 uint8_t i, key;
34
35 for (i = 0, key = 0; i < 6; i++)
36 key ^= macaddr[i];
37
38 return key % WLAN_TDLS_PEER_LIST_SIZE;
39}
40
41struct tdls_peer *tdls_find_peer(struct tdls_vdev_priv_obj *vdev_obj,
42 const uint8_t *macaddr)
43{
44 uint8_t key;
45 QDF_STATUS status;
46 struct tdls_peer *peer;
47 qdf_list_t *head;
48 qdf_list_node_t *p_node;
49
50 key = calculate_hash_key(macaddr);
51 head = &vdev_obj->peer_list[key];
52
53 status = qdf_list_peek_front(head, &p_node);
54 while (QDF_IS_STATUS_SUCCESS(status)) {
55 peer = qdf_container_of(p_node, struct tdls_peer, node);
56 if (WLAN_ADDR_EQ(&peer->peer_mac, macaddr)
57 == QDF_STATUS_SUCCESS) {
58 return peer;
59 }
60 status = qdf_list_peek_next(head, p_node, &p_node);
61 }
62
Dustin Brown759661d2018-01-25 11:46:31 -080063 tdls_debug("no tdls peer " QDF_MAC_ADDR_STR,
Frank Liuc3aad432017-03-13 21:30:21 +080064 QDF_MAC_ADDR_ARRAY(macaddr));
65 return NULL;
66}
67
68/**
69 * tdls_find_peer_handler() - helper function for tdls_find_all_peer
70 * @psoc: soc object
71 * @obj: vdev object
72 * @arg: used to keep search peer parameters
73 *
74 * Return: None.
75 */
76static void
77tdls_find_peer_handler(struct wlan_objmgr_psoc *psoc, void *obj, void *arg)
78{
79 struct wlan_objmgr_vdev *vdev = obj;
80 struct tdls_search_peer_param *tdls_param = arg;
81 struct tdls_vdev_priv_obj *vdev_obj;
82
83 if (tdls_param->peer)
84 return;
85
86 if (!vdev) {
87 tdls_err("invalid vdev");
88 return;
89 }
90
91 if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE &&
92 wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE)
93 return;
94
95 vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
96 WLAN_UMAC_COMP_TDLS);
97 if (!vdev_obj)
98 return;
99
100 tdls_param->peer = tdls_find_peer(vdev_obj, tdls_param->macaddr);
101}
102
103struct tdls_peer *
104tdls_find_all_peer(struct tdls_soc_priv_obj *soc_obj, const uint8_t *macaddr)
105{
106 struct tdls_search_peer_param tdls_search_param;
107 struct wlan_objmgr_psoc *psoc;
108
109 if (!soc_obj) {
110 tdls_err("tdls soc object is NULL");
111 return NULL;
112 }
113
114 psoc = soc_obj->soc;
115 if (!psoc) {
116 tdls_err("psoc is NULL");
117 return NULL;
118 }
119 tdls_search_param.macaddr = macaddr;
120 tdls_search_param.peer = NULL;
121
122 wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
123 tdls_find_peer_handler,
124 &tdls_search_param, 0, WLAN_TDLS_NB_ID);
125
126 return tdls_search_param.peer;
127}
128
Kabilan Kannance5880e2017-04-17 21:53:42 -0700129uint8_t tdls_find_opclass(struct wlan_objmgr_psoc *psoc, uint8_t channel,
Frank Liuc3aad432017-03-13 21:30:21 +0800130 uint8_t bw_offset)
131{
132 char country[REG_ALPHA2_LEN + 1];
133 QDF_STATUS status;
134
135 if (!psoc) {
136 tdls_err("psoc is NULL");
137 return 0;
138 }
139
140 status = wlan_reg_read_default_country(psoc, country);
141 if (QDF_IS_STATUS_ERROR(status))
142 return 0;
143
144 return wlan_reg_dmn_get_opclass_from_channel(country, channel,
145 bw_offset);
146}
147
148/**
149 * tdls_add_peer() - add TDLS peer in TDLS vdev object
150 * @vdev_obj: TDLS vdev object
151 * @macaddr: MAC address of peer
152 *
153 * Allocate memory for the new peer, and add it to hash table.
154 *
155 * Return: new added TDLS peer, NULL if failed.
156 */
157static struct tdls_peer *tdls_add_peer(struct tdls_vdev_priv_obj *vdev_obj,
158 const uint8_t *macaddr)
159{
160 struct tdls_peer *peer;
161 struct tdls_soc_priv_obj *soc_obj;
162 uint8_t key = 0;
163 qdf_list_t *head;
164
165 peer = qdf_mem_malloc(sizeof(*peer));
166 if (!peer) {
167 tdls_err("add tdls peer malloc memory failed!");
168 return NULL;
169 }
170
171 soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
172 if (!soc_obj) {
173 tdls_err("NULL tdls soc object");
174 return NULL;
175 }
176
177 key = calculate_hash_key(macaddr);
178 head = &vdev_obj->peer_list[key];
179
180 qdf_mem_copy(&peer->peer_mac, macaddr, sizeof(peer->peer_mac));
181 peer->vdev_priv = vdev_obj;
182
183 peer->pref_off_chan_num =
184 soc_obj->tdls_configs.tdls_pre_off_chan_num;
185 peer->op_class_for_pref_off_chan =
Bala Venkatesh36c69752019-08-20 18:32:03 +0530186 tdls_get_opclass_from_bandwidth(soc_obj,
187 peer->pref_off_chan_num,
188 soc_obj->tdls_configs.tdls_pre_off_chan_bw);
nakul kachhwaha987f6b12019-07-26 11:41:23 +0530189
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +0530190 peer->valid_entry = false;
Frank Liuc3aad432017-03-13 21:30:21 +0800191
192 qdf_list_insert_back(head, &peer->node);
193
Dustin Brown759661d2018-01-25 11:46:31 -0800194 tdls_debug("add tdls peer: " QDF_MAC_ADDR_STR,
Frank Liuc3aad432017-03-13 21:30:21 +0800195 QDF_MAC_ADDR_ARRAY(macaddr));
196 return peer;
197}
198
199struct tdls_peer *tdls_get_peer(struct tdls_vdev_priv_obj *vdev_obj,
200 const uint8_t *macaddr)
201{
202 struct tdls_peer *peer;
203
204 peer = tdls_find_peer(vdev_obj, macaddr);
205 if (!peer)
206 peer = tdls_add_peer(vdev_obj, macaddr);
207
208 return peer;
209}
210
211static struct tdls_peer *
212tdls_find_progress_peer_in_list(qdf_list_t *head,
213 const uint8_t *macaddr, uint8_t skip_self)
214{
215 QDF_STATUS status;
216 struct tdls_peer *peer;
217 qdf_list_node_t *p_node;
218
219 status = qdf_list_peek_front(head, &p_node);
220 while (QDF_IS_STATUS_SUCCESS(status)) {
221 peer = qdf_container_of(p_node, struct tdls_peer, node);
222 if (skip_self && macaddr &&
223 WLAN_ADDR_EQ(&peer->peer_mac, macaddr)
224 == QDF_STATUS_SUCCESS) {
225 status = qdf_list_peek_next(head, p_node, &p_node);
226 continue;
227 } else if (TDLS_LINK_CONNECTING == peer->link_status) {
Dustin Brown759661d2018-01-25 11:46:31 -0800228 tdls_debug(QDF_MAC_ADDR_STR " TDLS_LINK_CONNECTING",
Frank Liuc3aad432017-03-13 21:30:21 +0800229 QDF_MAC_ADDR_ARRAY(peer->peer_mac.bytes));
230 return peer;
231 }
232 status = qdf_list_peek_next(head, p_node, &p_node);
233 }
234
235 return NULL;
236}
237
238/**
239 * tdls_find_progress_peer() - find the peer with ongoing TDLS progress
240 * on present vdev
241 * @vdev_obj: TDLS vdev object
242 * @macaddr: MAC address of peer, if NULL check for all the peer list
243 * @skip_self: If true, skip this macaddr. Otherwise, check all the peer list.
244 * if macaddr is NULL, this argument is ignored, and check for all
245 * the peer list.
246 *
247 * Return: Pointer to tdls_peer if TDLS is ongoing. Otherwise return NULL.
248 */
249static struct tdls_peer *
250tdls_find_progress_peer(struct tdls_vdev_priv_obj *vdev_obj,
251 const uint8_t *macaddr, uint8_t skip_self)
252{
253 uint8_t i;
254 struct tdls_peer *peer;
255 qdf_list_t *head;
256
257 if (!vdev_obj) {
258 tdls_err("invalid tdls vdev object");
259 return NULL;
260 }
261
262 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
263 head = &vdev_obj->peer_list[i];
264
265 peer = tdls_find_progress_peer_in_list(head, macaddr,
266 skip_self);
267 if (peer)
268 return peer;
269 }
270
271 return NULL;
272}
273
274/**
275 * tdls_find_progress_peer_handler() - helper function for tdls_is_progress
276 * @psoc: soc object
277 * @obj: vdev object
278 * @arg: used to keep search peer parameters
279 *
280 * Return: None.
281 */
282static void
283tdls_find_progress_peer_handler(struct wlan_objmgr_psoc *psoc,
284 void *obj, void *arg)
285{
286 struct wlan_objmgr_vdev *vdev = obj;
287 struct tdls_search_progress_param *tdls_progress = arg;
288 struct tdls_vdev_priv_obj *vdev_obj;
289
290 if (tdls_progress->peer)
291 return;
292
293 if (!vdev) {
294 tdls_err("invalid vdev");
295 return;
296 }
297
298 if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE &&
299 wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE)
300 return;
301
302 vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
303 WLAN_UMAC_COMP_TDLS);
304
305 tdls_progress->peer = tdls_find_progress_peer(vdev_obj,
306 tdls_progress->macaddr,
307 tdls_progress->skip_self);
308}
309
310struct tdls_peer *tdls_is_progress(struct tdls_vdev_priv_obj *vdev_obj,
311 const uint8_t *macaddr, uint8_t skip_self)
312{
313 struct tdls_search_progress_param tdls_progress;
314 struct wlan_objmgr_psoc *psoc;
315
316 if (!vdev_obj) {
317 tdls_err("invalid tdls vdev object");
318 return NULL;
319 }
320
Frank Liuc3aad432017-03-13 21:30:21 +0800321 psoc = wlan_vdev_get_psoc(vdev_obj->vdev);
Frank Liuc3aad432017-03-13 21:30:21 +0800322 if (!psoc) {
323 tdls_err("invalid psoc");
324 return NULL;
325 }
326 tdls_progress.macaddr = macaddr;
327 tdls_progress.skip_self = skip_self;
328 tdls_progress.peer = NULL;
329
330 wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
331 tdls_find_progress_peer_handler,
332 &tdls_progress, 0, WLAN_TDLS_NB_ID);
333
334 return tdls_progress.peer;
335}
336
337struct tdls_peer *
338tdls_find_first_connected_peer(struct tdls_vdev_priv_obj *vdev_obj)
339{
340 uint16_t i;
341 struct tdls_peer *peer;
342 qdf_list_t *head;
343 qdf_list_node_t *p_node;
344 QDF_STATUS status;
345
346 if (!vdev_obj) {
347 tdls_err("invalid tdls vdev object");
348 return NULL;
349 }
350
351 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
352 head = &vdev_obj->peer_list[i];
353
354 status = qdf_list_peek_front(head, &p_node);
355 while (QDF_IS_STATUS_SUCCESS(status)) {
356 peer = qdf_container_of(p_node, struct tdls_peer, node);
357
358 if (peer && TDLS_LINK_CONNECTED == peer->link_status) {
Dustin Brown759661d2018-01-25 11:46:31 -0800359 tdls_debug(QDF_MAC_ADDR_STR
Frank Liuc3aad432017-03-13 21:30:21 +0800360 " TDLS_LINK_CONNECTED",
361 QDF_MAC_ADDR_ARRAY(
362 peer->peer_mac.bytes));
363 return peer;
364 }
365 status = qdf_list_peek_next(head, p_node, &p_node);
366 }
367 }
368
369 return NULL;
370}
371
372/**
373 * tdls_determine_channel_opclass() - determine channel and opclass
374 * @soc_obj: TDLS soc object
375 * @vdev_obj: TDLS vdev object
376 * @peer: TDLS peer
377 * @channel: pointer to channel
378 * @opclass: pinter to opclass
379 *
380 * Function determines the channel and operating class
381 *
382 * Return: None.
383 */
384static void tdls_determine_channel_opclass(struct tdls_soc_priv_obj *soc_obj,
385 struct tdls_vdev_priv_obj *vdev_obj,
386 struct tdls_peer *peer,
387 uint32_t *channel, uint32_t *opclass)
388{
389 uint32_t vdev_id;
Jeff Johnson19867852017-11-09 09:54:12 -0800390 enum QDF_OPMODE opmode;
Frank Liuc3aad432017-03-13 21:30:21 +0800391 /*
392 * If tdls offchannel is not enabled then we provide base channel
393 * and in that case pass opclass as 0 since opclass is mainly needed
394 * for offchannel cases.
395 */
396 if (!(TDLS_IS_OFF_CHANNEL_ENABLED(
397 soc_obj->tdls_configs.tdls_feature_flags)) ||
398 soc_obj->tdls_fw_off_chan_mode != ENABLE_CHANSWITCH) {
Frank Liuc3aad432017-03-13 21:30:21 +0800399 vdev_id = wlan_vdev_get_id(vdev_obj->vdev);
400 opmode = wlan_vdev_mlme_get_opmode(vdev_obj->vdev);
Frank Liuc3aad432017-03-13 21:30:21 +0800401
Manikandan Mohan7fdb0252019-08-14 16:49:02 -0700402 *channel = wlan_freq_to_chan(
403 policy_mgr_get_channel(
404 soc_obj->soc,
Tushnim Bhattacharyyad7b52a12018-03-28 11:41:04 -0700405 policy_mgr_convert_device_mode_to_qdf_type(opmode),
Manikandan Mohan7fdb0252019-08-14 16:49:02 -0700406 &vdev_id));
Frank Liuc3aad432017-03-13 21:30:21 +0800407 *opclass = 0;
408 } else {
409 *channel = peer->pref_off_chan_num;
410 *opclass = peer->op_class_for_pref_off_chan;
411 }
412 tdls_debug("channel:%d opclass:%d", *channel, *opclass);
413}
414
415/**
416 * tdls_get_wifi_hal_state() - get TDLS wifi hal state on current peer
417 * @peer: TDLS peer
418 * @state: output parameter to store the TDLS wifi hal state
419 * @reason: output parameter to store the reason of the current peer
420 *
421 * Return: None.
422 */
423static void tdls_get_wifi_hal_state(struct tdls_peer *peer, uint32_t *state,
424 int32_t *reason)
425{
426 struct wlan_objmgr_vdev *vdev;
427 struct tdls_soc_priv_obj *soc_obj;
428
429 vdev = peer->vdev_priv->vdev;
430 soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
431 if (!soc_obj) {
432 tdls_err("can't get tdls object");
433 return;
434 }
435
436 *reason = peer->reason;
437
438 switch (peer->link_status) {
439 case TDLS_LINK_IDLE:
440 case TDLS_LINK_DISCOVERED:
441 case TDLS_LINK_DISCOVERING:
442 case TDLS_LINK_CONNECTING:
443 *state = QCA_WIFI_HAL_TDLS_S_ENABLED;
444 break;
445 case TDLS_LINK_CONNECTED:
446 if ((TDLS_IS_OFF_CHANNEL_ENABLED(
447 soc_obj->tdls_configs.tdls_feature_flags)) &&
448 (soc_obj->tdls_fw_off_chan_mode == ENABLE_CHANSWITCH))
449 *state = QCA_WIFI_HAL_TDLS_S_ESTABLISHED_OFF_CHANNEL;
450 else
451 *state = QCA_WIFI_HAL_TDLS_S_ENABLED;
452 break;
453 case TDLS_LINK_TEARING:
454 *state = QCA_WIFI_HAL_TDLS_S_DROPPED;
455 break;
456 }
457}
458
459/**
460 * tdls_extract_peer_state_param() - extract peer update params from TDLS peer
461 * @peer_param: output peer update params
462 * @peer: TDLS peer
463 *
464 * This is used when enable TDLS link
465 *
466 * Return: None.
467 */
468void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param,
469 struct tdls_peer *peer)
470{
471 uint16_t i, num;
472 struct tdls_vdev_priv_obj *vdev_obj;
473 struct tdls_soc_priv_obj *soc_obj;
474 enum channel_state ch_state;
475 struct wlan_objmgr_pdev *pdev;
476 uint8_t chan_id;
Bala Venkatesh36c69752019-08-20 18:32:03 +0530477 enum band_info cur_band = BAND_ALL;
Frank Liuc3aad432017-03-13 21:30:21 +0800478
479 vdev_obj = peer->vdev_priv;
480 soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
481 pdev = wlan_vdev_get_pdev(vdev_obj->vdev);
482 if (!soc_obj || !pdev) {
Jeff Johnson6ada3cd2017-09-18 10:07:54 -0700483 tdls_err("soc_obj: %pK, pdev: %pK", soc_obj, pdev);
Frank Liuc3aad432017-03-13 21:30:21 +0800484 return;
485 }
486
487 qdf_mem_zero(peer_param, sizeof(*peer_param));
Frank Liuc3aad432017-03-13 21:30:21 +0800488 peer_param->vdev_id = wlan_vdev_get_id(vdev_obj->vdev);
Frank Liuc3aad432017-03-13 21:30:21 +0800489
490 qdf_mem_copy(peer_param->peer_macaddr,
491 peer->peer_mac.bytes, QDF_MAC_ADDR_SIZE);
Jeff Johnson067f2372019-02-07 12:52:39 -0800492 peer_param->peer_state = TDLS_PEER_STATE_CONNECTED;
Frank Liuc3aad432017-03-13 21:30:21 +0800493 peer_param->peer_cap.is_peer_responder = peer->is_responder;
494 peer_param->peer_cap.peer_uapsd_queue = peer->uapsd_queues;
495 peer_param->peer_cap.peer_max_sp = peer->max_sp;
496 peer_param->peer_cap.peer_buff_sta_support = peer->buf_sta_capable;
497 peer_param->peer_cap.peer_off_chan_support =
498 peer->off_channel_capable;
499 peer_param->peer_cap.peer_curr_operclass = 0;
500 peer_param->peer_cap.self_curr_operclass = 0;
Frank Liuc3aad432017-03-13 21:30:21 +0800501 peer_param->peer_cap.pref_off_channum = peer->pref_off_chan_num;
502 peer_param->peer_cap.pref_off_chan_bandwidth =
503 soc_obj->tdls_configs.tdls_pre_off_chan_bw;
504 peer_param->peer_cap.opclass_for_prefoffchan =
505 peer->op_class_for_pref_off_chan;
506
Bala Venkatesh36c69752019-08-20 18:32:03 +0530507 if (QDF_STATUS_SUCCESS != ucfg_reg_get_band(pdev, &cur_band)) {
508 tdls_err("not able get the current frequency band");
509 return;
510 }
511
512 if (BAND_2G == cur_band) {
513 tdls_err("sending the offchannel value as 0 as only 2g is supported");
514 peer_param->peer_cap.pref_off_channum = 0;
515 peer_param->peer_cap.opclass_for_prefoffchan = 0;
516 }
Frank Liuc3aad432017-03-13 21:30:21 +0800517 if (wlan_reg_is_dfs_ch(pdev, peer_param->peer_cap.pref_off_channum)) {
518 tdls_err("Resetting TDLS off-channel from %d to %d",
519 peer_param->peer_cap.pref_off_channum,
520 WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF);
521 peer_param->peer_cap.pref_off_channum =
522 WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF;
523 }
524
525 num = 0;
526 for (i = 0; i < peer->supported_channels_len; i++) {
527 chan_id = peer->supported_channels[i];
528 ch_state = wlan_reg_get_channel_state(pdev, chan_id);
529
530 if (CHANNEL_STATE_INVALID != ch_state &&
531 CHANNEL_STATE_DFS != ch_state &&
Kiran Kumar Lokere693754c2018-05-15 15:48:57 -0700532 !wlan_reg_is_dsrc_chan(pdev, chan_id)) {
Frank Liuc3aad432017-03-13 21:30:21 +0800533 peer_param->peer_cap.peer_chan[num].chan_id = chan_id;
534 peer_param->peer_cap.peer_chan[num].pwr =
535 wlan_reg_get_channel_reg_power(pdev, chan_id);
536 peer_param->peer_cap.peer_chan[num].dfs_set = false;
Bala Venkateshce774662018-11-02 15:17:53 +0530537 peer_param->peer_cap.peer_chanlen++;
Frank Liuc3aad432017-03-13 21:30:21 +0800538 num++;
539 }
540 }
541
542 peer_param->peer_cap.peer_oper_classlen =
543 peer->supported_oper_classes_len;
544 for (i = 0; i < peer->supported_oper_classes_len; i++)
545 peer_param->peer_cap.peer_oper_class[i] =
546 peer->supported_oper_classes[i];
547}
548
549/**
550 * tdls_set_link_status() - set link statue for TDLS peer
551 * @vdev_obj: TDLS vdev object
552 * @mac: MAC address of current TDLS peer
553 * @link_status: link status
554 * @link_reason: reason with link status
555 *
556 * Return: None.
557 */
558void tdls_set_link_status(struct tdls_vdev_priv_obj *vdev_obj,
559 const uint8_t *mac,
560 enum tdls_link_state link_status,
561 enum tdls_link_state_reason link_reason)
562{
563 uint32_t state = 0;
564 int32_t res = 0;
565 uint32_t op_class = 0;
566 uint32_t channel = 0;
567 struct tdls_peer *peer;
568 struct tdls_soc_priv_obj *soc_obj;
569
570 peer = tdls_find_peer(vdev_obj, mac);
571 if (!peer) {
572 tdls_err("peer is NULL, can't set link status %d, reason %d",
573 link_status, link_reason);
574 return;
575 }
576
577 peer->link_status = link_status;
578
579 if (link_status >= TDLS_LINK_DISCOVERED)
580 peer->discovery_attempt = 0;
581
582 if (peer->is_forced_peer && peer->state_change_notification) {
583 peer->reason = link_reason;
584
585 soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
586 if (!soc_obj) {
587 tdls_err("NULL psoc object");
588 return;
589 }
590
591 tdls_determine_channel_opclass(soc_obj, vdev_obj,
592 peer, &channel, &op_class);
593 tdls_get_wifi_hal_state(peer, &state, &res);
594 peer->state_change_notification(mac, op_class, channel,
595 state, res, soc_obj->soc);
596 }
597}
598
599void tdls_set_peer_link_status(struct tdls_peer *peer,
600 enum tdls_link_state link_status,
601 enum tdls_link_state_reason link_reason)
602{
603 uint32_t state = 0;
604 int32_t res = 0;
605 uint32_t op_class = 0;
606 uint32_t channel = 0;
607 struct tdls_soc_priv_obj *soc_obj;
608 struct tdls_vdev_priv_obj *vdev_obj;
609
610 peer->link_status = link_status;
611
612 if (link_status >= TDLS_LINK_DISCOVERED)
613 peer->discovery_attempt = 0;
614
615 if (peer->is_forced_peer && peer->state_change_notification) {
616 peer->reason = link_reason;
617
618 vdev_obj = peer->vdev_priv;
619 soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
620 if (!soc_obj) {
621 tdls_err("NULL psoc object");
622 return;
623 }
624
625 tdls_determine_channel_opclass(soc_obj, vdev_obj,
626 peer, &channel, &op_class);
627 tdls_get_wifi_hal_state(peer, &state, &res);
628 peer->state_change_notification(peer->peer_mac.bytes,
629 op_class, channel, state,
630 res, soc_obj->soc);
631 }
632}
633
634void tdls_set_peer_caps(struct tdls_vdev_priv_obj *vdev_obj,
635 const uint8_t *macaddr,
636 struct tdls_update_peer_params *req_info)
637{
Kabilan Kannana75fa9d2017-08-23 18:06:30 -0700638 uint8_t is_buffer_sta = 0;
639 uint8_t is_off_channel_supported = 0;
640 uint8_t is_qos_wmm_sta = 0;
Frank Liuc3aad432017-03-13 21:30:21 +0800641 struct tdls_soc_priv_obj *soc_obj;
642 struct tdls_peer *curr_peer;
643 uint32_t feature;
644
645 soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
646 if (!soc_obj) {
647 tdls_err("NULL psoc object");
648 return;
649 }
650
651 curr_peer = tdls_find_peer(vdev_obj, macaddr);
652 if (!curr_peer) {
653 tdls_err("NULL tdls peer");
654 return;
655 }
656
657 feature = soc_obj->tdls_configs.tdls_feature_flags;
658 if ((1 << 4) & req_info->extn_capability[3])
659 is_buffer_sta = 1;
660
661 if ((1 << 6) & req_info->extn_capability[3])
662 is_off_channel_supported = 1;
663
664 if (TDLS_IS_WMM_ENABLED(feature) && req_info->is_qos_wmm_sta)
Kabilan Kannana75fa9d2017-08-23 18:06:30 -0700665 is_qos_wmm_sta = 1;
Frank Liuc3aad432017-03-13 21:30:21 +0800666
667 curr_peer->uapsd_queues = req_info->uapsd_queues;
668 curr_peer->max_sp = req_info->max_sp;
669 curr_peer->buf_sta_capable = is_buffer_sta;
670 curr_peer->off_channel_capable = is_off_channel_supported;
671
672 qdf_mem_copy(curr_peer->supported_channels,
673 req_info->supported_channels,
674 req_info->supported_channels_len);
675
676 curr_peer->supported_channels_len = req_info->supported_channels_len;
677
678 qdf_mem_copy(curr_peer->supported_oper_classes,
679 req_info->supported_oper_classes,
680 req_info->supported_oper_classes_len);
681
682 curr_peer->supported_oper_classes_len =
683 req_info->supported_oper_classes_len;
684
685 curr_peer->qos = is_qos_wmm_sta;
686}
687
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +0530688QDF_STATUS tdls_set_valid(struct tdls_vdev_priv_obj *vdev_obj,
689 const uint8_t *macaddr)
Frank Liuc3aad432017-03-13 21:30:21 +0800690{
691 struct tdls_peer *peer;
692
693 peer = tdls_find_peer(vdev_obj, macaddr);
694 if (!peer) {
695 tdls_err("peer is NULL");
696 return QDF_STATUS_E_FAILURE;
697 }
698
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +0530699 peer->valid_entry = true;
Frank Liuc3aad432017-03-13 21:30:21 +0800700
701 return QDF_STATUS_SUCCESS;
702}
703
Frank Liuc3aad432017-03-13 21:30:21 +0800704QDF_STATUS tdls_set_force_peer(struct tdls_vdev_priv_obj *vdev_obj,
705 const uint8_t *macaddr, bool forcepeer)
706{
707 struct tdls_peer *peer;
708
709 peer = tdls_find_peer(vdev_obj, macaddr);
710 if (!peer) {
711 tdls_err("peer is NULL");
712 return QDF_STATUS_E_FAILURE;
713 }
714 peer->is_forced_peer = forcepeer;
715
716 return QDF_STATUS_SUCCESS;
717}
718
719QDF_STATUS tdls_set_callback(struct tdls_peer *peer,
720 tdls_state_change_callback callback)
721{
722 if (!peer) {
723 tdls_err("peer is NULL");
724 return QDF_STATUS_E_FAILURE;
725 }
726 peer->state_change_notification = callback;
727
728 return QDF_STATUS_SUCCESS;
729}
730
731QDF_STATUS tdls_set_extctrl_param(struct tdls_peer *peer, uint32_t chan,
732 uint32_t max_latency, uint32_t op_class,
733 uint32_t min_bandwidth)
734{
735 if (!peer) {
736 tdls_err("peer is NULL");
737 return QDF_STATUS_E_FAILURE;
738 }
739 peer->op_class_for_pref_off_chan = (uint8_t)op_class;
740 peer->pref_off_chan_num = (uint8_t)chan;
741
742 return QDF_STATUS_SUCCESS;
743}
744
745QDF_STATUS tdls_reset_peer(struct tdls_vdev_priv_obj *vdev_obj,
746 const uint8_t *macaddr)
747{
748 struct tdls_soc_priv_obj *soc_obj;
749 struct tdls_peer *curr_peer;
750 struct tdls_user_config *config;
751
752 soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
753 if (!soc_obj) {
754 tdls_err("NULL psoc object");
755 return QDF_STATUS_E_FAILURE;
756 }
757
758 curr_peer = tdls_find_peer(vdev_obj, macaddr);
759 if (!curr_peer) {
760 tdls_err("NULL tdls peer");
761 return QDF_STATUS_E_FAILURE;
762 }
763
764 if (!curr_peer->is_forced_peer) {
765 config = &soc_obj->tdls_configs;
766 curr_peer->pref_off_chan_num = config->tdls_pre_off_chan_num;
767 curr_peer->op_class_for_pref_off_chan =
Bala Venkatesh36c69752019-08-20 18:32:03 +0530768 tdls_get_opclass_from_bandwidth(soc_obj,
769 curr_peer->pref_off_chan_num,
770 soc_obj->tdls_configs.tdls_pre_off_chan_bw);
Frank Liuc3aad432017-03-13 21:30:21 +0800771 }
772
773 tdls_set_peer_link_status(curr_peer, TDLS_LINK_IDLE,
774 TDLS_LINK_UNSPECIFIED);
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +0530775 curr_peer->valid_entry = false;
Frank Liuc3aad432017-03-13 21:30:21 +0800776
777 return QDF_STATUS_SUCCESS;
778}
779
780void tdls_peer_idle_timers_destroy(struct tdls_vdev_priv_obj *vdev_obj)
781{
782 uint16_t i;
783 struct tdls_peer *peer;
784 qdf_list_t *head;
785 qdf_list_node_t *p_node;
786 QDF_STATUS status;
787
788 if (!vdev_obj) {
789 tdls_err("NULL tdls vdev object");
790 return;
791 }
792
793 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
794 head = &vdev_obj->peer_list[i];
795
796 status = qdf_list_peek_front(head, &p_node);
797 while (QDF_IS_STATUS_SUCCESS(status)) {
798 peer = qdf_container_of(p_node, struct tdls_peer, node);
799 if (peer && peer->is_peer_idle_timer_initialised) {
Dustin Brown759661d2018-01-25 11:46:31 -0800800 tdls_debug(QDF_MAC_ADDR_STR
Frank Liuc3aad432017-03-13 21:30:21 +0800801 ": destroy idle timer ",
802 QDF_MAC_ADDR_ARRAY(
803 peer->peer_mac.bytes));
804 qdf_mc_timer_stop(&peer->peer_idle_timer);
805 qdf_mc_timer_destroy(&peer->peer_idle_timer);
806 }
807 status = qdf_list_peek_next(head, p_node, &p_node);
808 }
809 }
810}
811
812void tdls_free_peer_list(struct tdls_vdev_priv_obj *vdev_obj)
813{
814 uint16_t i;
815 struct tdls_peer *peer;
816 qdf_list_t *head;
817 qdf_list_node_t *p_node;
818
819 if (!vdev_obj) {
820 tdls_err("NULL tdls vdev object");
821 return;
822 }
823
824 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
825 head = &vdev_obj->peer_list[i];
826
827 while (QDF_IS_STATUS_SUCCESS(
828 qdf_list_remove_front(head, &p_node))) {
829 peer = qdf_container_of(p_node, struct tdls_peer, node);
830 qdf_mem_free(peer);
831 }
832 qdf_list_destroy(head);
833 }
834}