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