1 /*
2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 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: wlan_hdd_nan.c
22 *
23 * WLAN Host Device Driver NAN API implementation
24 */
25
26 #include <linux/version.h>
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <net/cfg80211.h>
30 #include <ani_global.h>
31 #include "sme_api.h"
32 #include "wlan_hdd_main.h"
33 #include "wlan_hdd_nan.h"
34 #include "osif_sync.h"
35 #include <qca_vendor.h>
36 #include "cfg_nan_api.h"
37 #include "os_if_nan.h"
38 #include "../../core/src/nan_main_i.h"
39 #include "spatial_reuse_api.h"
40 #include "wlan_nan_api.h"
41 #include "spatial_reuse_ucfg_api.h"
42
43 /**
44 * wlan_hdd_nan_is_supported() - HDD NAN support query function
45 * @hdd_ctx: Pointer to hdd context
46 *
47 * This function is called to determine if NAN is supported by the
48 * driver and by the firmware.
49 *
50 * Return: true if NAN is supported by the driver and firmware
51 */
wlan_hdd_nan_is_supported(struct hdd_context * hdd_ctx)52 bool wlan_hdd_nan_is_supported(struct hdd_context *hdd_ctx)
53 {
54 return cfg_nan_get_enable(hdd_ctx->psoc) &&
55 sme_is_feature_supported_by_fw(NAN);
56 }
57
58 /**
59 * __wlan_hdd_cfg80211_nan_ext_request() - cfg80211 NAN extended request handler
60 * @wiphy: driver's wiphy struct
61 * @wdev: wireless device to which the request is targeted
62 * @data: actual request data (netlink-encapsulated)
63 * @data_len: length of @data
64 *
65 * Handles NAN Extended vendor commands, sends the command to NAN component
66 * which parses and forwards the NAN requests.
67 *
68 * Return: 0 on success, negative errno on failure
69 */
__wlan_hdd_cfg80211_nan_ext_request(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)70 static int __wlan_hdd_cfg80211_nan_ext_request(struct wiphy *wiphy,
71 struct wireless_dev *wdev,
72 const void *data,
73 int data_len)
74 {
75 int ret_val;
76 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
77 struct net_device *dev = wdev->netdev;
78 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
79
80 hdd_enter_dev(wdev->netdev);
81
82 ret_val = wlan_hdd_validate_context(hdd_ctx);
83 if (ret_val)
84 return ret_val;
85
86 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
87 hdd_err_rl("Command not allowed in FTM mode");
88 return -EPERM;
89 }
90
91 if (!wlan_hdd_nan_is_supported(hdd_ctx)) {
92 hdd_debug_rl("NAN is not supported");
93 return -EPERM;
94 }
95
96 if (hdd_is_connection_in_progress(NULL, NULL)) {
97 hdd_err("Connection refused: conn in progress");
98 return -EAGAIN;
99 }
100
101 return os_if_process_nan_req(hdd_ctx->pdev, adapter->deflink->vdev_id,
102 data, data_len);
103 }
104
wlan_hdd_cfg80211_nan_ext_request(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)105 int wlan_hdd_cfg80211_nan_ext_request(struct wiphy *wiphy,
106 struct wireless_dev *wdev,
107 const void *data,
108 int data_len)
109
110 {
111 struct osif_psoc_sync *psoc_sync;
112 int errno;
113
114 errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
115 if (errno)
116 return errno;
117
118 errno = __wlan_hdd_cfg80211_nan_ext_request(wiphy, wdev,
119 data, data_len);
120
121 osif_psoc_sync_op_stop(psoc_sync);
122
123 return errno;
124 }
125
hdd_nan_concurrency_update(void)126 void hdd_nan_concurrency_update(void)
127 {
128 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
129 int ret;
130
131 hdd_enter();
132 ret = wlan_hdd_validate_context(hdd_ctx);
133 if (ret)
134 return;
135
136 wlan_twt_concurrency_update(hdd_ctx);
137 hdd_exit();
138 }
139
140 #ifdef WLAN_FEATURE_NAN
141 #ifdef WLAN_FEATURE_SR
hdd_nan_sr_concurrency_update(struct nan_event_params * nan_evt)142 void hdd_nan_sr_concurrency_update(struct nan_event_params *nan_evt)
143 {
144 struct wlan_objmgr_vdev *sta_vdev = NULL;
145 uint32_t conc_vdev_id = WLAN_INVALID_VDEV_ID;
146 uint8_t sr_ctrl;
147 bool is_sr_enabled = false;
148 uint32_t sta_vdev_id = WLAN_INVALID_VDEV_ID;
149 uint8_t sta_cnt, i;
150 uint32_t conn_count;
151 uint8_t non_srg_max_pd_offset = 0;
152 uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {
153 WLAN_INVALID_VDEV_ID};
154 struct nan_psoc_priv_obj *psoc_obj =
155 nan_get_psoc_priv_obj(nan_evt->psoc);
156 struct connection_info info[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
157 uint8_t mac_id;
158 QDF_STATUS status;
159
160 if (!psoc_obj) {
161 nan_err("nan psoc priv object is NULL");
162 return;
163 }
164 conn_count = policy_mgr_get_connection_info(nan_evt->psoc, info);
165 if (!conn_count)
166 return;
167 sta_cnt = policy_mgr_get_mode_specific_conn_info(nan_evt->psoc, NULL,
168 vdev_id_list,
169 PM_STA_MODE);
170 /*
171 * Get all active sta vdevs. STA + STA SR concurrency is not supported
172 * so break whenever a first sta with SR enabled is found.
173 */
174 for (i = 0; i < sta_cnt; i++) {
175 if (vdev_id_list[i] != WLAN_INVALID_VDEV_ID) {
176 sta_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
177 nan_evt->psoc,
178 vdev_id_list[i],
179 WLAN_OSIF_ID);
180 if (!sta_vdev) {
181 nan_err("sta vdev invalid for vdev id %d",
182 vdev_id_list[i]);
183 continue;
184 }
185 ucfg_spatial_reuse_get_sr_config(
186 sta_vdev, &sr_ctrl,
187 &non_srg_max_pd_offset, &is_sr_enabled);
188 if (is_sr_enabled) {
189 sta_vdev_id = vdev_id_list[i];
190 break;
191 }
192 wlan_objmgr_vdev_release_ref(sta_vdev, WLAN_OSIF_ID);
193 }
194 }
195 if (sta_cnt && sta_vdev &&
196 (!(sr_ctrl & NON_SRG_PD_SR_DISALLOWED) ||
197 (sr_ctrl & SRG_INFO_PRESENT)) &&
198 is_sr_enabled) {
199 if (nan_evt->evt_type == nan_event_id_enable_rsp) {
200 wlan_vdev_mlme_set_sr_disable_due_conc(
201 sta_vdev, true);
202 wlan_spatial_reuse_osif_event(
203 sta_vdev, SR_OPERATION_SUSPEND,
204 SR_REASON_CODE_CONCURRENCY);
205 }
206 if (nan_evt->evt_type == nan_event_id_disable_ind) {
207 if (conn_count > 2) {
208 status =
209 policy_mgr_get_mac_id_by_session_id(
210 nan_evt->psoc, sta_vdev_id,
211 &mac_id);
212 if (QDF_IS_STATUS_ERROR(status)) {
213 hdd_err("get mac id failed");
214 goto exit;
215 }
216 conc_vdev_id =
217 policy_mgr_get_conc_vdev_on_same_mac(
218 nan_evt->psoc, sta_vdev_id,
219 mac_id);
220 /*
221 * Don't enable SR, if concurrent vdev is not
222 * NAN and SR concurrency on same mac is not
223 * allowed.
224 */
225 if (conc_vdev_id != WLAN_INVALID_VDEV_ID &&
226 !policy_mgr_sr_same_mac_conc_enabled(
227 nan_evt->psoc)) {
228 hdd_debug("don't enable SR in SCC/MCC");
229 goto exit;
230 }
231 }
232 wlan_vdev_mlme_set_sr_disable_due_conc(sta_vdev, false);
233 wlan_spatial_reuse_osif_event(
234 sta_vdev, SR_OPERATION_RESUME,
235 SR_REASON_CODE_CONCURRENCY);
236 }
237 }
238 exit:
239 if (sta_vdev && is_sr_enabled)
240 wlan_objmgr_vdev_release_ref(sta_vdev, WLAN_OSIF_ID);
241 }
242 #endif
243 #endif
244