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