1 /*
2 * Copyright (c) 2023 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 /**
20 * DOC: contains ll_lt_sap_definitions specific to the ll_lt_sap module
21 */
22
23 #include "wlan_hdd_ll_lt_sap.h"
24 #include "wlan_ll_sap_ucfg_api.h"
25 #include "osif_sync.h"
26 #include "wlan_hdd_cfg80211.h"
27 #include "os_if_ll_sap.h"
28
29 const struct nla_policy
30 wlan_hdd_ll_lt_sap_transport_switch_policy
31 [QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX + 1] = {
32 [QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE] = {
33 .type = NLA_U8},
34 [QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS] = {
35 .type = NLA_U8},
36 };
37
38 /**
39 * __wlan_hdd_cfg80211_ll_lt_sap_transport_switch() - Request to switch the
40 * transport
41 * @wiphy: pointer to wireless wiphy structure.
42 * @wdev: pointer to wireless_dev structure.
43 * @data: Pointer to the data to be passed via vendor interface
44 * @data_len:Length of the data to be passed
45 *
46 * Return: Return the Success or Failure code.
47 */
48 static int
__wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)49 __wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy,
50 struct wireless_dev *wdev,
51 const void *data,
52 int data_len)
53 {
54 struct net_device *dev = wdev->netdev;
55 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
56 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
57 struct wlan_objmgr_vdev *vdev;
58 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX + 1];
59 enum qca_wlan_audio_transport_switch_type transport_switch_type;
60 enum qca_wlan_audio_transport_switch_status transport_switch_status;
61 QDF_STATUS status;
62
63 hdd_enter_dev(dev);
64
65 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
66 hdd_err("Command not allowed in FTM mode");
67 return -EPERM;
68 }
69
70 if (wlan_hdd_validate_context(hdd_ctx))
71 return -EINVAL;
72
73 if (hdd_validate_adapter(adapter))
74 return -EINVAL;
75
76 if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
77 return -EINVAL;
78
79 if (!policy_mgr_is_vdev_ll_lt_sap(hdd_ctx->psoc,
80 adapter->deflink->vdev_id)) {
81 hdd_err("Command not allowed on vdev %d",
82 adapter->deflink->vdev_id);
83 return -EINVAL;
84 }
85
86 if (wlan_cfg80211_nla_parse(
87 tb, QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX,
88 data, data_len,
89 wlan_hdd_ll_lt_sap_transport_switch_policy)) {
90 hdd_err("vdev %d Invalid attribute", adapter->deflink->vdev_id);
91 return -EINVAL;
92 }
93
94 if (!tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE]) {
95 hdd_err("Vdev %d attr transport switch type failed",
96 adapter->deflink->vdev_id);
97 return -EINVAL;
98 }
99
100 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(hdd_ctx->psoc,
101 adapter->deflink->vdev_id,
102 WLAN_LL_SAP_ID);
103 if (!vdev) {
104 hdd_err("vdev %d not found", adapter->deflink->vdev_id);
105 return -EINVAL;
106 }
107
108 transport_switch_type = nla_get_u8(
109 tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE]);
110
111 if (!tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS]) {
112 status = osif_ll_lt_sap_request_for_audio_transport_switch(
113 vdev,
114 transport_switch_type);
115 wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID);
116 hdd_debug("Transport switch request type %d status %d vdev %d",
117 transport_switch_type, status,
118 adapter->deflink->vdev_id);
119 return qdf_status_to_os_return(status);
120 }
121
122 transport_switch_status = nla_get_u8(
123 tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS]);
124
125 /* Deliver the switch response */
126 status = osif_ll_lt_sap_deliver_audio_transport_switch_resp(
127 vdev,
128 transport_switch_type,
129 transport_switch_status);
130
131 wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID);
132
133 return qdf_status_to_os_return(status);
134 }
135
wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)136 int wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy,
137 struct wireless_dev *wdev,
138 const void *data,
139 int data_len)
140 {
141 int errno;
142 struct osif_vdev_sync *vdev_sync;
143
144 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
145 if (errno)
146 return errno;
147
148 errno = __wlan_hdd_cfg80211_ll_lt_sap_transport_switch(wiphy, wdev,
149 data, data_len);
150
151 osif_vdev_sync_op_stop(vdev_sync);
152
153 return errno;
154 }
155