|
@@ -761,41 +761,65 @@ static inline QDF_STATUS cm_set_fils_key(struct cnx_mgr *cm_ctx,
|
|
|
}
|
|
|
#endif /* WLAN_FEATURE_FILS_SK */
|
|
|
|
|
|
-static void cm_get_vdev_id_from_bssid(struct wlan_objmgr_pdev *pdev,
|
|
|
- void *object, void *arg)
|
|
|
+/**
|
|
|
+ * cm_get_vdev_id_with_active_vdev_op() - Get vdev id from serialization
|
|
|
+ * pending queue for which disconnect or connect is ongoing
|
|
|
+ * @pdev: pdev common object
|
|
|
+ * @object: vdev object
|
|
|
+ * @arg: vdev operation search arg
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+static void cm_get_vdev_id_with_active_vdev_op(struct wlan_objmgr_pdev *pdev,
|
|
|
+ void *object, void *arg)
|
|
|
{
|
|
|
- uint8_t *vdev_id = arg;
|
|
|
+ struct vdev_op_search_arg *vdev_arg = arg;
|
|
|
struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
|
|
|
+ uint8_t vdev_id = wlan_vdev_get_id(vdev);
|
|
|
+ enum QDF_OPMODE opmode = wlan_vdev_mlme_get_opmode(vdev);
|
|
|
|
|
|
- if (!vdev_id)
|
|
|
+ if (!vdev_arg)
|
|
|
return;
|
|
|
|
|
|
- if (!(wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE ||
|
|
|
- wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_CLIENT_MODE))
|
|
|
+ /* Avoid same vdev id check */
|
|
|
+ if (vdev_arg->current_vdev_id == vdev_id)
|
|
|
return;
|
|
|
|
|
|
- if (cm_is_vdev_disconnecting(vdev))
|
|
|
- *vdev_id = wlan_vdev_get_id(vdev);
|
|
|
+ if (opmode == QDF_STA_MODE || opmode == QDF_P2P_CLIENT_MODE) {
|
|
|
+ if (cm_is_vdev_disconnecting(vdev))
|
|
|
+ vdev_arg->sta_cli_vdev_id = vdev_id;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE) {
|
|
|
+ /* Check if START/STOP AP OP is in progress */
|
|
|
+ if (wlan_ser_is_non_scan_cmd_type_in_vdev_queue(vdev,
|
|
|
+ WLAN_SER_CMD_VDEV_START_BSS) ||
|
|
|
+ wlan_ser_is_non_scan_cmd_type_in_vdev_queue(vdev,
|
|
|
+ WLAN_SER_CMD_VDEV_STOP_BSS))
|
|
|
+ vdev_arg->sap_go_vdev_id = vdev_id;
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * cm_is_any_other_vdev_disconnecting() - check whether any other vdev is in
|
|
|
- * disconnecting state
|
|
|
+ * cm_is_any_other_vdev_connecting_disconnecting() - check whether any other
|
|
|
+ * vdev is in waiting for vdev operations (connect/disconnect or start/stop AP)
|
|
|
* @cm_ctx: connection manager context
|
|
|
* @cm_req: Connect request.
|
|
|
*
|
|
|
- * As Connect is a blocking call this API will make sure the disconnect
|
|
|
- * doesn't timeout on any vdev and thus make sure that PEER/VDEV SM are cleaned
|
|
|
- * before vdev delete is sent.
|
|
|
+ * As Connect is a blocking call this API will make sure the vdev operations on
|
|
|
+ * other vdev doesn't starve
|
|
|
*
|
|
|
- * Return : true if disconnection is on any vdev_id
|
|
|
+ * Return : true if any other vdev has pending operation
|
|
|
*/
|
|
|
-static bool cm_is_any_other_vdev_disconnecting(struct cnx_mgr *cm_ctx,
|
|
|
- struct cm_req *cm_req)
|
|
|
+static bool
|
|
|
+cm_is_any_other_vdev_connecting_disconnecting(struct cnx_mgr *cm_ctx,
|
|
|
+ struct cm_req *cm_req)
|
|
|
{
|
|
|
struct wlan_objmgr_pdev *pdev;
|
|
|
- uint8_t vdev_id;
|
|
|
uint8_t cur_vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
|
|
|
+ struct vdev_op_search_arg vdev_arg;
|
|
|
|
|
|
pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
|
|
|
if (!pdev) {
|
|
@@ -804,16 +828,32 @@ static bool cm_is_any_other_vdev_disconnecting(struct cnx_mgr *cm_ctx,
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- vdev_id = WLAN_INVALID_VDEV_ID;
|
|
|
+ vdev_arg.current_vdev_id = cur_vdev_id;
|
|
|
+ vdev_arg.sap_go_vdev_id = WLAN_INVALID_VDEV_ID;
|
|
|
+ vdev_arg.sta_cli_vdev_id = WLAN_INVALID_VDEV_ID;
|
|
|
wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
|
|
|
- cm_get_vdev_id_from_bssid,
|
|
|
- &vdev_id, 0,
|
|
|
+ cm_get_vdev_id_with_active_vdev_op,
|
|
|
+ &vdev_arg, 0,
|
|
|
WLAN_MLME_CM_ID);
|
|
|
|
|
|
- if (vdev_id != WLAN_INVALID_VDEV_ID && vdev_id != cur_vdev_id) {
|
|
|
- mlme_info(CM_PREFIX_FMT "Abort connection as vdev %d is waiting for disconnect",
|
|
|
+ /* For STA/CLI avoid the fist candidate itself if possible */
|
|
|
+ if (vdev_arg.sta_cli_vdev_id != WLAN_INVALID_VDEV_ID) {
|
|
|
+ mlme_info(CM_PREFIX_FMT "Abort connection as sta/cli vdev %d is disconnecting",
|
|
|
CM_PREFIX_REF(cur_vdev_id, cm_req->cm_id),
|
|
|
- vdev_id);
|
|
|
+ vdev_arg.sta_cli_vdev_id);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * For SAP/GO ops pending avoid the next candidate, this is to support
|
|
|
+ * wifi sharing etc use case where we need to connect to AP in parallel
|
|
|
+ * to SAP operation, so try atleast one candidate.
|
|
|
+ */
|
|
|
+ if (cm_req->connect_req.cur_candidate &&
|
|
|
+ vdev_arg.sap_go_vdev_id != WLAN_INVALID_VDEV_ID) {
|
|
|
+ mlme_info(CM_PREFIX_FMT "Avoid next candidate as SAP/GO vdev %d has pending vdev op",
|
|
|
+ CM_PREFIX_REF(cur_vdev_id, cm_req->cm_id),
|
|
|
+ vdev_arg.sap_go_vdev_id);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -1050,10 +1090,9 @@ static void cm_teardown_tdls(struct wlan_objmgr_vdev *vdev)
|
|
|
}
|
|
|
|
|
|
#else
|
|
|
-
|
|
|
-static inline
|
|
|
-bool cm_is_any_other_vdev_disconnecting(struct cnx_mgr *cm_ctx,
|
|
|
- struct cm_req *cm_req)
|
|
|
+static inline bool
|
|
|
+cm_is_any_other_vdev_connecting_disconnecting(struct cnx_mgr *cm_ctx,
|
|
|
+ struct cm_req *cm_req)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
@@ -1595,10 +1634,14 @@ static QDF_STATUS cm_get_valid_candidate(struct cnx_mgr *cm_ctx,
|
|
|
* This can lead to vdev delete sent without vdev down/stop/peer delete
|
|
|
* for the vdev.
|
|
|
*
|
|
|
- * So abort the connection if any of the vdev is waiting for disconnect,
|
|
|
- * to avoid disconnect timeout.
|
|
|
+ * Same way if a SAP/GO has start/stop command or peer disconnect in
|
|
|
+ * pending queue, delay in processing it can cause timeouts and other
|
|
|
+ * issues.
|
|
|
+ *
|
|
|
+ * So abort the next connection attempt if any of the vdev is waiting
|
|
|
+ * for vdev operation to avoid timeouts
|
|
|
*/
|
|
|
- if (cm_is_any_other_vdev_disconnecting(cm_ctx, cm_req)) {
|
|
|
+ if (cm_is_any_other_vdev_connecting_disconnecting(cm_ctx, cm_req)) {
|
|
|
status = QDF_STATUS_E_FAILURE;
|
|
|
goto flush_single_pmk;
|
|
|
}
|