1 /*
2 * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 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: defines driver functions interfacing with linux kernel
22 */
23
24 #include <qdf_util.h>
25 #include <wlan_objmgr_psoc_obj.h>
26 #include <wlan_objmgr_global_obj.h>
27 #include <wlan_objmgr_pdev_obj.h>
28 #include <wlan_objmgr_vdev_obj.h>
29 #include <wlan_objmgr_peer_obj.h>
30 #include <wlan_p2p_public_struct.h>
31 #include <wlan_p2p_ucfg_api.h>
32 #include <wlan_policy_mgr_api.h>
33 #include <wlan_utility.h>
34 #include <wlan_osif_priv.h>
35 #include "wlan_cfg80211.h"
36 #include "wlan_cfg80211_p2p.h"
37 #include "wlan_mlo_mgr_sta.h"
38
39 #define MAX_NO_OF_2_4_CHANNELS 14
40 #define MAX_OFFCHAN_TIME_FOR_DNBS 150
41
42 /**
43 * wlan_p2p_rx_callback() - Callback for rx mgmt frame
44 * @user_data: pointer to soc object
45 * @rx_frame: RX mgmt frame information
46 *
47 * This callback will be used to rx frames in os interface.
48 *
49 * Return: None
50 */
wlan_p2p_rx_callback(void * user_data,struct p2p_rx_mgmt_frame * rx_frame)51 static void wlan_p2p_rx_callback(void *user_data,
52 struct p2p_rx_mgmt_frame *rx_frame)
53 {
54 struct wlan_objmgr_psoc *psoc;
55 struct wlan_objmgr_vdev *vdev, *assoc_vdev;
56 struct vdev_osif_priv *osif_priv;
57 struct wireless_dev *wdev;
58 enum QDF_OPMODE opmode;
59
60 psoc = user_data;
61 if (!psoc) {
62 osif_err("psoc is null");
63 return;
64 }
65
66 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
67 rx_frame->vdev_id, WLAN_P2P_ID);
68 if (!vdev) {
69 osif_err("vdev is null");
70 return;
71 }
72
73 assoc_vdev = vdev;
74 opmode = wlan_vdev_mlme_get_opmode(assoc_vdev);
75
76 if (opmode == QDF_STA_MODE && wlan_vdev_mlme_is_mlo_vdev(vdev)) {
77 assoc_vdev = ucfg_mlo_get_assoc_link_vdev(vdev);
78 if (!assoc_vdev) {
79 osif_err("Assoc vdev is NULL");
80 goto fail;
81 }
82 }
83
84 osif_priv = wlan_vdev_get_ospriv(assoc_vdev);
85 if (!osif_priv) {
86 osif_err("osif_priv is null");
87 goto fail;
88 }
89
90 wdev = osif_priv->wdev;
91 if (!wdev) {
92 osif_err("wdev is null");
93 goto fail;
94 }
95
96 osif_debug("Indicate frame over nl80211, idx:%d",
97 wdev->netdev->ifindex);
98
99 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
100 cfg80211_rx_mgmt(wdev, rx_frame->rx_freq, rx_frame->rx_rssi * 100,
101 rx_frame->buf, rx_frame->frame_len,
102 NL80211_RXMGMT_FLAG_ANSWERED);
103 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
104 cfg80211_rx_mgmt(wdev, rx_frame->rx_freq, rx_frame->rx_rssi * 100,
105 rx_frame->buf, rx_frame->frame_len,
106 NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC);
107 #else
108 cfg80211_rx_mgmt(wdev, rx_frame->rx_freq, rx_frame->rx_rssi * 100,
109 rx_frame->buf, rx_frame->frame_len, GFP_ATOMIC);
110 #endif /* LINUX_VERSION_CODE */
111 fail:
112 wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
113 }
114
115 /**
116 * wlan_p2p_action_tx_cnf_callback() - Callback for tx confirmation
117 * @user_data: pointer to soc object
118 * @tx_cnf: tx confirmation information
119 *
120 * This callback will be used to give tx mgmt frame confirmation to
121 * os interface.
122 *
123 * Return: None
124 */
wlan_p2p_action_tx_cnf_callback(void * user_data,struct p2p_tx_cnf * tx_cnf)125 static void wlan_p2p_action_tx_cnf_callback(void *user_data,
126 struct p2p_tx_cnf *tx_cnf)
127 {
128 struct wlan_objmgr_psoc *psoc;
129 struct wlan_objmgr_vdev *vdev;
130 struct vdev_osif_priv *osif_priv;
131 struct wireless_dev *wdev;
132 bool is_success;
133
134 psoc = user_data;
135 if (!psoc) {
136 osif_err("psoc is null");
137 return;
138 }
139
140 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
141 tx_cnf->vdev_id, WLAN_P2P_ID);
142 if (!vdev) {
143 osif_err("vdev is null");
144 return;
145 }
146
147 osif_priv = wlan_vdev_get_ospriv(vdev);
148 if (!osif_priv) {
149 osif_err("osif_priv is null");
150 goto fail;
151 }
152
153 wdev = osif_priv->wdev;
154 if (!wdev) {
155 osif_err("wireless dev is null");
156 goto fail;
157 }
158
159 is_success = tx_cnf->status ? false : true;
160 cfg80211_mgmt_tx_status(
161 wdev,
162 tx_cnf->action_cookie,
163 tx_cnf->buf, tx_cnf->buf_len,
164 is_success, GFP_KERNEL);
165 fail:
166 wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
167 }
168
169 #ifdef FEATURE_P2P_LISTEN_OFFLOAD
170 /**
171 * wlan_p2p_lo_event_callback() - Callback for listen offload event
172 * @user_data: pointer to soc object
173 * @p2p_lo_event: listen offload event information
174 *
175 * This callback will be used to give listen offload event to os interface.
176 *
177 * Return: None
178 */
wlan_p2p_lo_event_callback(void * user_data,struct p2p_lo_event * p2p_lo_event)179 static void wlan_p2p_lo_event_callback(void *user_data,
180 struct p2p_lo_event *p2p_lo_event)
181 {
182 struct wlan_objmgr_psoc *psoc;
183 struct wlan_objmgr_vdev *vdev;
184 struct vdev_osif_priv *osif_priv;
185 struct wireless_dev *wdev;
186 struct sk_buff *vendor_event;
187 enum qca_nl80211_vendor_subcmds_index index =
188 QCA_NL80211_VENDOR_SUBCMD_P2P_LO_EVENT_INDEX;
189
190 osif_debug("user data:%pK, vdev id:%d, reason code:%d",
191 user_data, p2p_lo_event->vdev_id,
192 p2p_lo_event->reason_code);
193
194 psoc = user_data;
195 if (!psoc) {
196 osif_err("psoc is null");
197 return;
198 }
199
200 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
201 p2p_lo_event->vdev_id, WLAN_P2P_ID);
202 if (!vdev) {
203 osif_err("vdev is null");
204 return;
205 }
206
207 osif_priv = wlan_vdev_get_ospriv(vdev);
208 if (!osif_priv) {
209 osif_err("osif_priv is null");
210 goto fail;
211 }
212
213 wdev = osif_priv->wdev;
214 if (!wdev) {
215 osif_err("wireless dev is null");
216 goto fail;
217 }
218
219 vendor_event = wlan_cfg80211_vendor_event_alloc(wdev->wiphy, NULL,
220 sizeof(uint32_t) +
221 NLMSG_HDRLEN,
222 index, GFP_KERNEL);
223 if (!vendor_event) {
224 osif_err("wlan_cfg80211_vendor_event_alloc failed");
225 goto fail;
226 }
227
228 if (nla_put_u32(vendor_event,
229 QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON,
230 p2p_lo_event->reason_code)) {
231 osif_err("nla put failed");
232 wlan_cfg80211_vendor_free_skb(vendor_event);
233 goto fail;
234 }
235
236 wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
237
238 fail:
239 wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
240 }
241
wlan_p2p_init_lo_event(struct p2p_start_param * start_param,struct wlan_objmgr_psoc * psoc)242 static inline void wlan_p2p_init_lo_event(struct p2p_start_param *start_param,
243 struct wlan_objmgr_psoc *psoc)
244 {
245 start_param->lo_event_cb = wlan_p2p_lo_event_callback;
246 start_param->lo_event_cb_data = psoc;
247 }
248 #else
wlan_p2p_init_lo_event(struct p2p_start_param * start_param,struct wlan_objmgr_psoc * psoc)249 static inline void wlan_p2p_init_lo_event(struct p2p_start_param *start_param,
250 struct wlan_objmgr_psoc *psoc)
251 {
252 }
253 #endif /* FEATURE_P2P_LISTEN_OFFLOAD */
254 /**
255 * wlan_p2p_event_callback() - Callback for P2P event
256 * @user_data: pointer to soc object
257 * @p2p_event: p2p event information
258 *
259 * This callback will be used to give p2p event to os interface.
260 *
261 * Return: None
262 */
wlan_p2p_event_callback(void * user_data,struct p2p_event * p2p_event)263 static void wlan_p2p_event_callback(void *user_data,
264 struct p2p_event *p2p_event)
265 {
266 struct wlan_objmgr_psoc *psoc;
267 struct wlan_objmgr_vdev *vdev;
268 struct ieee80211_channel *chan;
269 struct vdev_osif_priv *osif_priv;
270 struct wireless_dev *wdev;
271 struct wlan_objmgr_pdev *pdev;
272
273 osif_debug("user data:%pK, vdev id:%d, event type:%d",
274 user_data, p2p_event->vdev_id, p2p_event->roc_event);
275
276 psoc = user_data;
277 if (!psoc) {
278 osif_err("psoc is null");
279 return;
280 }
281
282 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
283 p2p_event->vdev_id, WLAN_P2P_ID);
284 if (!vdev) {
285 osif_err("vdev is null");
286 return;
287 }
288
289 osif_priv = wlan_vdev_get_ospriv(vdev);
290 if (!osif_priv) {
291 osif_err("osif_priv is null");
292 goto fail;
293 }
294
295 wdev = osif_priv->wdev;
296 if (!wdev) {
297 osif_err("wireless dev is null");
298 goto fail;
299 }
300
301 pdev = wlan_vdev_get_pdev(vdev);
302 chan = ieee80211_get_channel(wdev->wiphy, p2p_event->chan_freq);
303 if (!chan) {
304 osif_err("channel conversion failed");
305 goto fail;
306 }
307
308 if (p2p_event->roc_event == ROC_EVENT_READY_ON_CHAN) {
309 cfg80211_ready_on_channel(wdev,
310 p2p_event->cookie, chan,
311 p2p_event->duration, GFP_KERNEL);
312 } else if (p2p_event->roc_event == ROC_EVENT_COMPLETED) {
313 cfg80211_remain_on_channel_expired(wdev,
314 p2p_event->cookie, chan, GFP_KERNEL);
315 } else {
316 osif_err("Invalid p2p event");
317 }
318
319 fail:
320 wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
321 }
322
p2p_psoc_enable(struct wlan_objmgr_psoc * psoc)323 QDF_STATUS p2p_psoc_enable(struct wlan_objmgr_psoc *psoc)
324 {
325 struct p2p_start_param start_param;
326
327 if (!psoc) {
328 osif_err("psoc null");
329 return QDF_STATUS_E_INVAL;
330 }
331
332 start_param.rx_cb = wlan_p2p_rx_callback;
333 start_param.rx_cb_data = psoc;
334 start_param.event_cb = wlan_p2p_event_callback;
335 start_param.event_cb_data = psoc;
336 start_param.tx_cnf_cb = wlan_p2p_action_tx_cnf_callback;
337 start_param.tx_cnf_cb_data = psoc;
338 wlan_p2p_init_lo_event(&start_param, psoc);
339
340 return ucfg_p2p_psoc_start(psoc, &start_param);
341 }
342
p2p_psoc_disable(struct wlan_objmgr_psoc * psoc)343 QDF_STATUS p2p_psoc_disable(struct wlan_objmgr_psoc *psoc)
344 {
345 if (!psoc) {
346 osif_err("psoc null");
347 return QDF_STATUS_E_INVAL;
348 }
349
350 return ucfg_p2p_psoc_stop(psoc);
351 }
352
wlan_cfg80211_roc(struct wlan_objmgr_vdev * vdev,struct ieee80211_channel * chan,uint32_t duration,uint64_t * cookie)353 int wlan_cfg80211_roc(struct wlan_objmgr_vdev *vdev,
354 struct ieee80211_channel *chan, uint32_t duration,
355 uint64_t *cookie)
356 {
357 struct p2p_roc_req roc_req = {0};
358 struct wlan_objmgr_psoc *psoc;
359 uint8_t vdev_id;
360 bool ok;
361 int ret;
362 struct wlan_objmgr_pdev *pdev = NULL;
363
364 if (!vdev) {
365 osif_err("invalid vdev object");
366 return -EINVAL;
367 }
368
369 if (!chan) {
370 osif_err("invalid channel");
371 return -EINVAL;
372 }
373
374 psoc = wlan_vdev_get_psoc(vdev);
375 vdev_id = wlan_vdev_get_id(vdev);
376 pdev = wlan_vdev_get_pdev(vdev);
377
378 if (!psoc) {
379 osif_err("psoc handle is NULL");
380 return -EINVAL;
381 }
382
383 roc_req.chan_freq = chan->center_freq;
384 roc_req.duration = duration;
385 roc_req.vdev_id = (uint32_t)vdev_id;
386
387 ret = policy_mgr_is_chan_ok_for_dnbs(psoc, chan->center_freq, &ok);
388 if (QDF_IS_STATUS_ERROR(ret)) {
389 osif_err("policy_mgr_is_chan_ok_for_dnbs():ret:%d",
390 ret);
391 return -EINVAL;
392 }
393
394 if (!ok) {
395 osif_err("channel%d not OK for DNBS", roc_req.chan_freq);
396 return -EINVAL;
397 }
398
399 return qdf_status_to_os_return(
400 ucfg_p2p_roc_req(psoc, &roc_req, cookie));
401 }
402
wlan_cfg80211_cancel_roc(struct wlan_objmgr_vdev * vdev,uint64_t cookie)403 int wlan_cfg80211_cancel_roc(struct wlan_objmgr_vdev *vdev,
404 uint64_t cookie)
405 {
406 struct wlan_objmgr_psoc *psoc;
407
408 if (!vdev) {
409 osif_err("invalid vdev object");
410 return -EINVAL;
411 }
412
413 psoc = wlan_vdev_get_psoc(vdev);
414 if (!psoc) {
415 osif_err("psoc handle is NULL");
416 return -EINVAL;
417 }
418
419 return qdf_status_to_os_return(
420 ucfg_p2p_roc_cancel_req(psoc, cookie));
421 }
422
wlan_cfg80211_mgmt_tx(struct wlan_objmgr_vdev * vdev,struct ieee80211_channel * chan,bool offchan,unsigned int wait,const uint8_t * buf,uint32_t len,bool no_cck,bool dont_wait_for_ack,uint64_t * cookie)423 int wlan_cfg80211_mgmt_tx(struct wlan_objmgr_vdev *vdev,
424 struct ieee80211_channel *chan, bool offchan,
425 unsigned int wait,
426 const uint8_t *buf, uint32_t len, bool no_cck,
427 bool dont_wait_for_ack, uint64_t *cookie)
428 {
429 struct p2p_mgmt_tx mgmt_tx = {0};
430 struct wlan_objmgr_psoc *psoc;
431 uint8_t vdev_id;
432 qdf_freq_t chan_freq = 0;
433 struct wlan_objmgr_pdev *pdev = NULL;
434 if (!vdev) {
435 osif_err("invalid vdev object");
436 return -EINVAL;
437 }
438
439 pdev = wlan_vdev_get_pdev(vdev);
440 if (chan)
441 chan_freq = chan->center_freq;
442 else
443 osif_debug("NULL chan, set channel to 0");
444
445 psoc = wlan_vdev_get_psoc(vdev);
446 vdev_id = wlan_vdev_get_id(vdev);
447 if (!psoc) {
448 osif_err("psoc handle is NULL");
449 return -EINVAL;
450 }
451
452 /**
453 * When offchannel time is more than MAX_OFFCHAN_TIME_FOR_DNBS,
454 * allow offchannel only if Do_Not_Switch_Channel is not set.
455 */
456 if (wait > MAX_OFFCHAN_TIME_FOR_DNBS) {
457 int ret;
458 bool ok;
459
460 ret = policy_mgr_is_chan_ok_for_dnbs(psoc, chan_freq, &ok);
461 if (QDF_IS_STATUS_ERROR(ret)) {
462 osif_err("policy_mgr_is_chan_ok_for_dnbs():ret:%d",
463 ret);
464 return -EINVAL;
465 }
466 if (!ok) {
467 osif_err("Rejecting mgmt_tx for channel:%d as DNSC is set",
468 chan_freq);
469 return -EINVAL;
470 }
471 }
472
473 mgmt_tx.vdev_id = (uint32_t)vdev_id;
474 mgmt_tx.chan_freq = chan_freq;
475 mgmt_tx.wait = wait;
476 mgmt_tx.len = len;
477 mgmt_tx.no_cck = (uint32_t)no_cck;
478 mgmt_tx.dont_wait_for_ack = (uint32_t)dont_wait_for_ack;
479 mgmt_tx.off_chan = (uint32_t)offchan;
480 mgmt_tx.buf = buf;
481
482 return qdf_status_to_os_return(
483 ucfg_p2p_mgmt_tx(psoc, &mgmt_tx, cookie, pdev));
484 }
485
wlan_cfg80211_mgmt_tx_cancel(struct wlan_objmgr_vdev * vdev,uint64_t cookie)486 int wlan_cfg80211_mgmt_tx_cancel(struct wlan_objmgr_vdev *vdev,
487 uint64_t cookie)
488 {
489 struct wlan_objmgr_psoc *psoc;
490
491 if (!vdev) {
492 osif_err("invalid vdev object");
493 return -EINVAL;
494 }
495
496 psoc = wlan_vdev_get_psoc(vdev);
497 if (!psoc) {
498 osif_err("psoc handle is NULL");
499 return -EINVAL;
500 }
501
502 return qdf_status_to_os_return(
503 ucfg_p2p_mgmt_tx_cancel(psoc, vdev, cookie));
504 }
505