xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/mlme/src/osif_cm_roam_rsp.c (revision 2888b71da71bce103343119fa1b31f4a0cee07c8)
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