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