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