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