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