xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/mlme/src/osif_cm_util.c (revision 97f44cd39e4ff816eaa1710279d28cf6b9e65ad9)
1 /*
2  * Copyright (c) 2012-2015, 2020 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_util.c
19  *
20  * This file maintains definitaions of connect, disconnect, roam
21  * common apis.
22  */
23 #include <include/wlan_mlme_cmn.h>
24 #include "osif_cm_util.h"
25 #include "wlan_osif_priv.h"
26 #include "wlan_cfg80211.h"
27 #include "osif_cm_rsp.h"
28 #include "wlan_cfg80211_scan.h"
29 
30 enum qca_sta_connect_fail_reason_codes
31 osif_cm_mac_to_qca_connect_fail_reason(enum wlan_status_code internal_reason)
32 {
33 	enum qca_sta_connect_fail_reason_codes reason = 0;
34 
35 	if (internal_reason < STATUS_PROP_START)
36 		return reason;
37 
38 	switch (internal_reason) {
39 	case STATUS_NO_NETWORK_FOUND:
40 		reason = QCA_STA_CONNECT_FAIL_REASON_NO_BSS_FOUND;
41 		break;
42 	case STATUS_AUTH_TX_FAIL:
43 		reason = QCA_STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL;
44 		break;
45 	case STATUS_AUTH_NO_ACK_RECEIVED:
46 		reason = QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED;
47 		break;
48 	case STATUS_AUTH_NO_RESP_RECEIVED:
49 		reason = QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED;
50 		break;
51 	case STATUS_ASSOC_TX_FAIL:
52 		reason = QCA_STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL;
53 		break;
54 	case STATUS_ASSOC_NO_ACK_RECEIVED:
55 		reason = QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED;
56 		break;
57 	case STATUS_ASSOC_NO_RESP_RECEIVED:
58 		reason = QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED;
59 		break;
60 	default:
61 		osif_debug("QCA code not present for internal status code %d",
62 			   internal_reason);
63 	}
64 
65 	return reason;
66 }
67 
68 const char *
69 osif_cm_qca_reason_to_str(enum qca_disconnect_reason_codes reason)
70 {
71 	switch (reason) {
72 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE);
73 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE);
74 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE);
75 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA);
76 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR);
77 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED);
78 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_DEVICE_RECOVERY);
79 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_KEY_TIMEOUT);
80 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE);
81 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_IFACE_DOWN);
82 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL);
83 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_PEER_INACTIVITY);
84 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT);
85 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE);
86 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE);
87 	CASE_RETURN_STRING(QCA_DISCONNECT_REASON_USER_TRIGGERED);
88 	case QCA_DISCONNECT_REASON_UNSPECIFIED:
89 		return "";
90 	default:
91 		return "Unknown";
92 	}
93 }
94 
95 enum qca_disconnect_reason_codes
96 osif_cm_mac_to_qca_reason(enum wlan_reason_code internal_reason)
97 {
98 	enum qca_disconnect_reason_codes reason =
99 					QCA_DISCONNECT_REASON_UNSPECIFIED;
100 
101 	if (internal_reason < REASON_PROP_START)
102 		return reason;
103 
104 	switch (internal_reason) {
105 	case REASON_HOST_TRIGGERED_ROAM_FAILURE:
106 	case REASON_FW_TRIGGERED_ROAM_FAILURE:
107 		reason = QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE;
108 		break;
109 	case REASON_USER_TRIGGERED_ROAM_FAILURE:
110 		reason = QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE;
111 		break;
112 	case REASON_GATEWAY_REACHABILITY_FAILURE:
113 		reason =
114 		QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE;
115 		break;
116 	case REASON_UNSUPPORTED_CHANNEL_CSA:
117 		reason = QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA;
118 		break;
119 	case REASON_OPER_CHANNEL_DISABLED_INDOOR:
120 		reason =
121 		QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR;
122 		break;
123 	case REASON_OPER_CHANNEL_USER_DISABLED:
124 		reason =
125 		QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED;
126 		break;
127 	case REASON_DEVICE_RECOVERY:
128 		reason = QCA_DISCONNECT_REASON_DEVICE_RECOVERY;
129 		break;
130 	case REASON_KEY_TIMEOUT:
131 		reason = QCA_DISCONNECT_REASON_KEY_TIMEOUT;
132 		break;
133 	case REASON_OPER_CHANNEL_BAND_CHANGE:
134 		reason = QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE;
135 		break;
136 	case REASON_IFACE_DOWN:
137 		reason = QCA_DISCONNECT_REASON_IFACE_DOWN;
138 		break;
139 	case REASON_PEER_XRETRY_FAIL:
140 		reason = QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL;
141 		break;
142 	case REASON_PEER_INACTIVITY:
143 		reason = QCA_DISCONNECT_REASON_PEER_INACTIVITY;
144 		break;
145 	case REASON_SA_QUERY_TIMEOUT:
146 		reason = QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT;
147 		break;
148 	case REASON_CHANNEL_SWITCH_FAILED:
149 		reason = QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE;
150 		break;
151 	case REASON_BEACON_MISSED:
152 		reason = QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE;
153 		break;
154 	default:
155 		osif_debug("No QCA reason code for mac reason: %u",
156 			   internal_reason);
157 		/* Unspecified reason by default */
158 	}
159 
160 	return reason;
161 }
162 
163 #ifdef FEATURE_CM_ENABLE
164 static struct osif_cm_ops *osif_cm_legacy_ops;
165 
166 void osif_cm_reset_id_and_src_no_lock(struct vdev_osif_priv *osif_priv)
167 {
168 	osif_priv->cm_info.last_id = CM_ID_INVALID;
169 	osif_priv->cm_info.last_source = CM_SOURCE_INVALID;
170 }
171 
172 QDF_STATUS osif_cm_reset_id_and_src(struct wlan_objmgr_vdev *vdev)
173 {
174 	struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev);
175 
176 	if (!osif_priv) {
177 		osif_err("Invalid vdev osif priv");
178 		return QDF_STATUS_E_INVAL;
179 	}
180 	qdf_spinlock_acquire(&osif_priv->cm_info.cmd_id_lock);
181 	osif_cm_reset_id_and_src_no_lock(osif_priv);
182 	qdf_spinlock_release(&osif_priv->cm_info.cmd_id_lock);
183 
184 	return QDF_STATUS_SUCCESS;
185 }
186 
187 /**
188  * osif_cm_connect_complete_cb() - Connect complete callback
189  * @vdev: vdev pointer
190  * @rsp: connect response
191  *
192  * Return: QDF_STATUS
193  */
194 static QDF_STATUS
195 osif_cm_connect_complete_cb(struct wlan_objmgr_vdev *vdev,
196 			    struct wlan_cm_connect_resp *rsp)
197 {
198 	return osif_connect_handler(vdev, rsp);
199 }
200 
201 /**
202  * osif_cm_failed_candidate_cb() - Callback to indicate failed candidate
203  * @vdev: vdev pointer
204  * @rsp: connect response
205  *
206  * Return: QDF_STATUS
207  */
208 static QDF_STATUS
209 osif_cm_failed_candidate_cb(struct wlan_objmgr_vdev *vdev,
210 			    struct wlan_cm_connect_resp *rsp)
211 {
212 	return osif_failed_candidate_handler(vdev, rsp);
213 }
214 
215 /**
216  * osif_cm_update_id_and_src_cb() - Callback to update id and
217  * source of the connect/disconnect request
218  * @vdev: vdev pointer
219  * @Source: Source of the connect req
220  * @id: Connect/disconnect id
221  *
222  * Context: Any context. Takes and releases cmd id spinlock
223  * Return: QDF_STATUS
224  */
225 static QDF_STATUS
226 osif_cm_update_id_and_src_cb(struct wlan_objmgr_vdev *vdev,
227 			     enum wlan_cm_source source, wlan_cm_id cm_id)
228 {
229 	struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev);
230 
231 	if (!osif_priv) {
232 		osif_err("Invalid vdev osif priv");
233 		return QDF_STATUS_E_INVAL;
234 	}
235 
236 	qdf_spinlock_acquire(&osif_priv->cm_info.cmd_id_lock);
237 	osif_priv->cm_info.last_id = cm_id;
238 	osif_priv->cm_info.last_source = source;
239 	qdf_spinlock_release(&osif_priv->cm_info.cmd_id_lock);
240 
241 	return QDF_STATUS_SUCCESS;
242 }
243 
244 /**
245  * osif_cm_disconnect_complete_cb() - Disconnect done callback
246  * @vdev: vdev pointer
247  * @disconnect_rsp: Disconnect response
248  *
249  * Context: Any context
250  * Return: QDF_STATUS
251  */
252 
253 static QDF_STATUS
254 osif_cm_disconnect_complete_cb(struct wlan_objmgr_vdev *vdev,
255 			       struct wlan_cm_discon_rsp *rsp)
256 {
257 	return osif_disconnect_handler(vdev, rsp);
258 }
259 
260 #ifdef CONN_MGR_ADV_FEATURE
261 void osif_cm_unlink_bss(struct wlan_objmgr_vdev *vdev,
262 			struct vdev_osif_priv *osif_priv,
263 			struct qdf_mac_addr *bssid,
264 			uint8_t *ssid, uint8_t ssid_len)
265 {
266 	struct wiphy *wiphy = osif_priv->wdev->wiphy;
267 	struct scan_filter *filter;
268 
269 	__wlan_cfg80211_unlink_bss_list(wiphy, bssid->bytes,
270 					ssid_len ? ssid : NULL, ssid_len);
271 	filter = qdf_mem_malloc(sizeof(*filter));
272 	if (!filter)
273 		return;
274 
275 	filter->num_of_bssid = 1;
276 	qdf_copy_macaddr(&filter->bssid_list[0], bssid);
277 	ucfg_scan_flush_results(wlan_vdev_get_pdev(vdev), filter);
278 	qdf_mem_free(filter);
279 }
280 
281 static QDF_STATUS
282 osif_cm_disable_netif_queue(struct wlan_objmgr_vdev *vdev)
283 {
284 	return osif_cm_netif_queue_ind(vdev,
285 				       WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
286 				       WLAN_CONTROL_PATH);
287 }
288 #else
289 static inline QDF_STATUS
290 osif_cm_disable_netif_queue(struct wlan_objmgr_vdev *vdev)
291 {
292 	return QDF_STATUS_SUCCESS;
293 }
294 #endif
295 /**
296  * osif_cm_disconnect_start_cb() - Disconnect start callback
297  * @vdev: vdev pointer
298  *
299  * This callback indicates os_if that disconnection is started
300  * so that os_if can stop all the activity on this connection
301  *
302  * Return: QDF_STATUS
303  */
304 static QDF_STATUS
305 osif_cm_disconnect_start_cb(struct wlan_objmgr_vdev *vdev)
306 {
307 	/* Disable netif queue on disconnect start */
308 	return osif_cm_disable_netif_queue(vdev);
309 }
310 
311 static struct mlme_cm_ops cm_ops = {
312 	.mlme_cm_connect_complete_cb = osif_cm_connect_complete_cb,
313 	.mlme_cm_failed_candidate_cb = osif_cm_failed_candidate_cb,
314 	.mlme_cm_update_id_and_src_cb = osif_cm_update_id_and_src_cb,
315 	.mlme_cm_disconnect_complete_cb = osif_cm_disconnect_complete_cb,
316 	.mlme_cm_disconnect_start_cb = osif_cm_disconnect_start_cb,
317 };
318 
319 /**
320  * osif_cm_get_global_ops() - Get connection manager global ops
321  *
322  * Return: Connection manager global ops
323  */
324 static struct mlme_cm_ops *osif_cm_get_global_ops(void)
325 {
326 	return &cm_ops;
327 }
328 
329 QDF_STATUS osif_cm_register_cb(void)
330 {
331 	mlme_set_osif_cm_cb(osif_cm_get_global_ops);
332 
333 	return QDF_STATUS_SUCCESS;
334 }
335 
336 QDF_STATUS osif_cm_osif_priv_init(struct wlan_objmgr_vdev *vdev)
337 {
338 	struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev);
339 	enum QDF_OPMODE mode = wlan_vdev_mlme_get_opmode(vdev);
340 
341 	if (mode != QDF_STA_MODE && mode != QDF_P2P_CLIENT_MODE)
342 		return QDF_STATUS_SUCCESS;
343 
344 	if (!osif_priv) {
345 		osif_err("Invalid vdev osif priv");
346 		return QDF_STATUS_E_INVAL;
347 	}
348 
349 	qdf_spinlock_create(&osif_priv->cm_info.cmd_id_lock);
350 
351 	return QDF_STATUS_SUCCESS;
352 }
353 
354 QDF_STATUS osif_cm_osif_priv_deinit(struct wlan_objmgr_vdev *vdev)
355 {
356 	struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev);
357 	enum QDF_OPMODE mode = wlan_vdev_mlme_get_opmode(vdev);
358 
359 	if (mode != QDF_STA_MODE && mode != QDF_P2P_CLIENT_MODE)
360 		return QDF_STATUS_SUCCESS;
361 
362 	if (!osif_priv) {
363 		osif_err("Invalid vdev osif priv");
364 		return QDF_STATUS_E_INVAL;
365 	}
366 	qdf_spinlock_destroy(&osif_priv->cm_info.cmd_id_lock);
367 
368 	return QDF_STATUS_SUCCESS;
369 }
370 
371 QDF_STATUS osif_cm_connect_comp_ind(struct wlan_objmgr_vdev *vdev,
372 				    struct wlan_cm_connect_resp *rsp,
373 				    enum osif_cb_type type)
374 {
375 	osif_cm_connect_comp_cb cb = NULL;
376 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
377 
378 	if (osif_cm_legacy_ops)
379 		cb = osif_cm_legacy_ops->connect_complete_cb;
380 	if (cb)
381 		ret = cb(vdev, rsp, type);
382 
383 	return ret;
384 }
385 
386 QDF_STATUS osif_cm_disconnect_comp_ind(struct wlan_objmgr_vdev *vdev,
387 				       struct wlan_cm_discon_rsp *rsp,
388 				       enum osif_cb_type type)
389 {
390 	osif_cm_disconnect_comp_cb cb = NULL;
391 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
392 
393 	if (osif_cm_legacy_ops)
394 		cb = osif_cm_legacy_ops->disconnect_complete_cb;
395 	if (cb)
396 		ret = cb(vdev, rsp, type);
397 
398 	return ret;
399 }
400 
401 #ifdef CONN_MGR_ADV_FEATURE
402 QDF_STATUS osif_cm_netif_queue_ind(struct wlan_objmgr_vdev *vdev,
403 				   enum netif_action_type action,
404 				   enum netif_reason_type reason)
405 {
406 	osif_cm_netif_queue_ctrl_cb cb = NULL;
407 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
408 
409 	if (osif_cm_legacy_ops)
410 		cb = osif_cm_legacy_ops->netif_queue_control_cb;
411 	if (cb)
412 		ret = cb(vdev, action, reason);
413 
414 	return ret;
415 }
416 #endif
417 
418 void osif_cm_set_legacy_cb(struct osif_cm_ops *osif_legacy_ops)
419 {
420 	osif_cm_legacy_ops = osif_legacy_ops;
421 }
422 
423 void osif_cm_reset_legacy_cb(void)
424 {
425 	osif_cm_legacy_ops = NULL;
426 }
427 #endif
428