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