1 /* 2 * Copyright (c) 2018-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 * @file wlan_vdev_mlme_ser.c 19 * This file contains the APIs to support interface between vdev_mlme and 20 * serialization module 21 */ 22 23 #include <qdf_types.h> 24 #include <qdf_status.h> 25 #include <qdf_mem.h> 26 #include <wlan_serialization_api.h> 27 #include <wlan_objmgr_vdev_obj.h> 28 #include <wlan_cmn.h> 29 #include <wlan_mlme_dbg.h> 30 #include <include/wlan_mlme_cmn.h> 31 #include <wlan_vdev_mlme_api.h> 32 #include <wlan_vdev_mlme_ser_if.h> 33 34 enum wlan_serialization_status 35 wlan_vdev_mlme_ser_start_bss(struct wlan_serialization_command *cmd) 36 { 37 struct vdev_mlme_obj *vdev_mlme; 38 39 if (!cmd || !cmd->vdev) { 40 mlme_err("Null input"); 41 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 42 } 43 44 if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev)) 45 return WLAN_SER_CMD_QUEUE_DISABLED; 46 /* 47 * Serialization command filtering logic 48 * a. Cancel any existing start bss cmd in the pending queue 49 * b. If there is an start bss cmd in active queue and 50 * there is no stop bss cmd in pending queue, 51 * then explicitly enqueue a stop bss cmd to avoid back to 52 * back execution of UP cmd. 53 * c. Enqueue the new start bss cmd with serialization 54 */ 55 wlan_vdev_mlme_ser_cancel_request( 56 cmd->vdev, 57 WLAN_SER_CMD_VDEV_START_BSS, 58 WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE); 59 60 if (wlan_serialization_is_cmd_present_in_active_queue(NULL, cmd)) { 61 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(cmd->vdev); 62 if (mlme_vdev_enqueue_exp_ser_cmd(vdev_mlme, 63 WLAN_SER_CMD_VDEV_STOP_BSS)) { 64 mlme_err("Unable to add the exception cmd request"); 65 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 66 } 67 } 68 69 return wlan_serialization_request(cmd); 70 } 71 72 enum wlan_serialization_status 73 wlan_vdev_mlme_ser_stop_bss(struct wlan_serialization_command *cmd) 74 { 75 uint8_t stop_cmd_pending; 76 uint8_t ret; 77 78 if (!cmd || !cmd->vdev) { 79 mlme_err("Null input"); 80 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 81 } 82 83 if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev)) 84 return WLAN_SER_CMD_QUEUE_DISABLED; 85 /* 86 * Serialization command filtering logic 87 * a. Cancel any existing start/stop/restart command in the pending 88 * queue. 89 * b. If there is a stop cmd in active queue then return 90 * c. Else enqueue the cmd 91 * d. If stop cmd already existed in pending queue then return with 92 * already exists else return the enqueued return value. 93 */ 94 stop_cmd_pending = 95 wlan_serialization_is_cmd_present_in_pending_queue(NULL, cmd); 96 wlan_vdev_mlme_ser_cancel_request(cmd->vdev, 97 WLAN_SER_CMD_NONSCAN, 98 WLAN_SER_CANCEL_VDEV_NON_SCAN_NB_CMD); 99 100 if (wlan_serialization_is_cmd_present_in_active_queue(NULL, cmd)) { 101 mlme_debug("Cmd already exist in the active queue"); 102 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 103 } 104 105 ret = wlan_serialization_request(cmd); 106 107 if (stop_cmd_pending && ret == WLAN_SER_CMD_PENDING) 108 return WLAN_SER_CMD_ALREADY_EXISTS; 109 else 110 return ret; 111 } 112 113 enum wlan_serialization_status 114 wlan_vdev_mlme_ser_vdev_restart(struct wlan_serialization_command *cmd) 115 { 116 if (!cmd || !cmd->vdev) { 117 mlme_err("Null input"); 118 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 119 } 120 121 if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev)) 122 return WLAN_SER_CMD_QUEUE_DISABLED; 123 /* 124 * Serialization command filtering logic 125 * a. If there exists START or PDEV/VDEV restart command in the pending 126 * queue then ignore this new vdev restart request. 127 * b. Else enqueue the new VDEV RESTART cmd 128 */ 129 cmd->cmd_type = WLAN_SER_CMD_VDEV_START_BSS; 130 if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, cmd)) { 131 mlme_debug("Start cmd already in the pending queue"); 132 return WLAN_SER_CMD_ALREADY_EXISTS; 133 } 134 135 cmd->cmd_type = WLAN_SER_CMD_PDEV_RESTART; 136 if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, cmd)) { 137 mlme_debug("Pdev restart already in the pending queue"); 138 return WLAN_SER_CMD_ALREADY_EXISTS; 139 } 140 141 cmd->cmd_type = WLAN_SER_CMD_VDEV_RESTART; 142 if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, cmd)) { 143 mlme_debug("Vdev restart already in the pending queue"); 144 return WLAN_SER_CMD_ALREADY_EXISTS; 145 } 146 147 return wlan_serialization_request(cmd); 148 } 149 150 void wlan_mlme_restart_pdev_iter_cb(struct wlan_objmgr_pdev *pdev, 151 void *object, void *arg) 152 { 153 struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; 154 uint8_t *pdev_restart_pending = (uint8_t *)arg; 155 struct wlan_serialization_command cmd = {0}; 156 uint8_t vdev_id = wlan_vdev_get_id(vdev); 157 158 cmd.vdev = vdev; 159 cmd.cmd_id = vdev_id; 160 cmd.cmd_type = WLAN_SER_CMD_PDEV_RESTART; 161 /* 162 * Serialization command filtering logic 163 * a. Cancel any existing VDEV restart cmd in the pending queue 164 * b. If Pdev restart already exist in pending queue then return else 165 * enqueue the new PDEV RESTART cmd 166 */ 167 wlan_vdev_mlme_ser_cancel_request( 168 vdev, 169 WLAN_SER_CMD_VDEV_RESTART, 170 WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE); 171 172 if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, &cmd)) { 173 mlme_debug("Cmd already exist in the pending queue vdev:%u", 174 vdev_id); 175 *pdev_restart_pending = 1; 176 } 177 } 178 179 enum wlan_serialization_status 180 wlan_vdev_mlme_ser_pdev_restart(struct wlan_serialization_command *cmd) 181 { 182 struct wlan_objmgr_pdev *pdev; 183 uint8_t pdev_restart_in_pending = 0; 184 185 if (!cmd || !cmd->vdev) { 186 mlme_err("Null input"); 187 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 188 } 189 190 if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev)) 191 return WLAN_SER_CMD_QUEUE_DISABLED; 192 193 pdev = wlan_vdev_get_pdev(cmd->vdev); 194 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 195 wlan_mlme_restart_pdev_iter_cb, 196 &pdev_restart_in_pending, 0, 197 WLAN_MLME_SER_IF_ID); 198 199 if (pdev_restart_in_pending) 200 return WLAN_SER_CMD_ALREADY_EXISTS; 201 202 return wlan_serialization_request(cmd); 203 } 204 205 enum wlan_serialization_status 206 wlan_vdev_mlme_ser_connect(struct wlan_serialization_command *cmd) 207 { 208 struct vdev_mlme_obj *vdev_mlme; 209 210 if (!cmd || !cmd->vdev) { 211 mlme_err("Null input"); 212 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 213 } 214 215 if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev)) 216 return WLAN_SER_CMD_QUEUE_DISABLED; 217 /* 218 * Serialization command filtering logic 219 * a. Cancel any existing CONNECT cmd in the pending queue 220 * b. If there is an CONNECT cmd in active queue and there is no 221 * DISCONNECT cmd in pending queue, then explicitly enqueue a 222 * DISCONNECT cmd to avoid back to back execution of CONNECT cmd. 223 * c. Enqueue the new CONNECT cmd to the pending queue 224 */ 225 wlan_vdev_mlme_ser_cancel_request( 226 cmd->vdev, 227 WLAN_SER_CMD_VDEV_CONNECT, 228 WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE); 229 230 if (wlan_serialization_is_cmd_present_in_active_queue(NULL, cmd)) { 231 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(cmd->vdev); 232 if (mlme_vdev_enqueue_exp_ser_cmd(vdev_mlme, 233 WLAN_SER_CMD_VDEV_DISCONNECT)) { 234 mlme_err("Unable to add the exception cmd request"); 235 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 236 } 237 } 238 239 return wlan_serialization_request(cmd); 240 } 241 242 enum wlan_serialization_status 243 wlan_vdev_mlme_ser_disconnect(struct wlan_serialization_command *cmd) 244 { 245 if (!cmd || !cmd->vdev) { 246 mlme_err("Null input"); 247 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 248 } 249 250 if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev)) 251 return WLAN_SER_CMD_QUEUE_DISABLED; 252 /* 253 * Serialization command filtering logic 254 * a.Cancel any existing non-blocking non-scan command in the 255 * pending queue 256 * b.If there is a DISCONNECT cmd in active queue then return 257 * c.Else enqueue the DISCONNECT cmd 258 */ 259 wlan_vdev_mlme_ser_cancel_request(cmd->vdev, 260 WLAN_SER_CMD_NONSCAN, 261 WLAN_SER_CANCEL_VDEV_NON_SCAN_NB_CMD); 262 263 if (wlan_serialization_is_cmd_present_in_active_queue(NULL, cmd)) { 264 mlme_debug("Cmd already exist in the active queue"); 265 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 266 } 267 268 return wlan_serialization_request(cmd); 269 } 270 271 static void 272 wlan_mlme_cancel_pending_csa_restart(struct wlan_objmgr_pdev *pdev, 273 void *object, void *arg) 274 { 275 struct wlan_objmgr_vdev *vdev = object; 276 bool *csa_restart_pending = arg; 277 struct wlan_serialization_command cmd = {0}; 278 uint8_t vdev_id = wlan_vdev_get_id(vdev); 279 280 cmd.vdev = vdev; 281 cmd.cmd_id = vdev_id; 282 cmd.cmd_type = WLAN_SER_CMD_PDEV_CSA_RESTART; 283 if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, &cmd)) { 284 mlme_debug("Cmd already exist in the pending queue vdev:%u", 285 vdev_id); 286 *csa_restart_pending = true; 287 } 288 289 wlan_vdev_mlme_ser_cancel_request( 290 vdev, 291 WLAN_SER_CMD_PDEV_CSA_RESTART, 292 WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE); 293 } 294 295 static void 296 wlan_mlme_check_pdev_restart(struct wlan_objmgr_pdev *pdev, 297 void *object, void *arg) 298 { 299 struct wlan_objmgr_vdev *vdev = object; 300 bool *pdev_restart_pending = arg; 301 struct wlan_serialization_command cmd = {0}; 302 uint8_t vdev_id = wlan_vdev_get_id(vdev); 303 304 cmd.vdev = vdev; 305 cmd.cmd_id = vdev_id; 306 cmd.cmd_type = WLAN_SER_CMD_PDEV_RESTART; 307 if (wlan_serialization_is_cmd_present_in_active_queue(NULL, &cmd)) { 308 mlme_debug("Pdev restart already in the active queue vdev:%u", 309 vdev_id); 310 *pdev_restart_pending = true; 311 } 312 } 313 314 enum wlan_serialization_status 315 wlan_vdev_mlme_ser_pdev_csa_restart(struct wlan_serialization_command *cmd) 316 { 317 struct wlan_objmgr_pdev *pdev; 318 bool csa_restart_pending = false; 319 bool pdev_restart_pending = false; 320 enum wlan_serialization_status ret; 321 322 if (!cmd || !cmd->vdev) { 323 mlme_err("Null input"); 324 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 325 } 326 327 if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev)) 328 return WLAN_SER_CMD_QUEUE_DISABLED; 329 330 /* 331 * Serialization command filtering logic 332 * a. Cancel any existing PDEV CSA restart cmd in the pending queue 333 * b. If there exists PDEV RESTART command in the active queue 334 * then deny this request 335 * c. If PDEV CSA RESTART cmd already existed in pending queue 336 * then enqueue and return already exists 337 * d. Else enqueue this PDEV CSA RESTART cmd 338 */ 339 pdev = wlan_vdev_get_pdev(cmd->vdev); 340 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 341 wlan_mlme_cancel_pending_csa_restart, 342 &csa_restart_pending, 0, 343 WLAN_MLME_SER_IF_ID); 344 345 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 346 wlan_mlme_check_pdev_restart, 347 &pdev_restart_pending, 0, 348 WLAN_MLME_SER_IF_ID); 349 350 if (pdev_restart_pending) 351 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 352 353 ret = wlan_serialization_request(cmd); 354 355 if (csa_restart_pending && ret == WLAN_SER_CMD_PENDING) 356 return WLAN_SER_CMD_ALREADY_EXISTS; 357 358 return ret; 359 } 360 361 void 362 wlan_vdev_mlme_ser_remove_request(struct wlan_objmgr_vdev *vdev, 363 uint32_t cmd_id, 364 enum wlan_serialization_cmd_type cmd_type) 365 { 366 struct wlan_serialization_queued_cmd_info cmd = {0}; 367 368 mlme_debug("Vdev:%d remove cmd:%d", wlan_vdev_get_id(vdev), cmd_type); 369 370 cmd.vdev = vdev; 371 cmd.cmd_id = cmd_id; 372 cmd.cmd_type = cmd_type; 373 cmd.requestor = WLAN_UMAC_COMP_MLME; 374 cmd.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; 375 cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; 376 377 /* Inform serialization for command completion */ 378 wlan_serialization_remove_cmd(&cmd); 379 } 380 381 void 382 wlan_vdev_mlme_ser_cancel_request(struct wlan_objmgr_vdev *vdev, 383 enum wlan_serialization_cmd_type cmd_type, 384 enum wlan_serialization_cancel_type req_type) 385 { 386 struct wlan_serialization_queued_cmd_info cmd = {0}; 387 388 cmd.vdev = vdev; 389 cmd.cmd_type = cmd_type; 390 cmd.req_type = req_type; 391 cmd.requestor = WLAN_UMAC_COMP_MLME; 392 cmd.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE; 393 394 wlan_serialization_cancel_request(&cmd); 395 } 396 397 void 398 mlme_ser_inc_act_cmd_timeout(struct wlan_serialization_command *cmd) 399 { 400 mlme_debug("Increase timeout of cmd type:%d", cmd->cmd_type); 401 wlan_serialization_update_timer(cmd); 402 } 403