1 /* 2 * Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: osif_cm_roam_rsp.c 20 * 21 * This file maintains definitaions of roam response apis. 22 */ 23 24 #include <linux/version.h> 25 #include <linux/nl80211.h> 26 #include <net/cfg80211.h> 27 #include <wlan_osif_priv.h> 28 #include "osif_cm_rsp.h" 29 #include <osif_cm_util.h> 30 #include <wlan_cfg80211.h> 31 #include <wlan_cfg80211_scan.h> 32 #ifdef CONN_MGR_ADV_FEATURE 33 #include "wlan_mlme_ucfg_api.h" 34 #endif 35 #include "wlan_crypto_global_api.h" 36 37 #ifdef CONN_MGR_ADV_FEATURE 38 #ifdef WLAN_FEATURE_FILS_SK 39 static inline void osif_update_fils_hlp_data(struct net_device *dev, 40 struct wlan_objmgr_vdev *vdev, 41 struct wlan_cm_connect_resp *rsp) 42 { 43 if (rsp->connect_ies.fils_ie && rsp->connect_ies.fils_ie->hlp_data_len) 44 osif_cm_set_hlp_data(dev, vdev, rsp); 45 } 46 #else 47 static inline void osif_update_fils_hlp_data(struct net_device *dev, 48 struct wlan_objmgr_vdev *vdev, 49 struct wlan_cm_connect_resp *rsp) 50 { 51 } 52 #endif 53 54 /** 55 * osif_roamed_ind() - send roamed indication to cfg80211 56 * @dev: network device 57 * @bss: cfg80211 roamed bss pointer 58 * @req_ie: IEs used in reassociation request 59 * @req_ie_len: Length of the @req_ie 60 * @resp_ie: IEs received in successful reassociation response 61 * @resp_ie_len: Length of @resp_ie 62 * 63 * Return: none 64 */ 65 #if defined CFG80211_ROAMED_API_UNIFIED || \ 66 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) 67 #ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT 68 static 69 void osif_copy_roamed_info(struct cfg80211_roam_info *info, 70 struct cfg80211_bss *bss) 71 { 72 info->links[0].bss = bss; 73 } 74 #else 75 static 76 void osif_copy_roamed_info(struct cfg80211_roam_info *info, 77 struct cfg80211_bss *bss) 78 { 79 info->bss = bss; 80 } 81 #endif 82 static void osif_roamed_ind(struct net_device *dev, struct cfg80211_bss *bss, 83 const uint8_t *req_ie, 84 size_t req_ie_len, const uint8_t *resp_ie, 85 size_t resp_ie_len) 86 { 87 struct cfg80211_roam_info info = {0}; 88 89 osif_copy_roamed_info(&info, bss); 90 info.req_ie = req_ie; 91 info.req_ie_len = req_ie_len; 92 info.resp_ie = resp_ie; 93 info.resp_ie_len = resp_ie_len; 94 cfg80211_roamed(dev, &info, qdf_mem_malloc_flags()); 95 } 96 #else 97 static inline void osif_roamed_ind(struct net_device *dev, 98 struct cfg80211_bss *bss, 99 const uint8_t *req_ie, size_t req_ie_len, 100 const uint8_t *resp_ie, 101 size_t resp_ie_len) 102 { 103 cfg80211_roamed_bss(dev, bss, req_ie, req_ie_len, resp_ie, resp_ie_len, 104 qdf_mem_malloc_flags()); 105 } 106 #endif 107 108 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 109 #ifdef WLAN_FEATURE_FILS_SK 110 /** 111 * wlan_hdd_add_fils_params_roam_auth_event() - Adds FILS params in roam auth 112 * @skb: SK buffer 113 * @roam_info: Roam info 114 * 115 * API adds fils params[pmk, pmkid, next sequence number] to roam auth event 116 * 117 * Return: zero on success, error code on failure 118 */ 119 static int 120 osif_add_fils_params_roam_auth_event(struct sk_buff *skb, 121 struct wlan_roam_sync_info *roam_info) 122 { 123 if (roam_info->pmk_len && 124 nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMK, 125 roam_info->pmk_len, roam_info->pmk)) { 126 osif_err("pmk send fail"); 127 return -EINVAL; 128 } 129 130 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID, 131 PMKID_LEN, roam_info->pmkid)) { 132 osif_err("pmkid send fail"); 133 return -EINVAL; 134 } 135 136 osif_debug("Update ERP Seq Num %d, Next ERP Seq Num %d", 137 roam_info->update_erp_next_seq_num, 138 roam_info->next_erp_seq_num); 139 if (roam_info->update_erp_next_seq_num && 140 nla_put_u16(skb, 141 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_FILS_ERP_NEXT_SEQ_NUM, 142 roam_info->next_erp_seq_num)) { 143 osif_err("ERP seq num send fail"); 144 return -EINVAL; 145 } 146 147 return 0; 148 } 149 #else 150 static inline int 151 osif_add_fils_params_roam_auth_event(struct sk_buff *skb, 152 struct wlan_roam_sync_info *roam_info) 153 { 154 return 0; 155 } 156 #endif 157 158 /** 159 * osif_get_roam_reason() - convert wmi roam reason to 160 * enum qca_roam_reason 161 * @roam_scan_trigger: wmi roam scan trigger ID 162 * 163 * Return: Meaningful qca_roam_reason from enum WMI_ROAM_TRIGGER_REASON_ID 164 */ 165 static enum qca_roam_reason osif_get_roam_reason(uint16_t roam_scan_trigger) 166 { 167 switch (roam_scan_trigger) { 168 case ROAM_TRIGGER_REASON_PER: 169 return QCA_ROAM_REASON_PER; 170 case ROAM_TRIGGER_REASON_BMISS: 171 return QCA_ROAM_REASON_BEACON_MISS; 172 case ROAM_TRIGGER_REASON_LOW_RSSI: 173 case ROAM_TRIGGER_REASON_BACKGROUND: 174 return QCA_ROAM_REASON_POOR_RSSI; 175 case ROAM_TRIGGER_REASON_HIGH_RSSI: 176 return QCA_ROAM_REASON_BETTER_RSSI; 177 case ROAM_TRIGGER_REASON_DENSE: 178 return QCA_ROAM_REASON_CONGESTION; 179 case ROAM_TRIGGER_REASON_FORCED: 180 return QCA_ROAM_REASON_USER_TRIGGER; 181 case ROAM_TRIGGER_REASON_BTM: 182 return QCA_ROAM_REASON_BTM; 183 case ROAM_TRIGGER_REASON_BSS_LOAD: 184 return QCA_ROAM_REASON_BSS_LOAD; 185 default: 186 return QCA_ROAM_REASON_UNKNOWN; 187 } 188 189 return QCA_ROAM_REASON_UNKNOWN; 190 } 191 192 /** 193 * osif_send_roam_auth_event() - API to send roam auth event response to kernel 194 * @vdev: vdev pointer 195 * @osif_priv: OS private structure of vdev 196 * @rsp: Connection manager response 197 * 198 * This is called when wlan driver needs to send the roaming and 199 * authorization information after roaming. 200 * 201 * The information that would be sent is the request RSN IE, response 202 * RSN IE and BSSID of the newly roamed AP. 203 * 204 * If the Authorized status is authenticated, then additional parameters 205 * like PTK's KCK and KEK and Replay Counter would also be passed to the 206 * supplicant. 207 * 208 * The supplicant upon receiving this event would ignore the legacy 209 * cfg80211_roamed call and use the entire information from this event. 210 * The cfg80211_roamed should still co-exist since the kernel will 211 * make use of the parameters even if the supplicant ignores it. 212 * 213 * 214 * Context: Any context. 215 * Return: int 216 */ 217 static int osif_send_roam_auth_event(struct wlan_objmgr_vdev *vdev, 218 struct vdev_osif_priv *osif_priv, 219 struct wlan_cm_connect_resp *rsp, 220 const uint8_t *req_ie, 221 size_t req_ie_len, const uint8_t *resp_ie, 222 size_t resp_ie_len) 223 { 224 struct wlan_objmgr_psoc *psoc; 225 uint32_t fils_params_len; 226 struct sk_buff *skb = NULL; 227 struct wlan_roam_sync_info *roaming_info; 228 int status; 229 int32_t akm; 230 bool roam_offload_enable; 231 232 psoc = wlan_vdev_get_psoc(vdev); 233 ucfg_mlme_get_roaming_offload(psoc, &roam_offload_enable); 234 235 if (!roam_offload_enable) 236 return 0; 237 238 roaming_info = rsp->roaming_info; 239 240 /* 241 * PMK is sent from FW in Roam Synch Event for FILS Roaming. 242 * In that case, add three more NL attributes.ie. PMK, PMKID 243 * and ERP next sequence number. Add corresponding lengths 244 * with 3 extra NL message headers for each of the 245 * aforementioned params. 246 */ 247 fils_params_len = roaming_info->pmk_len + PMKID_LEN + 248 sizeof(uint16_t) + (3 * NLMSG_HDRLEN); 249 250 skb = cfg80211_vendor_event_alloc(osif_priv->wdev->wiphy, 251 osif_priv->wdev, 252 ETH_ALEN + req_ie_len + 253 resp_ie_len + 254 sizeof(uint8_t) + REPLAY_CTR_LEN + 255 KCK_KEY_LEN + roaming_info->kek_len + 256 sizeof(uint16_t) + sizeof(uint8_t) + 257 (9 * NLMSG_HDRLEN) + fils_params_len, 258 QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX, 259 qdf_mem_malloc_flags()); 260 261 if (!skb) { 262 osif_err("cfg80211_vendor_event_alloc failed"); 263 return -1; 264 } 265 266 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID, 267 ETH_ALEN, rsp->bssid.bytes) || 268 nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE, 269 req_ie_len, req_ie) || 270 nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE, 271 resp_ie_len, resp_ie)) { 272 osif_err("nla put fail"); 273 goto nla_put_failure; 274 } 275 276 if (roaming_info->auth_status == ROAM_AUTH_STATUS_AUTHENTICATED) { 277 osif_debug("Include Auth Params TLV's"); 278 if (nla_put_u8(skb, 279 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, 280 true)) { 281 osif_err("nla put fail"); 282 goto nla_put_failure; 283 } 284 akm = wlan_crypto_get_param(vdev, 285 WLAN_CRYPTO_PARAM_KEY_MGMT); 286 /* if FT or CCKM connection: dont send replay counter */ 287 if (!QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X) && 288 !QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK) && 289 !QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE) && 290 !QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384) && 291 !QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM) && 292 nla_put(skb, 293 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR, 294 REPLAY_CTR_LEN, 295 roaming_info->replay_ctr)) { 296 osif_err("non FT/non CCKM connection"); 297 osif_err("failed to send replay counter"); 298 goto nla_put_failure; 299 } 300 if (roaming_info->kek_len > MAX_KEK_LENGTH || 301 nla_put(skb, 302 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK, 303 roaming_info->kck_len, roaming_info->kck) || 304 nla_put(skb, 305 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK, 306 roaming_info->kek_len, roaming_info->kek)) { 307 osif_err("nla put fail, kek_len %d", 308 roaming_info->kek_len); 309 goto nla_put_failure; 310 } 311 312 if (nla_put_u16(skb, 313 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REASON, 314 osif_get_roam_reason(roaming_info->roam_reason))) { 315 osif_err("roam reason send failure"); 316 goto nla_put_failure; 317 } 318 319 status = osif_add_fils_params_roam_auth_event(skb, 320 roaming_info); 321 if (status) 322 goto nla_put_failure; 323 /* 324 * Save the gtk rekey parameters in HDD STA context. They will 325 * be used next time when host enables GTK offload and goes 326 * into power save state. 327 */ 328 osif_cm_save_gtk(vdev, rsp); 329 osif_debug("roam_info_ptr->replay_ctr 0x%llx", 330 *((uint64_t *)roaming_info->replay_ctr)); 331 332 } else { 333 osif_debug("No Auth Params TLV's"); 334 if (nla_put_u8(skb, 335 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, 336 false)) { 337 osif_err("nla put fail"); 338 goto nla_put_failure; 339 } 340 } 341 342 osif_debug("Auth Status = %d Subnet Change Status = %d", 343 roaming_info->auth_status, 344 roaming_info->subnet_change_status); 345 /* 346 * Add subnet change status if subnet has changed 347 * 0 = unchanged 348 * 1 = changed 349 * 2 = unknown 350 */ 351 if (roaming_info->subnet_change_status) { 352 if (nla_put_u8(skb, 353 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS, 354 roaming_info->subnet_change_status)) { 355 osif_err("nla put fail"); 356 goto nla_put_failure; 357 } 358 } 359 360 cfg80211_vendor_event(skb, qdf_mem_malloc_flags()); 361 return 0; 362 363 nla_put_failure: 364 kfree_skb(skb); 365 return -1; 366 } 367 #else 368 static inline int 369 osif_send_roam_auth_event(struct wlan_objmgr_vdev *vdev, 370 struct vdev_osif_priv *osif_priv, 371 struct wlan_cm_connect_resp *rsp, 372 const uint8_t *req_ie, 373 size_t req_ie_len, const uint8_t *resp_ie, 374 size_t resp_ie_len) 375 { 376 return 0; 377 } 378 #endif 379 380 static void osif_cm_get_reassoc_req_ie_data(struct element_info *assoc_req, 381 size_t *ie_data_len, 382 const uint8_t **ie_data_ptr) 383 { 384 /* Validate IE and length */ 385 if (!assoc_req->len || !assoc_req->ptr || 386 assoc_req->len <= WLAN_REASSOC_REQ_IES_OFFSET) 387 return; 388 389 *ie_data_len = assoc_req->len - WLAN_REASSOC_REQ_IES_OFFSET; 390 *ie_data_ptr = assoc_req->ptr + WLAN_REASSOC_REQ_IES_OFFSET; 391 } 392 393 void osif_indicate_reassoc_results(struct wlan_objmgr_vdev *vdev, 394 struct vdev_osif_priv *osif_priv, 395 struct wlan_cm_connect_resp *rsp) 396 { 397 struct net_device *dev = osif_priv->wdev->netdev; 398 size_t req_len = 0; 399 const uint8_t *req_ie = NULL; 400 size_t rsp_len = 0; 401 const uint8_t *rsp_ie = NULL; 402 struct cfg80211_bss *bss; 403 struct ieee80211_channel *chan; 404 struct wlan_objmgr_psoc *psoc; 405 406 if (QDF_IS_STATUS_ERROR(rsp->connect_status)) 407 return; 408 409 psoc = wlan_vdev_get_psoc(vdev); 410 if (!psoc) 411 return; 412 413 chan = ieee80211_get_channel(osif_priv->wdev->wiphy, 414 rsp->freq); 415 bss = wlan_cfg80211_get_bss(osif_priv->wdev->wiphy, chan, 416 rsp->bssid.bytes, rsp->ssid.ssid, 417 rsp->ssid.length); 418 if (!bss) 419 osif_warn("not able to find bss"); 420 if (rsp->is_ft) 421 osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req, 422 &req_len, &req_ie); 423 else 424 osif_cm_get_reassoc_req_ie_data(&rsp->connect_ies.assoc_req, 425 &req_len, &req_ie); 426 osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp, 427 &rsp_len, &rsp_ie); 428 osif_roamed_ind(dev, bss, req_ie, req_len, rsp_ie, rsp_len); 429 osif_send_roam_auth_event(vdev, osif_priv, rsp, req_ie, req_len, rsp_ie, 430 rsp_len); 431 432 osif_update_fils_hlp_data(dev, vdev, rsp); 433 } 434 435 QDF_STATUS 436 osif_pmksa_candidate_notify(struct wlan_objmgr_vdev *vdev, 437 struct qdf_mac_addr *bssid, 438 int index, bool preauth) 439 { 440 struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev); 441 struct wireless_dev *wdev; 442 443 if (!osif_priv) { 444 osif_err("Invalid vdev osif priv"); 445 return QDF_STATUS_E_INVAL; 446 } 447 448 wdev = osif_priv->wdev; 449 if (!wdev) { 450 osif_err("wdev is null"); 451 return QDF_STATUS_E_INVAL; 452 } 453 454 osif_debug("is going to notify supplicant of:"); 455 osif_info(QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(bssid->bytes)); 456 457 cfg80211_pmksa_candidate_notify(wdev->netdev, index, 458 bssid->bytes, 459 preauth, qdf_mem_malloc_flags()); 460 return QDF_STATUS_SUCCESS; 461 } 462 #endif /* CONN_MGR_ADV_FEATURE */ 463