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