1 /* 2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-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_rssi_monitor.c 22 * 23 * WLAN rssi monitoring functions 24 * 25 */ 26 27 #include "osif_sync.h" 28 #include <wlan_hdd_includes.h> 29 #include <linux/netdevice.h> 30 #include <linux/skbuff.h> 31 #include <linux/etherdevice.h> 32 #include <linux/if_ether.h> 33 #include <wlan_hdd_ext_scan.h> 34 #include <wlan_hdd_rssi_monitor.h> 35 36 /* 37 * define short names for the global vendor params 38 * used by __wlan_hdd_cfg80211_monitor_rssi() 39 */ 40 #define PARAM_MAX QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX 41 #define PARAM_REQUEST_ID QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID 42 #define PARAM_CONTROL QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL 43 #define PARAM_MIN_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI 44 #define PARAM_MAX_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI 45 46 const struct nla_policy moitor_rssi_policy[ 47 QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX + 1] = { 48 [QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID] = { .type = NLA_U32 }, 49 [QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL] = { .type = NLA_U32 }, 50 [QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI] = { .type = NLA_S8 }, 51 [QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI] = { .type = NLA_S8 }, 52 }; 53 54 /** 55 * __wlan_hdd_cfg80211_monitor_rssi() - monitor rssi 56 * @wiphy: Pointer to wireless phy 57 * @wdev: Pointer to wireless device 58 * @data: Pointer to data 59 * @data_len: Data length 60 * 61 * Return: 0 on success, negative errno on failure 62 */ 63 static int __wlan_hdd_cfg80211_monitor_rssi(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)64 __wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, 65 struct wireless_dev *wdev, 66 const void *data, 67 int data_len) 68 { 69 struct net_device *dev = wdev->netdev; 70 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 71 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 72 struct nlattr *tb[PARAM_MAX + 1]; 73 struct rssi_monitor_param req; 74 QDF_STATUS status; 75 int ret; 76 uint32_t control; 77 mac_handle_t mac_handle; 78 79 hdd_enter_dev(dev); 80 81 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 82 hdd_err("Command not allowed in FTM mode"); 83 return -EPERM; 84 } 85 86 if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) 87 return -EINVAL; 88 89 ret = wlan_hdd_validate_context(hdd_ctx); 90 if (ret) 91 return ret; 92 93 if (!hdd_cm_is_vdev_associated(adapter->deflink)) { 94 hdd_err("Not in Connected state!"); 95 return -ENOTSUPP; 96 } 97 98 if (wlan_cfg80211_nla_parse(tb, PARAM_MAX, data, data_len, 99 moitor_rssi_policy)) { 100 hdd_err("Invalid ATTR"); 101 return -EINVAL; 102 } 103 104 if (!tb[PARAM_REQUEST_ID]) { 105 hdd_err("attr request id failed"); 106 return -EINVAL; 107 } 108 109 if (!tb[PARAM_CONTROL]) { 110 hdd_err("attr control failed"); 111 return -EINVAL; 112 } 113 114 req.request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); 115 req.vdev_id = adapter->deflink->vdev_id; 116 control = nla_get_u32(tb[PARAM_CONTROL]); 117 118 if (control == QCA_WLAN_RSSI_MONITORING_START) { 119 req.control = true; 120 if (!tb[PARAM_MIN_RSSI]) { 121 hdd_err("attr min rssi failed"); 122 return -EINVAL; 123 } 124 125 if (!tb[PARAM_MAX_RSSI]) { 126 hdd_err("attr max rssi failed"); 127 return -EINVAL; 128 } 129 130 req.min_rssi = nla_get_s8(tb[PARAM_MIN_RSSI]); 131 req.max_rssi = nla_get_s8(tb[PARAM_MAX_RSSI]); 132 133 if (!(req.min_rssi < req.max_rssi)) { 134 hdd_warn("min_rssi: %d must be less than max_rssi: %d", 135 req.min_rssi, req.max_rssi); 136 return -EINVAL; 137 } 138 hdd_debug("Min_rssi: %d Max_rssi: %d", 139 req.min_rssi, req.max_rssi); 140 141 } else if (control == QCA_WLAN_RSSI_MONITORING_STOP) { 142 req.control = false; 143 } else { 144 hdd_err("Invalid control cmd: %d", control); 145 return -EINVAL; 146 } 147 hdd_debug("Request Id: %u vdev id: %d Control: %d", 148 req.request_id, req.vdev_id, req.control); 149 150 mac_handle = hdd_ctx->mac_handle; 151 status = sme_set_rssi_monitoring(mac_handle, &req); 152 if (!QDF_IS_STATUS_SUCCESS(status)) { 153 hdd_err("sme_set_rssi_monitoring failed(err=%d)", status); 154 return -EINVAL; 155 } 156 157 return 0; 158 } 159 160 /* 161 * done with short names for the global vendor params 162 * used by __wlan_hdd_cfg80211_monitor_rssi() 163 */ 164 #undef PARAM_MAX 165 #undef PARAM_CONTROL 166 #undef PARAM_REQUEST_ID 167 #undef PARAM_MAX_RSSI 168 #undef PARAM_MIN_RSSI 169 170 int wlan_hdd_cfg80211_monitor_rssi(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)171 wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev, 172 const void *data, int data_len) 173 { 174 struct osif_vdev_sync *vdev_sync; 175 int errno; 176 177 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 178 if (errno) 179 return errno; 180 181 errno = __wlan_hdd_cfg80211_monitor_rssi(wiphy, wdev, data, data_len); 182 183 osif_vdev_sync_op_stop(vdev_sync); 184 185 return errno; 186 } 187 hdd_rssi_threshold_breached(hdd_handle_t hdd_handle,struct rssi_breach_event * data)188 void hdd_rssi_threshold_breached(hdd_handle_t hdd_handle, 189 struct rssi_breach_event *data) 190 { 191 struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); 192 struct sk_buff *skb; 193 enum qca_nl80211_vendor_subcmds_index index = 194 QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX; 195 196 hdd_enter(); 197 198 if (wlan_hdd_validate_context(hdd_ctx)) 199 return; 200 if (!data) { 201 hdd_err("data is null"); 202 return; 203 } 204 205 skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, 206 EXTSCAN_EVENT_BUF_SIZE + 207 NLMSG_HDRLEN, 208 index, GFP_KERNEL); 209 210 if (!skb) { 211 hdd_err("mem alloc failed"); 212 return; 213 } 214 215 hdd_debug("Req Id: %u Current rssi: %d", 216 data->request_id, data->curr_rssi); 217 hdd_debug("Current BSSID: "QDF_MAC_ADDR_FMT, 218 QDF_MAC_ADDR_REF(data->curr_bssid.bytes)); 219 220 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID, 221 data->request_id) || 222 nla_put(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID, 223 sizeof(data->curr_bssid), data->curr_bssid.bytes) || 224 nla_put_s8(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI, 225 data->curr_rssi)) { 226 hdd_err("nla put fail"); 227 goto fail; 228 } 229 230 wlan_cfg80211_vendor_event(skb, GFP_KERNEL); 231 return; 232 233 fail: 234 wlan_cfg80211_vendor_free_skb(skb); 235 } 236 237