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