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 (!cm_is_connect_req_reassoc(req)) 76 return QDF_STATUS_E_FAILURE; 77 78 wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &bssid); 79 80 /* Reject re-assoc unless prev_bssid matches the current BSSID. */ 81 if (!qdf_is_macaddr_equal(&req->prev_bssid, &bssid)) { 82 mlme_debug("BSSID didn't matched: bssid: "QDF_MAC_ADDR_FMT " prev bssid: " QDF_MAC_ADDR_FMT, 83 QDF_MAC_ADDR_REF(bssid.bytes), 84 QDF_MAC_ADDR_REF(req->prev_bssid.bytes)); 85 return QDF_STATUS_E_FAILURE; 86 } 87 88 status = wlan_vdev_mlme_get_ssid(cm_ctx->vdev, ssid.ssid, &ssid.length); 89 if (QDF_IS_STATUS_ERROR(status)) { 90 mlme_err("failed to get ssid"); 91 return QDF_STATUS_E_FAILURE; 92 } 93 94 /* Reject re-assoc unless ssid matches. */ 95 if (ssid.length != req->ssid.length || 96 qdf_mem_cmp(ssid.ssid, req->ssid.ssid, ssid.length)) { 97 mlme_debug("SSID didn't matched: self ssid: \"%.*s\", ssid in req: \"%.*s\"", 98 ssid.length, ssid.ssid, req->ssid.length, 99 req->ssid.ssid); 100 return QDF_STATUS_E_FAILURE; 101 } 102 103 /* fill roam_req for roaming and free cm_req */ 104 *roam_req = qdf_mem_malloc(sizeof(**roam_req)); 105 if (!*roam_req) 106 return QDF_STATUS_E_NOMEM; 107 108 req_ptr = *roam_req; 109 if (!qdf_is_macaddr_zero(&req->bssid)) 110 qdf_copy_macaddr(&req_ptr->roam_req.req.bssid, &req->bssid); 111 else 112 qdf_copy_macaddr(&req_ptr->roam_req.req.bssid, 113 &req->bssid_hint); 114 115 qdf_copy_macaddr(&req_ptr->roam_req.req.prev_bssid, &req->prev_bssid); 116 cm_fill_roam_vdev_crypto_params(cm_ctx, &connect_req->req); 117 req_ptr->roam_req.req.chan_freq = freq; 118 req_ptr->roam_req.req.source = CM_ROAMING_HOST; 119 120 /* Free the connect req, as reassoc is tried */ 121 cm_free_connect_req_mem(connect_req); 122 qdf_mem_free(cm_req); 123 124 return QDF_STATUS_SUCCESS; 125 } 126 127 QDF_STATUS cm_add_roam_req_to_list(struct cnx_mgr *cm_ctx, 128 struct cm_req *cm_req) 129 { 130 QDF_STATUS status; 131 132 cm_req->roam_req.cm_id = 133 cm_get_cm_id(cm_ctx, cm_req->roam_req.req.source); 134 cm_req->cm_id = cm_req->roam_req.cm_id; 135 cm_req->roam_req.req.vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 136 status = 137 cm_add_req_to_list_and_indicate_osif(cm_ctx, cm_req, 138 cm_req->roam_req.req.source); 139 140 return status; 141 } 142 143 QDF_STATUS 144 cm_fill_bss_info_in_roam_rsp_by_cm_id(struct cnx_mgr *cm_ctx, 145 wlan_cm_id cm_id, 146 struct wlan_cm_connect_resp *resp) 147 { 148 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 149 struct cm_req *cm_req; 150 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 151 struct wlan_cm_roam_req *req; 152 153 if (prefix != ROAM_REQ_PREFIX) 154 return QDF_STATUS_E_INVAL; 155 156 cm_req_lock_acquire(cm_ctx); 157 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 158 while (cur_node) { 159 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 160 cm_req = qdf_container_of(cur_node, struct cm_req, node); 161 162 if (cm_req->cm_id == cm_id) { 163 req = &cm_req->roam_req.req; 164 resp->freq = req->chan_freq; 165 wlan_vdev_mlme_get_ssid(cm_ctx->vdev, resp->ssid.ssid, 166 &resp->ssid.length); 167 168 if (!qdf_is_macaddr_zero(&req->bssid)) 169 qdf_copy_macaddr(&resp->bssid, &req->bssid); 170 171 cm_req_lock_release(cm_ctx); 172 return QDF_STATUS_SUCCESS; 173 } 174 175 cur_node = next_node; 176 next_node = NULL; 177 } 178 cm_req_lock_release(cm_ctx); 179 180 return QDF_STATUS_E_FAILURE; 181 } 182 183 bool cm_is_roam_enabled(struct wlan_objmgr_psoc *psoc) 184 { 185 if (cm_roam_offload_enabled(psoc) || cm_is_host_roam_enabled()) 186 return true; 187 188 mlme_rl_debug("All roam mode (offload %d, host %d) are disabled", 189 cm_roam_offload_enabled(psoc), cm_is_host_roam_enabled()); 190 191 return false; 192 } 193 #endif 194 195 #ifdef WLAN_FEATURE_HOST_ROAM 196 bool cm_get_active_reassoc_req(struct wlan_objmgr_vdev *vdev, 197 struct wlan_cm_vdev_reassoc_req *req) 198 { 199 struct cnx_mgr *cm_ctx; 200 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 201 struct cm_req *cm_req = NULL; 202 bool status = false; 203 uint32_t cm_id_prefix; 204 205 cm_ctx = cm_get_cm_ctx(vdev); 206 if (!cm_ctx) 207 return status; 208 209 cm_req_lock_acquire(cm_ctx); 210 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 211 while (cur_node) { 212 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 213 214 cm_req = qdf_container_of(cur_node, struct cm_req, node); 215 cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id)); 216 217 if (cm_req->cm_id == cm_ctx->active_cm_id && 218 cm_id_prefix == ROAM_REQ_PREFIX) { 219 req->vdev_id = wlan_vdev_get_id(vdev); 220 req->cm_id = cm_req->roam_req.cm_id; 221 qdf_copy_macaddr(&req->prev_bssid, 222 &cm_req->roam_req.req.prev_bssid); 223 req->bss = cm_req->roam_req.cur_candidate; 224 status = true; 225 cm_req_lock_release(cm_ctx); 226 return status; 227 } 228 229 cur_node = next_node; 230 next_node = NULL; 231 } 232 cm_req_lock_release(cm_ctx); 233 234 return status; 235 } 236 #endif 237 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 238 struct cm_roam_req *cm_get_first_roam_command(struct wlan_objmgr_vdev *vdev) 239 { 240 struct cnx_mgr *cm_ctx; 241 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 242 struct cm_req *cm_req = NULL; 243 uint32_t cm_id_prefix; 244 245 cm_ctx = cm_get_cm_ctx(vdev); 246 if (!cm_ctx) 247 return NULL; 248 249 cm_req_lock_acquire(cm_ctx); 250 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 251 while (cur_node) { 252 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 253 254 cm_req = qdf_container_of(cur_node, struct cm_req, node); 255 cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id)); 256 257 if (cm_id_prefix == ROAM_REQ_PREFIX) { 258 cm_req_lock_release(cm_ctx); 259 return &cm_req->roam_req; 260 } 261 262 cur_node = next_node; 263 next_node = NULL; 264 } 265 cm_req_lock_release(cm_ctx); 266 267 return NULL; 268 } 269 #endif 270