diff --git a/os_if/linux/mlme/inc/osif_cm_req.h b/os_if/linux/mlme/inc/osif_cm_req.h index 0abdf04fb4..a88397e957 100644 --- a/os_if/linux/mlme/inc/osif_cm_req.h +++ b/os_if/linux/mlme/inc/osif_cm_req.h @@ -38,8 +38,7 @@ * * Return: int */ -int osif_cm_connect(struct net_device *dev, - struct wlan_objmgr_vdev *vdev, +int osif_cm_connect(struct net_device *dev, struct wlan_objmgr_vdev *vdev, struct cfg80211_connect_params *req); /** @@ -50,8 +49,17 @@ int osif_cm_connect(struct net_device *dev, * * Return: int */ -int osif_cm_disconnect(struct net_device *dev, - struct wlan_objmgr_vdev *vdev, +int osif_cm_disconnect(struct net_device *dev, struct wlan_objmgr_vdev *vdev, uint16_t reason); + +/** + * osif_cm_disconnect_sync() - Disconnect vdev and wait for it to complete + * @vdev: vdev pointer + * @reason: disconnect reason + * + * Return: int + */ +int osif_cm_disconnect_sync(struct wlan_objmgr_vdev *vdev, uint16_t reason); + #endif #endif /* __OSIF_CM_REQ_H */ diff --git a/os_if/linux/mlme/src/osif_cm_disconnect_rsp.c b/os_if/linux/mlme/src/osif_cm_disconnect_rsp.c index fd7f47f04a..fe9ce5a68a 100644 --- a/os_if/linux/mlme/src/osif_cm_disconnect_rsp.c +++ b/os_if/linux/mlme/src/osif_cm_disconnect_rsp.c @@ -150,5 +150,7 @@ QDF_STATUS osif_disconnect_handler(struct wlan_objmgr_vdev *vdev, locally_generated, rsp->ap_discon_ie.ptr, rsp->ap_discon_ie.len, GFP_KERNEL); + qdf_event_set(&osif_priv->cm_info.disconnect_complete); + return status; } diff --git a/os_if/linux/mlme/src/osif_cm_req.c b/os_if/linux/mlme/src/osif_cm_req.c index 5f151e06b1..07278d10a5 100644 --- a/os_if/linux/mlme/src/osif_cm_req.c +++ b/os_if/linux/mlme/src/osif_cm_req.c @@ -21,6 +21,7 @@ * request apis. */ +#include "wlan_osif_priv.h" #include "osif_cm_req.h" #include "wlan_cm_ucfg_api.h" #include "wlan_nl_to_crypto_params.h" @@ -395,16 +396,11 @@ connect_start_fail: return qdf_status_to_os_return(status); } -int osif_cm_disconnect(struct net_device *dev, struct wlan_objmgr_vdev *vdev, - uint16_t reason) +static QDF_STATUS osif_cm_send_disconnect(struct wlan_objmgr_vdev *vdev, + uint16_t reason) { - struct wlan_cm_disconnect_req *req; - uint8_t vdev_id = vdev->vdev_objmgr.vdev_id; QDF_STATUS status; - - osif_info("%s(vdevid-%d): Received Disconnect reason:%d %s", - dev->name, vdev_id, reason, - ucfg_cm_reason_code_to_str(reason)); + struct wlan_cm_disconnect_req *req; status = osif_cm_reset_id_and_src(vdev); if (QDF_IS_STATUS_ERROR(status)) @@ -412,17 +408,62 @@ int osif_cm_disconnect(struct net_device *dev, struct wlan_objmgr_vdev *vdev, req = qdf_mem_malloc(sizeof(*req)); if (!req) - return -ENOMEM; + return QDF_STATUS_E_NOMEM; - req->vdev_id = vdev_id; + req->vdev_id = wlan_vdev_get_id(vdev); req->source = CM_OSIF_DISCONNECT; req->reason_code = reason; status = ucfg_cm_start_disconnect(vdev, req); + qdf_mem_free(req); + + return status; +} + +int osif_cm_disconnect(struct net_device *dev, struct wlan_objmgr_vdev *vdev, + uint16_t reason) +{ + uint8_t vdev_id = wlan_vdev_get_id(vdev); + QDF_STATUS status; + + osif_info("%s(vdevid-%d): Received Disconnect reason:%d %s", + dev->name, vdev_id, reason, + ucfg_cm_reason_code_to_str(reason)); + + status = osif_cm_send_disconnect(vdev, reason); if (QDF_IS_STATUS_ERROR(status)) osif_err("Disconnect failed with status %d", status); - qdf_mem_free(req); - return qdf_status_to_os_return(status); } +int osif_cm_disconnect_sync(struct wlan_objmgr_vdev *vdev, uint16_t reason) +{ + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev); + QDF_STATUS status; + + if (ucfg_cm_is_vdev_disconnected(vdev)) + return 0; + + if (!osif_priv) { + osif_err("vdev %d invalid vdev osif priv", vdev_id); + return -EINVAL; + } + + osif_info("vdevid-%d: Received Disconnect reason:%d %s", + vdev_id, reason, ucfg_cm_reason_code_to_str(reason)); + + qdf_event_reset(&osif_priv->cm_info.disconnect_complete); + status = osif_cm_send_disconnect(vdev, reason); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Disconnect failed with status %d", status); + return qdf_status_to_os_return(status); + } + + status = qdf_wait_single_event(&osif_priv->cm_info.disconnect_complete, + CM_DISCONNECT_CMD_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) + osif_err("Disconnect timeout with status %d", status); + + return qdf_status_to_os_return(status); +} diff --git a/os_if/linux/mlme/src/osif_cm_util.c b/os_if/linux/mlme/src/osif_cm_util.c index c6c440a643..8b675698e6 100644 --- a/os_if/linux/mlme/src/osif_cm_util.c +++ b/os_if/linux/mlme/src/osif_cm_util.c @@ -261,6 +261,7 @@ QDF_STATUS osif_cm_osif_priv_init(struct wlan_objmgr_vdev *vdev) { struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev); enum QDF_OPMODE mode = wlan_vdev_mlme_get_opmode(vdev); + QDF_STATUS status; if (mode != QDF_STA_MODE && mode != QDF_P2P_CLIENT_MODE) return QDF_STATUS_SUCCESS; @@ -272,7 +273,19 @@ QDF_STATUS osif_cm_osif_priv_init(struct wlan_objmgr_vdev *vdev) qdf_spinlock_create(&osif_priv->cm_info.cmd_id_lock); - return QDF_STATUS_SUCCESS; + status = qdf_event_create(&osif_priv->cm_info.disconnect_complete); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("failed to create disconnect complete event fro vdev %d", + wlan_vdev_get_id(vdev)); + goto event_create_fail; + } + + return status; + +event_create_fail: + qdf_spinlock_destroy(&osif_priv->cm_info.cmd_id_lock); + + return status; } QDF_STATUS osif_cm_osif_priv_deinit(struct wlan_objmgr_vdev *vdev) @@ -287,7 +300,7 @@ QDF_STATUS osif_cm_osif_priv_deinit(struct wlan_objmgr_vdev *vdev) osif_err("Invalid vdev osif priv"); return QDF_STATUS_E_INVAL; } - + qdf_event_destroy(&osif_priv->cm_info.disconnect_complete); qdf_spinlock_destroy(&osif_priv->cm_info.cmd_id_lock); return QDF_STATUS_SUCCESS; diff --git a/os_if/linux/wlan_osif_priv.h b/os_if/linux/wlan_osif_priv.h index ff4bd6c2b1..30d7bcf19e 100644 --- a/os_if/linux/wlan_osif_priv.h +++ b/os_if/linux/wlan_osif_priv.h @@ -21,6 +21,7 @@ #define _WLAN_OSIF_PRIV_H_ #include "qdf_net_if.h" +#include #include "wlan_cm_public_struct.h" #include @@ -49,6 +50,7 @@ struct pdev_osif_priv { * @cmd_id_lock: lock to update and read last command source * @last_disconnect_reason: last disconnect reason to be indicated in get * station + * @disconnect_complete: disconnect completion wait event * @ext_priv: legacy data pointer. */ struct osif_cm_info { @@ -56,6 +58,7 @@ struct osif_cm_info { wlan_cm_id last_id; struct qdf_spinlock cmd_id_lock; enum qca_disconnect_reason_codes last_disconnect_reason; + qdf_event_t disconnect_complete; void *ext_priv; }; #endif diff --git a/umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c b/umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c index c788e0250d..343e83f547 100644 --- a/umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c +++ b/umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c @@ -117,8 +117,6 @@ cm_ser_disconnect_cb(struct wlan_serialization_command *cmd, return status; } -#define DISCONNECT_TIMEOUT STOP_RESPONSE_TIMER + DELETE_RESPONSE_TIMER + 1000 - static QDF_STATUS cm_ser_disconnect_req(struct wlan_objmgr_pdev *pdev, struct cnx_mgr *cm_ctx, struct cm_disconnect_req *req) diff --git a/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h b/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h index 27e109440a..2a04115b14 100644 --- a/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h +++ b/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h @@ -31,6 +31,12 @@ #define CM_ID_INVALID 0xFFFFFFFF typedef uint32_t wlan_cm_id; +/* Diconnect active timeout */ +#define DISCONNECT_TIMEOUT STOP_RESPONSE_TIMER + DELETE_RESPONSE_TIMER + 1000 + +/* Diconnect command wait timeout */ +#define CM_DISCONNECT_CMD_TIMEOUT DISCONNECT_TIMEOUT + 2000 + /** * struct wlan_cm_wep_key_params - store wep key info * @key: key info