1 /*
2  * Copyright (c) 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 any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  * DOC:  wlan_hdd_mdns_offload.c
20  *
21  * WLAN Host Device Driver MDNS offload interface implementation.
22  */
23 
24 /* Include Files */
25 
26 #include <osif_vdev_sync.h>
27 #include "os_if_fwol.h"
28 #include "wlan_hdd_mdns_offload.h"
29 #include "wlan_hdd_main.h"
30 
31 #define MDNS_ENABLE \
32 	QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ENABLE
33 #define MDNS_TABLE \
34 	QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_TABLE
35 #define MDNS_ENTRY \
36 	QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ENTRY
37 #define MDNS_FQDN \
38 	QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_FQDN
39 #define MDNS_RESOURCE_RECORDS_COUNT \
40 	QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ANSWER_RESOURCE_RECORDS_COUNT
41 #define MDNS_ANSWER_PAYLOAD \
42 	QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ANSWER_PAYLOAD
43 
44 const struct nla_policy wlan_hdd_set_mdns_offload_policy[
45 			QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX + 1] = {
46 	[MDNS_ENABLE] = {.type = NLA_FLAG},
47 	[MDNS_TABLE] = {.type = NLA_NESTED},
48 	[MDNS_ENTRY] = {.type = NLA_NESTED},
49 	[MDNS_FQDN] = {.type = NLA_STRING, .len = MAX_FQDN_LEN - 1 },
50 	[MDNS_RESOURCE_RECORDS_COUNT] = {.type = NLA_U16},
51 	[MDNS_ANSWER_PAYLOAD] = {.type = NLA_BINARY, .len = MAX_MDNS_RESP_LEN },
52 
53 };
54 
hdd_extract_mdns_attr(struct nlattr * tb[],struct mdns_config_info * mdns_info)55 static int hdd_extract_mdns_attr(struct nlattr *tb[],
56 				 struct mdns_config_info *mdns_info)
57 {
58 	int len, count;
59 
60 	/* Configure mDNS FQDN*/
61 
62 	if (!tb[MDNS_FQDN]) {
63 		hdd_err_rl("mDNS_FQDN attr failed");
64 		return -EINVAL;
65 	}
66 
67 	len = nla_len(tb[MDNS_FQDN]);
68 	mdns_info->fqdn_len = len;
69 	mdns_info->fqdn_type = MDNS_FQDN_TYPE_GENERAL;
70 	wlan_cfg80211_nla_strscpy(mdns_info->fqdn_data, tb[MDNS_FQDN],
71 				  sizeof(mdns_info->fqdn_data));
72 
73 	/* Configure mDNS Answer Payload*/
74 
75 	if (!tb[MDNS_RESOURCE_RECORDS_COUNT]) {
76 		hdd_err_rl("mDNS_RR count attr failed");
77 		return -EINVAL;
78 	}
79 
80 	count = nla_get_u16(tb[MDNS_RESOURCE_RECORDS_COUNT]);
81 	mdns_info->resource_record_count = count;
82 
83 	if (!tb[MDNS_ANSWER_PAYLOAD]) {
84 		hdd_err_rl("mDNS_Response attr failed");
85 		return -EINVAL;
86 	}
87 
88 	len = nla_len(tb[MDNS_ANSWER_PAYLOAD]);
89 	mdns_info->answer_payload_len = len;
90 	nla_memcpy(mdns_info->answer_payload_data,
91 		   nla_data(tb[MDNS_ANSWER_PAYLOAD]),
92 		   sizeof(mdns_info->answer_payload_data));
93 
94 	return 0;
95 }
96 
97 /**
98  * __wlan_hdd_cfg80211_set_mdns_offload() - mDNS Offload configuration
99  * @wiphy: wiphy device pointer
100  * @wdev: wireless device pointer
101  * @data: Vendor command data buffer
102  * @data_len: Buffer length
103  *
104  * Handles QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX.
105  *
106  * Return: Error code.
107  */
108 static int
__wlan_hdd_cfg80211_set_mdns_offload(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)109 __wlan_hdd_cfg80211_set_mdns_offload(struct wiphy *wiphy,
110 				     struct wireless_dev *wdev,
111 				     const void *data,
112 				     int data_len)
113 {
114 	struct net_device *dev = wdev->netdev;
115 	struct hdd_context *hdd_ctx  = wiphy_priv(wiphy);
116 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
117 	struct nlattr *curr_attr;
118 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX + 1];
119 	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX + 1];
120 	struct mdns_config_info *mdns_info;
121 	bool is_mdns_enable;
122 	int errno, rem;
123 
124 	hdd_enter_dev(dev);
125 
126 	errno = wlan_hdd_validate_context(hdd_ctx);
127 	if (errno)
128 		return errno;
129 
130 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
131 		hdd_err_rl("Command not allowed in FTM mode");
132 		return -EINVAL;
133 	}
134 
135 	if (!(adapter->device_mode == QDF_STA_MODE ||
136 	      adapter->device_mode == QDF_P2P_CLIENT_MODE)) {
137 		hdd_err_rl("mDNS is only supported in STA or P2P CLI modes!");
138 		return -ENOTSUPP;
139 	}
140 	if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX,
141 				    data, data_len,
142 				    wlan_hdd_set_mdns_offload_policy)) {
143 		hdd_err_rl("invalid attr");
144 		return -EINVAL;
145 	}
146 
147 	if (!tb[MDNS_ENABLE]) {
148 		os_if_fwol_disable_mdns_offload(hdd_ctx->psoc);
149 		hdd_debug_rl("MDNS offload is disabled");
150 		return 0;
151 	}
152 
153 	is_mdns_enable = nla_get_flag(tb[MDNS_ENABLE]);
154 
155 	if (is_mdns_enable && !tb[MDNS_TABLE]) {
156 		hdd_err_rl("Invalid mDNS table of records");
157 		return -EINVAL;
158 	}
159 
160 	mdns_info = qdf_mem_malloc(sizeof(*mdns_info));
161 	if (!mdns_info)
162 		return -ENOMEM;
163 
164 	mdns_info->enable = is_mdns_enable;
165 	mdns_info->vdev_id = adapter->deflink->vdev_id;
166 
167 	nla_for_each_nested(curr_attr, tb[MDNS_TABLE], rem) {
168 		if (wlan_cfg80211_nla_parse(tb2,
169 					QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX,
170 					nla_data(curr_attr),
171 					nla_len(curr_attr),
172 					wlan_hdd_set_mdns_offload_policy)) {
173 			hdd_err_rl("Failed to parse mDNS table of records");
174 			errno = -EINVAL;
175 			goto out;
176 		}
177 
178 		errno = hdd_extract_mdns_attr(tb2, mdns_info);
179 		if (errno) {
180 			hdd_err_rl("Failed to extract MDNS nested attrs");
181 			goto out;
182 		}
183 	}
184 
185 	os_if_fwol_enable_mdns_offload(hdd_ctx->psoc, mdns_info);
186 
187 out:
188 	qdf_mem_free(mdns_info);
189 	hdd_exit();
190 
191 	return errno;
192 }
193 
194 /**
195  * wlan_hdd_cfg80211_set_mdns_offload() - mDNS Offload configuration
196  * @wiphy: wiphy device pointer
197  * @wdev: wireless device pointer
198  * @data: Vendor command data buffer
199  * @data_len: Buffer length
200  *
201  * Handles QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX.
202  *
203  * Return: EOK or other error codes.
204  */
wlan_hdd_cfg80211_set_mdns_offload(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)205 int wlan_hdd_cfg80211_set_mdns_offload(struct wiphy *wiphy,
206 				       struct wireless_dev *wdev,
207 				       const void *data, int data_len)
208 {
209 	int errno;
210 	struct osif_vdev_sync *vdev_sync;
211 
212 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
213 	if (errno)
214 		return errno;
215 
216 	errno = __wlan_hdd_cfg80211_set_mdns_offload(wiphy, wdev,
217 						     data, data_len);
218 
219 	osif_vdev_sync_op_stop(vdev_sync);
220 
221 	return errno;
222 }
223