1 /* 2 * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-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: Implements general Roam utils for connection manager 20 */ 21 22 #include "wlan_cm_main.h" 23 #include "wlan_cm_roam_sm.h" 24 #include "wlan_cm_sm.h" 25 #include "wlan_cm_main_api.h" 26 #include "wlan_cm_roam.h" 27 #include <wlan_scan_api.h> 28 29 void cm_free_roam_req_mem(struct cm_roam_req *roam_req) 30 { 31 if (roam_req->candidate_list) 32 wlan_scan_purge_results(roam_req->candidate_list); 33 } 34 35 #ifndef CONN_MGR_ADV_FEATURE 36 static void cm_fill_roam_vdev_crypto_params(struct cnx_mgr *cm_ctx, 37 struct wlan_cm_connect_req *req) 38 { 39 cm_fill_vdev_crypto_params(cm_ctx, req); 40 } 41 #else 42 static void cm_fill_roam_vdev_crypto_params(struct cnx_mgr *cm_ctx, 43 struct wlan_cm_connect_req *req) 44 { 45 } 46 #endif /* CONN_MGR_ADV_FEATURE */ 47 48 #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) 49 QDF_STATUS cm_check_and_prepare_roam_req(struct cnx_mgr *cm_ctx, 50 struct cm_connect_req *connect_req, 51 struct cm_req **roam_req) 52 { 53 QDF_STATUS status; 54 struct wlan_cm_connect_req *req; 55 struct qdf_mac_addr bssid; 56 struct wlan_ssid ssid; 57 struct cm_req *cm_req, *req_ptr; 58 qdf_freq_t freq = 0; 59 60 /* Handle only if roam is enabled */ 61 if (!cm_is_roam_enabled(wlan_vdev_get_psoc(cm_ctx->vdev))) 62 return QDF_STATUS_E_NOSUPPORT; 63 64 cm_req = qdf_container_of(connect_req, struct cm_req, connect_req); 65 req = &connect_req->req; 66 67 if (req->chan_freq) 68 freq = req->chan_freq; 69 else if (req->chan_freq_hint) 70 freq = req->chan_freq_hint; 71 /* 72 * Reject re-assoc unless freq along with prev bssid and one 73 * of bssid or bssid hint is present. 74 */ 75 if (!freq || qdf_is_macaddr_zero(&req->prev_bssid) || 76 (qdf_is_macaddr_zero(&req->bssid) && 77 qdf_is_macaddr_zero(&req->bssid_hint))) 78 return QDF_STATUS_E_FAILURE; 79 80 wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &bssid); 81 82 /* Reject re-assoc unless prev_bssid matches the current BSSID. */ 83 if (!qdf_is_macaddr_equal(&req->prev_bssid, &bssid)) { 84 mlme_debug("BSSID didn't matched: bssid: "QDF_MAC_ADDR_FMT " prev bssid: " QDF_MAC_ADDR_FMT, 85 QDF_MAC_ADDR_REF(bssid.bytes), 86 QDF_MAC_ADDR_REF(req->prev_bssid.bytes)); 87 return QDF_STATUS_E_FAILURE; 88 } 89 90 status = wlan_vdev_mlme_get_ssid(cm_ctx->vdev, ssid.ssid, &ssid.length); 91 if (QDF_IS_STATUS_ERROR(status)) { 92 mlme_err("failed to get ssid"); 93 return QDF_STATUS_E_FAILURE; 94 } 95 96 /* Reject re-assoc unless ssid matches. */ 97 if (ssid.length != req->ssid.length || 98 qdf_mem_cmp(ssid.ssid, req->ssid.ssid, ssid.length)) { 99 mlme_debug("SSID didn't matched: self ssid: \"%.*s\", ssid in req: \"%.*s\"", 100 ssid.length, ssid.ssid, req->ssid.length, 101 req->ssid.ssid); 102 return QDF_STATUS_E_FAILURE; 103 } 104 105 /* fill roam_req for roaming and free cm_req */ 106 *roam_req = qdf_mem_malloc(sizeof(**roam_req)); 107 if (!*roam_req) 108 return QDF_STATUS_E_NOMEM; 109 110 req_ptr = *roam_req; 111 if (!qdf_is_macaddr_zero(&req->bssid)) 112 qdf_copy_macaddr(&req_ptr->roam_req.req.bssid, &req->bssid); 113 else 114 qdf_copy_macaddr(&req_ptr->roam_req.req.bssid, 115 &req->bssid_hint); 116 117 qdf_copy_macaddr(&req_ptr->roam_req.req.prev_bssid, &req->prev_bssid); 118 cm_fill_roam_vdev_crypto_params(cm_ctx, &connect_req->req); 119 req_ptr->roam_req.req.chan_freq = freq; 120 req_ptr->roam_req.req.source = CM_ROAMING_HOST; 121 122 /* Free the connect req, as reassoc is tried */ 123 cm_free_connect_req_mem(connect_req); 124 qdf_mem_free(cm_req); 125 126 return QDF_STATUS_SUCCESS; 127 } 128 129 QDF_STATUS cm_add_roam_req_to_list(struct cnx_mgr *cm_ctx, 130 struct cm_req *cm_req) 131 { 132 QDF_STATUS status; 133 134 cm_req->roam_req.cm_id = 135 cm_get_cm_id(cm_ctx, cm_req->roam_req.req.source); 136 cm_req->cm_id = cm_req->roam_req.cm_id; 137 cm_req->roam_req.req.vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 138 status = 139 cm_add_req_to_list_and_indicate_osif(cm_ctx, cm_req, 140 cm_req->roam_req.req.source); 141 142 return status; 143 } 144 145 QDF_STATUS 146 cm_fill_bss_info_in_roam_rsp_by_cm_id(struct cnx_mgr *cm_ctx, 147 wlan_cm_id cm_id, 148 struct wlan_cm_connect_resp *resp) 149 { 150 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 151 struct cm_req *cm_req; 152 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 153 struct wlan_cm_roam_req *req; 154 155 if (prefix != ROAM_REQ_PREFIX) 156 return QDF_STATUS_E_INVAL; 157 158 cm_req_lock_acquire(cm_ctx); 159 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 160 while (cur_node) { 161 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 162 cm_req = qdf_container_of(cur_node, struct cm_req, node); 163 164 if (cm_req->cm_id == cm_id) { 165 req = &cm_req->roam_req.req; 166 resp->freq = req->chan_freq; 167 wlan_vdev_mlme_get_ssid(cm_ctx->vdev, resp->ssid.ssid, 168 &resp->ssid.length); 169 170 if (!qdf_is_macaddr_zero(&req->bssid)) 171 qdf_copy_macaddr(&resp->bssid, &req->bssid); 172 173 cm_req_lock_release(cm_ctx); 174 return QDF_STATUS_SUCCESS; 175 } 176 177 cur_node = next_node; 178 next_node = NULL; 179 } 180 cm_req_lock_release(cm_ctx); 181 182 return QDF_STATUS_E_FAILURE; 183 } 184 185 bool cm_is_roam_enabled(struct wlan_objmgr_psoc *psoc) 186 { 187 if (cm_roam_offload_enabled(psoc) || cm_is_host_roam_enabled()) 188 return true; 189 190 mlme_rl_debug("All roam mode (offload %d, host %d) are disabled", 191 cm_roam_offload_enabled(psoc), cm_is_host_roam_enabled()); 192 193 return false; 194 } 195 #endif 196 197 #ifdef WLAN_FEATURE_HOST_ROAM 198 bool cm_get_active_reassoc_req(struct wlan_objmgr_vdev *vdev, 199 struct wlan_cm_vdev_reassoc_req *req) 200 { 201 struct cnx_mgr *cm_ctx; 202 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 203 struct cm_req *cm_req = NULL; 204 bool status = false; 205 uint32_t cm_id_prefix; 206 207 cm_ctx = cm_get_cm_ctx(vdev); 208 if (!cm_ctx) 209 return status; 210 211 cm_req_lock_acquire(cm_ctx); 212 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 213 while (cur_node) { 214 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 215 216 cm_req = qdf_container_of(cur_node, struct cm_req, node); 217 cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id)); 218 219 if (cm_req->cm_id == cm_ctx->active_cm_id && 220 cm_id_prefix == ROAM_REQ_PREFIX) { 221 req->vdev_id = wlan_vdev_get_id(vdev); 222 req->cm_id = cm_req->roam_req.cm_id; 223 qdf_copy_macaddr(&req->prev_bssid, 224 &cm_req->roam_req.req.prev_bssid); 225 req->bss = cm_req->roam_req.cur_candidate; 226 status = true; 227 cm_req_lock_release(cm_ctx); 228 return status; 229 } 230 231 cur_node = next_node; 232 next_node = NULL; 233 } 234 cm_req_lock_release(cm_ctx); 235 236 return status; 237 } 238 #endif 239 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 240 struct cm_roam_req *cm_get_first_roam_command(struct wlan_objmgr_vdev *vdev) 241 { 242 struct cnx_mgr *cm_ctx; 243 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 244 struct cm_req *cm_req = NULL; 245 uint32_t cm_id_prefix; 246 247 cm_ctx = cm_get_cm_ctx(vdev); 248 if (!cm_ctx) 249 return NULL; 250 251 cm_req_lock_acquire(cm_ctx); 252 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 253 while (cur_node) { 254 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 255 256 cm_req = qdf_container_of(cur_node, struct cm_req, node); 257 cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id)); 258 259 if (cm_id_prefix == ROAM_REQ_PREFIX) { 260 cm_req_lock_release(cm_ctx); 261 return &cm_req->roam_req; 262 } 263 264 cur_node = next_node; 265 next_node = NULL; 266 } 267 cm_req_lock_release(cm_ctx); 268 269 return NULL; 270 } 271 #endif 272