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