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