1 /*
2  * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 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: wlan_hdd_subnet_detect.c
22  *
23  * WLAN Host Device Driver subnet detect API implementation
24  */
25 
26 #include <linux/version.h>
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <net/cfg80211.h>
30 #include <ani_global.h>
31 #include "sme_api.h"
32 #include "osif_sync.h"
33 #include "wlan_hdd_main.h"
34 #include "wlan_hdd_subnet_detect.h"
35 #include <qca_vendor.h>
36 #include "wlan_dp_ucfg_api.h"
37 #include "wlan_hdd_object_manager.h"
38 
39 /*
40  * define short names for the global vendor params
41  * used by __wlan_hdd_cfg80211_set_gateway_params()
42  */
43 #define PARAM_MAC_ADDR QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_GW_MAC_ADDR
44 #define PARAM_IPV4_ADDR QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV4_ADDR
45 #define PARAM_IPV6_ADDR QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV6_ADDR
46 
47 const struct nla_policy subnet_detect_policy[
48 			QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX + 1] = {
49 		[QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_GW_MAC_ADDR] =
50 				VENDOR_NLA_POLICY_MAC_ADDR,
51 		[QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV4_ADDR] =
52 				VENDOR_NLA_POLICY_IPV4_ADDR,
53 		[QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV6_ADDR] =
54 				VENDOR_NLA_POLICY_IPV6_ADDR,
55 };
56 
57 /**
58  * __wlan_hdd_cfg80211_set_gateway_params() - set gateway params
59  * @wiphy: Pointer to wireless phy
60  * @wdev: Pointer to wireless device
61  * @data: Pointer to data
62  * @data_len: Data length
63  *
64  * Return: 0 on success, negative errno on failure
65  */
__wlan_hdd_cfg80211_set_gateway_params(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)66 static int __wlan_hdd_cfg80211_set_gateway_params(struct wiphy *wiphy,
67 		struct wireless_dev *wdev,
68 		const void *data,
69 		int data_len)
70 {
71 	struct net_device *dev = wdev->netdev;
72 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
73 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
74 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX + 1];
75 	struct gateway_update_req_param req = { 0 };
76 	int ret;
77 	QDF_STATUS status;
78 	bool subnet_detection_enabled;
79 	struct wlan_objmgr_vdev *vdev;
80 
81 	hdd_enter_dev(dev);
82 
83 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
84 		hdd_err("Command not allowed in FTM mode");
85 		return -EPERM;
86 	}
87 
88 	ret = wlan_hdd_validate_context(hdd_ctx);
89 	if (0 != ret)
90 		return ret;
91 
92 	/* user may have disabled the feature in INI */
93 	ucfg_mlme_is_subnet_detection_enabled(hdd_ctx->psoc,
94 					      &subnet_detection_enabled);
95 	if (!subnet_detection_enabled) {
96 		hdd_debug("LFR Subnet Detection disabled in INI");
97 		return -ENOTSUPP;
98 	}
99 
100 	/* The gateway parameters are only valid in the STA persona
101 	 * and only in the connected state.
102 	 */
103 	if (QDF_STA_MODE != adapter->device_mode) {
104 		hdd_debug("Received GW param update for non-STA mode adapter");
105 		return -ENOTSUPP;
106 	}
107 
108 	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
109 		hdd_debug("Received GW param update in disconnected state!");
110 		return -ENOTSUPP;
111 	}
112 
113 	/* Extract NL parameters
114 	 * mac_addr:  6 bytes
115 	 * ipv4 addr: 4 bytes
116 	 * ipv6 addr: 16 bytes
117 	 */
118 	if (wlan_cfg80211_nla_parse(tb,
119 				    QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX,
120 				    data, data_len, subnet_detect_policy)) {
121 		hdd_err("Invalid ATTR list");
122 		return -EINVAL;
123 	}
124 
125 	if (!tb[PARAM_MAC_ADDR]) {
126 		hdd_err("request mac addr failed");
127 		return -EINVAL;
128 	}
129 	nla_memcpy(req.gw_mac_addr.bytes, tb[PARAM_MAC_ADDR],
130 			QDF_MAC_ADDR_SIZE);
131 
132 	/* req ipv4_addr_type and ipv6_addr_type are initially false due
133 	 * to zeroing the struct
134 	 */
135 	if (tb[PARAM_IPV4_ADDR]) {
136 		nla_memcpy(req.ipv4_addr, tb[PARAM_IPV4_ADDR],
137 			QDF_IPV4_ADDR_SIZE);
138 		req.ipv4_addr_type = true;
139 	}
140 
141 	if (tb[PARAM_IPV6_ADDR]) {
142 		nla_memcpy(&req.ipv6_addr, tb[PARAM_IPV6_ADDR],
143 			QDF_IPV6_ADDR_SIZE);
144 		req.ipv6_addr_type = true;
145 	}
146 
147 	if (!req.ipv4_addr_type && !req.ipv6_addr_type) {
148 		hdd_err("invalid ipv4 or ipv6 gateway address");
149 		return -EINVAL;
150 	}
151 
152 	req.max_retries = 3;
153 	req.timeout = 100;   /* in milliseconds */
154 	req.vdev_id = adapter->deflink->vdev_id;
155 
156 	hdd_debug("Configuring gateway for session %d", req.vdev_id);
157 	hdd_debug("mac:"QDF_MAC_ADDR_FMT", ipv4:%pI4 (type %d), ipv6:%pI6c (type %d)",
158 		  QDF_MAC_ADDR_REF(req.gw_mac_addr.bytes),
159 		  req.ipv4_addr, req.ipv4_addr_type,
160 		  req.ipv6_addr, req.ipv6_addr_type);
161 
162 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID);
163 	if (vdev) {
164 		ucfg_dp_nud_set_gateway_addr(vdev, req.gw_mac_addr);
165 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
166 	}
167 
168 	status = sme_gateway_param_update(hdd_ctx->mac_handle, &req);
169 	if (!QDF_IS_STATUS_SUCCESS(status)) {
170 		hdd_err("sme_gateway_param_update failed(err=%d)", status);
171 		ret = -EINVAL;
172 	}
173 
174 	hdd_exit();
175 	return ret;
176 }
177 
178 /**
179  * wlan_hdd_cfg80211_set_gateway_params() - set gateway parameters
180  * @wiphy:    wiphy structure pointer
181  * @wdev:     Wireless device structure pointer
182  * @data:     Pointer to the data received
183  * @data_len: Length of @data
184  *
185  * The API is invoked by the user space to set the gateway parameters
186  * such as mac address and the IP address which is used for detecting
187  * the IP subnet change
188  *
189  * Return: 0 on success; errno on failure
190  */
wlan_hdd_cfg80211_set_gateway_params(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)191 int wlan_hdd_cfg80211_set_gateway_params(struct wiphy *wiphy,
192 		struct wireless_dev *wdev, const void *data, int data_len)
193 {
194 	int errno;
195 	struct osif_vdev_sync *vdev_sync;
196 
197 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
198 	if (errno)
199 		return errno;
200 
201 	errno = __wlan_hdd_cfg80211_set_gateway_params(wiphy, wdev,
202 						       data, data_len);
203 
204 	osif_vdev_sync_op_stop(vdev_sync);
205 
206 	return errno;
207 }
208 #undef PARAM_MAC_ADDR
209 #undef PARAM_IPV4_ADDR
210 #undef PARAM_IPV6_ADDR
211