Просмотр исходного кода

qcacmn: Add changes to add and delete connection mgr req

Add changes in connection manager to add and delete connection mgr
request from the cm ctx list. Also make changes to add support
to get cm id for these requests.

Change-Id: I33706e01ea684e8c3524407ca9b4c67d438db8a5
CRs-Fixed: 2770693
gaurank kathpalia 4 лет назад
Родитель
Сommit
d69cadae0c

+ 1 - 1
os_if/linux/mlme/src/wlan_cfg80211_cm_req.c

@@ -324,7 +324,7 @@ int wlan_osif_cfg80211_connect(struct net_device *dev,
 		return -ENOMEM;
 
 	connect_req->vdev_id = vdev_id;
-	connect_req->source = CM_OSIF_CONENCT_REQ;
+	connect_req->source = CM_OSIF_CONNECT_REQ;
 	if (req->bssid)
 		qdf_mem_copy(connect_req->bssid.bytes, req->bssid,
 			     QDF_MAC_ADDR_SIZE);

+ 36 - 6
umac/mlme/connection_mgr/core/src/wlan_cm_connect.c

@@ -398,15 +398,45 @@ QDF_STATUS cm_connect_complete(struct cnx_mgr *cm_ctx,
 QDF_STATUS cm_connect_start_req(struct wlan_objmgr_vdev *vdev,
 				struct wlan_cm_connect_req *req)
 {
-	struct cnx_mgr *cm_ctx = NULL;
-	struct cm_connect_req *cm_req = NULL;
+	struct cnx_mgr *cm_ctx;
+	struct cm_req *cm_req;
+	struct cm_connect_req *connect_req;
+	QDF_STATUS status;
+
+	cm_ctx = cm_get_cm_ctx(vdev);
+
+	if (!cm_ctx) {
+		mlme_err("cm ctx NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* This would be freed as part of list removal from req list */
+	cm_req = qdf_mem_malloc(sizeof(*cm_req));
+	if (!cm_req)
+		return QDF_STATUS_E_NOMEM;
 
 	/*
 	 * Get WAPI/WPA/RSN IE and refill crypto params of req.
-	 * Prepare cm_connect_req cm_req, get cm id and inform it to OSIF.
-	 * store connect req to the cm ctx req_list
 	 */
 
-	return cm_sm_deliver_event(cm_ctx, WLAN_CM_SM_EV_CONNECT_REQ,
-				   sizeof(*cm_req), cm_req);
+	connect_req = &cm_req->connect_req;
+	connect_req->cm_id = cm_get_cm_id(cm_ctx, req->source);
+	cm_req->cm_id = connect_req->cm_id;
+	connect_req->req = *req;
+
+	status = cm_add_req_to_list(cm_ctx, cm_req);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(cm_req);
+		return status;
+	}
+
+	mlme_cm_osif_update_id_and_src(vdev, req->source, cm_req->cm_id);
+
+	status = cm_sm_deliver_event(cm_ctx, WLAN_CM_SM_EV_CONNECT_REQ,
+				     sizeof(*connect_req), connect_req);
+	if (QDF_IS_STATUS_ERROR(status))
+		cm_delete_req_from_list(cm_ctx, cm_req->cm_id);
+
+	return status;
 }

+ 37 - 8
umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c

@@ -148,14 +148,43 @@ QDF_STATUS cm_disconnect_complete(struct cnx_mgr *cm_ctx,
 QDF_STATUS cm_disconnect_start_req(struct wlan_objmgr_vdev *vdev,
 				   struct wlan_cm_disconnect_req *req)
 {
-	struct cnx_mgr *cm_ctx = NULL;
-	struct cm_disconnect_req *cm_req = NULL;
+	struct cnx_mgr *cm_ctx;
+	struct cm_req *cm_req;
+	struct cm_disconnect_req *disconnect_req;
+	QDF_STATUS status;
 
-	/*
-	 * Prepare cm_disconnect_req cm_req, get cm id and inform it to
-	 * OSIF. store disconnect req to the cm ctx req_list
-	 */
+	cm_ctx = cm_get_cm_ctx(vdev);
+
+	if (!cm_ctx) {
+		mlme_err("cm ctx NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* This would be freed as part of list removal from req list */
+	cm_req = qdf_mem_malloc(sizeof(*cm_req));
+
+	if (!cm_req)
+		return QDF_STATUS_E_NOMEM;
+
+	disconnect_req = &cm_req->discon_req;
 
-	return cm_sm_deliver_event(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_REQ,
-				   sizeof(*cm_req), cm_req);
+	disconnect_req->cm_id = cm_get_cm_id(cm_ctx, req->source);
+	cm_req->cm_id = disconnect_req->cm_id;
+	disconnect_req->req = *req;
+
+	status = cm_add_req_to_list(cm_ctx, cm_req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(cm_req);
+		return status;
+	}
+
+	mlme_cm_osif_update_id_and_src(vdev, req->source, cm_req->cm_id);
+
+	status = cm_sm_deliver_event(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_REQ,
+				     sizeof(*disconnect_req), disconnect_req);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		cm_delete_req_from_list(cm_ctx, cm_req->cm_id);
+
+	return status;
 }

+ 44 - 0
umac/mlme/connection_mgr/core/src/wlan_cm_main.c

@@ -21,6 +21,48 @@
 #include "wlan_cm_main.h"
 #include "wlan_cm_sm.h"
 
+#ifdef WLAN_CM_USE_SPINLOCK
+/**
+ * cm_req_lock_create - Create CM req SM mutex/spinlock
+ * @cm_ctx:  connection manager ctx
+ *
+ * Creates CM SM mutex/spinlock
+ *
+ * Return: void
+ */
+static inline void
+cm_req_lock_create(struct cnx_mgr *cm_ctx)
+{
+	qdf_spinlock_create(&cm_ctx->cm_req_lock);
+}
+
+/**
+ * cm_req_lock_destroy - Destroy CM SM mutex/spinlock
+ * @cm_ctx:  connection manager ctx
+ *
+ * Destroy CM SM mutex/spinlock
+ *
+ * Return: void
+ */
+static inline void
+cm_req_lock_destroy(struct cnx_mgr *cm_ctx)
+{
+	qdf_spinlock_destroy(&cm_ctx->cm_req_lock);
+}
+#else
+static inline void
+cm_req_lock_create(struct cnx_mgr *cm_ctx)
+{
+	qdf_mutex_create(&cm_ctx->cm_req_lock);
+}
+
+static inline void
+cm_req_lock_destroy(struct cnx_mgr *cm_ctx)
+{
+	qdf_mutex_destroy(&cm_ctx->cm_req_lock);
+}
+#endif /* WLAN_CM_USE_SPINLOCK */
+
 QDF_STATUS wlan_cm_init(struct vdev_mlme_obj *vdev_mlme)
 {
 	struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev;
@@ -43,6 +85,7 @@ QDF_STATUS wlan_cm_init(struct vdev_mlme_obj *vdev_mlme)
 		return QDF_STATUS_E_NOMEM;
 	}
 	qdf_list_create(&vdev_mlme->cnx_mgr_ctx->req_list, CM_MAX_REQ);
+	cm_req_lock_create(vdev_mlme->cnx_mgr_ctx);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -55,6 +98,7 @@ QDF_STATUS wlan_cm_deinit(struct vdev_mlme_obj *vdev_mlme)
 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
 		return QDF_STATUS_SUCCESS;
 
+	cm_req_lock_destroy(vdev_mlme->cnx_mgr_ctx);
 	qdf_list_destroy(&vdev_mlme->cnx_mgr_ctx->req_list);
 	cm_sm_destroy(vdev_mlme->cnx_mgr_ctx);
 	qdf_mem_free(vdev_mlme->cnx_mgr_ctx);

+ 8 - 2
umac/mlme/connection_mgr/core/src/wlan_cm_main.h

@@ -124,14 +124,12 @@ struct cm_disconnect_req {
 /**
  * struct cm_req - connect manager req
  * @node: connection manager req node
- * @source: req source
  * @cm_id: cm id
  * @connect_req: connect req
  * @disconnect_req: disconnect req
  */
 struct cm_req {
 	qdf_list_node_t node;
-	enum wlan_cm_source source;
 	wlan_cm_id cm_id;
 	union {
 		struct cm_connect_req connect_req;
@@ -160,21 +158,29 @@ struct connect_ies {
  * @vdev: vdev back pointer
  * @sm: state machine
  * @req_list: connect/disconnect req list
+ * @cm_req_lock: lock to manupulate/read the cm req list
  * @disconnect_count: disconnect count
  * @connect_count: connect count
  * @force_rsne_override: if QCA_WLAN_VENDOR_ATTR_CONFIG_RSN_IE is set by
  * framework
  * @req_ie: request ies for connect/disconnect set by osif/user separately from
  * connect req
+ * @global_cmd_id: global cmd id for getting cm id for connect/disconnect req
  */
 struct cnx_mgr {
 	struct wlan_objmgr_vdev *vdev;
 	struct cm_state_sm sm;
 	qdf_list_t req_list;
+#ifdef WLAN_CM_USE_SPINLOCK
+	qdf_spinlock_t cm_req_lock;
+#else
+	qdf_mutex_t cm_req_lock;
+#endif
 	uint8_t disconnect_count;
 	uint8_t connect_count;
 	bool force_rsne_override;
 	struct connect_ies req_ie;
+	qdf_atomic_t global_cmd_id;
 };
 
 /**

+ 80 - 9
umac/mlme/connection_mgr/core/src/wlan_cm_main_api.h

@@ -24,8 +24,10 @@
 #define __WLAN_CM_MAIN_API_H__
 
 #include "wlan_cm_main.h"
+#include <include/wlan_mlme_cmn.h>
 
 /*************** CONNECT APIs ****************/
+
 /**
  * cm_connect_start() - This API will be called to initiate the connect
  * process
@@ -112,6 +114,21 @@ QDF_STATUS cm_connect_complete(struct cnx_mgr *cm_ctx,
 QDF_STATUS cm_connect_start_req(struct wlan_objmgr_vdev *vdev,
 				struct wlan_cm_connect_req *req);
 
+#ifdef WLAN_POLICY_MGR_ENABLE
+/**
+ * cm_hw_mode_change_resp() - HW mode change response
+ * @pdev: pdev pointer
+ * @vdev_id: vdev id
+ * @cm_id: connection ID which gave the hw mode change request
+ * @status: status of the HW mode change.
+ *
+ * Return: QDF_STATUS
+ */
+void cm_hw_mode_change_resp(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
+			    wlan_cm_id cm_id, QDF_STATUS status);
+
+#endif
+
 /*************** DISCONNECT APIs ****************/
 
 /**
@@ -157,18 +174,72 @@ QDF_STATUS cm_disconnect_complete(struct cnx_mgr *cm_ctx,
 QDF_STATUS cm_disconnect_start_req(struct wlan_objmgr_vdev *vdev,
 				   struct wlan_cm_disconnect_req *req);
 
+/*************** UTIL APIs ****************/
+
 /**
- * cm_hw_mode_change_resp() - HW mode change response
- * @pdev: pdev pointer
- * @vdev_id: vdev id
- * @cm_id: connection ID which gave the hw mode change request
- * @status: status of the HW mode change.
+ * cm_get_cm_id() - Get unique cm id for connect/disconnect request
+ * @cm_ctx: connection manager context
+ * @source: source of the request (can be connect or disconnect request)
+ *
+ * Return: cm id
+ */
+wlan_cm_id cm_get_cm_id(struct cnx_mgr *cm_ctx, enum wlan_cm_source source);
+
+/**
+ * cm_get_cm_ctx() - Get connection manager context from vdev
+ * @vdev: vdev object pointer
+ *
+ * Return: pointer to connection manager context
+ */
+struct cnx_mgr *cm_get_cm_ctx(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * cm_check_cmid_match_list_head() - check if list head command matches the
+ * given cm_id
+ * @cm_ctx: connection manager context
+ * @cm_id: cm id of connect/disconnect req
+ *
+ * Check if front req command matches the given
+ * cm_id, this can be used to check if the latest (head) is same we are
+ * trying to processing
+ *
+ * Return: true if match else false
+ */
+bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id);
+
+/**
+ * cm_delete_req_from_list() - Delete the request matching cm id
+ * @cm_ctx: connection manager context
+ * @cm_id: cm id of connect/disconnect req
+ *
+ * Context: Can be called from any context.
  *
  * Return: QDF_STATUS
  */
-#ifdef WLAN_POLICY_MGR_ENABLE
-void cm_hw_mode_change_resp(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
-			    wlan_cm_id cm_id, QDF_STATUS status);
+QDF_STATUS cm_delete_req_from_list(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id);
+
+/**
+ * cm_add_req_to_list() - Add the request to request list in cm ctx
+ * @cm_ctx: connection manager context
+ * @cm_req: cm request
+ *
+ * Context: Can be called from any context.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS cm_add_req_to_list(struct cnx_mgr *cm_ctx, struct cm_req *cm_req);
+
+/**
+ * cm_get_req_by_cm_id() - Get cm req matching the cm id
+ * @cm_ctx: connection manager context
+ * @cm_id: cm id of connect/disconnect req
+ *
+ * Context: Can be called from any context and to be used only after posting a
+ * msg to SM (ie holding the SM lock) to avoid use after free. also returned req
+ * should only be used till SM lock is hold.
+ *
+ * Return: cm req from the req list whose cm id matches the argument
+ */
+struct cm_req *cm_get_req_by_cm_id(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id);
 
-#endif
 #endif /* __WLAN_CM_MAIN_API_H__ */

+ 191 - 0
umac/mlme/connection_mgr/core/src/wlan_cm_util.c

@@ -17,3 +17,194 @@
 /**
  * DOC: Implements general util apis of connection manager
  */
+
+#include "wlan_cm_main_api.h"
+#include "wlan_scan_api.h"
+#include "wlan_cm_public_struct.h"
+
+#define CONNECT_REQ_PREFIX          0x00C00000
+#define DISCONNECT_REQ_PREFIX       0x00D00000
+#define CM_ID_MASK                  0x0000FFFF
+
+#define CM_ID_GET_PREFIX(cm_id)     cm_id & 0xFFFF0000
+
+static uint32_t cm_get_prefix_for_cm_id(enum wlan_cm_source source) {
+	switch (source) {
+	case CM_OSIF_CONNECT_REQ:
+	case CM_ROAMING:
+		return CONNECT_REQ_PREFIX;
+	default:
+		return DISCONNECT_REQ_PREFIX;
+	}
+}
+
+wlan_cm_id cm_get_cm_id(struct cnx_mgr *cm_ctx, enum wlan_cm_source source)
+{
+	wlan_cm_id cmd_id;
+	uint32_t prefix;
+
+	prefix = cm_get_prefix_for_cm_id(source);
+
+	cmd_id = qdf_atomic_inc_return(&cm_ctx->global_cmd_id);
+	cmd_id = (cmd_id & CM_ID_MASK);
+	cmd_id = (cmd_id | prefix);
+
+	return cmd_id;
+}
+
+struct cnx_mgr *cm_get_cm_ctx(struct wlan_objmgr_vdev *vdev)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme)
+		return NULL;
+
+	return vdev_mlme->cnx_mgr_ctx;
+}
+
+
+#ifdef WLAN_CM_USE_SPINLOCK
+/**
+ * cm_req_lock_acquire - acquire CM SM mutex/spinlock
+ * @cm_ctx:  connection manager ctx
+ *
+ * acquire CM SM mutex/spinlock
+ *
+ * return: void
+ */
+static inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx)
+{
+	qdf_spinlock_acquire(&cm_ctx->cm_req_lock);
+}
+
+/**
+ * cm_req_lock_release - release CM SM mutex/spinlock
+ * @cm_ctx:  connection manager ctx
+ *
+ * release CM SM mutex/spinlock
+ *
+ * return: void
+ */
+static inline void cm_req_lock_release(struct cnx_mgr *cm_ctx)
+{
+	qdf_spinlock_release(&cm_ctx->cm_req_lock);
+}
+#else
+static inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx)
+{
+	qdf_mutex_acquire(&cm_ctx->cm_req_lock);
+}
+
+static inline void cm_req_lock_release(struct cnx_mgr *cm_ctx)
+{
+	qdf_mutex_release(&cm_ctx->cm_req_lock);
+}
+#endif /* WLAN_CM_USE_SPINLOCK */
+
+bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
+{
+	qdf_list_node_t *cur_node = NULL;
+	struct cm_req *cm_req;
+	bool match = false;
+
+	cm_req_lock_acquire(cm_ctx);
+	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
+	if (!cur_node)
+		goto exit;
+
+	cm_req = qdf_container_of(cur_node, struct cm_req, node);
+	if (cm_req->cm_id == cm_id)
+		match = true;
+
+exit:
+	cm_req_lock_release(cm_ctx);
+
+	return match;
+}
+
+struct cm_req *cm_get_req_by_cm_id(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
+{
+	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
+	struct cm_req * cm_req;
+
+	cm_req_lock_acquire(cm_ctx);
+	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
+	while (cur_node) {
+		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
+		cm_req = qdf_container_of(cur_node, struct cm_req, node);
+
+		if (cm_req->cm_id == cm_id) {
+			cm_req_lock_release(cm_ctx);
+			return cm_req;
+		}
+
+		cur_node = next_node;
+		next_node = NULL;
+	}
+	cm_req_lock_release(cm_ctx);
+
+	return NULL;
+}
+
+QDF_STATUS cm_add_req_to_list(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
+{
+	uint32_t prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
+
+	cm_req_lock_acquire(cm_ctx);
+	if (qdf_list_size(&cm_ctx->req_list) >= CM_MAX_REQ) {
+		cm_req_lock_release(cm_ctx);
+		mlme_err("List full size %d", qdf_list_size(&cm_ctx->req_list));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_list_insert_front(&cm_ctx->req_list, &cm_req->node);
+	if (prefix == CONNECT_REQ_PREFIX)
+		cm_ctx->connect_count++;
+	else
+		cm_ctx->disconnect_count++;
+	cm_req_lock_release(cm_ctx);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cm_delete_req_from_list(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
+{
+	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
+	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
+	struct cm_req *cm_req = NULL;
+
+	cm_req_lock_acquire(cm_ctx);
+	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
+	while (cur_node) {
+		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
+
+		cm_req = qdf_container_of(cur_node, struct cm_req, node);
+		if (cm_req->cm_id == cm_id)
+			break;
+
+		cur_node = next_node;
+		next_node = NULL;
+		cm_req = NULL;
+	}
+
+	if (!cm_req) {
+		cm_req_lock_release(cm_ctx);
+		mlme_err("cm req id %d not found", cm_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node);
+	if (prefix == CONNECT_REQ_PREFIX) {
+		cm_ctx->connect_count--;
+		wlan_scan_purge_results(cm_req->connect_req.candidate_list);
+	} else {
+		cm_ctx->disconnect_count--;
+	}
+
+	qdf_mem_free(cm_req);
+	cm_req_lock_release(cm_ctx);
+
+	return QDF_STATUS_SUCCESS;
+}

+ 2 - 2
umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h

@@ -100,7 +100,7 @@ struct wlan_fils_con_info {
 
 /**
  * enum wlan_cm_source - connection manager req source
- * @CM_OSIF_CONENCT_REQ: Connect req initiated by OSIF or north bound
+ * @CM_OSIF_CONNECT_REQ: Connect req initiated by OSIF or north bound
  * @CM_ROAMING: Roaming request
  * @CM_OSIF_DISCONNECT: Disconnect req initiated by OSIF or north bound
  * @CM_PEER_DISCONNECT: Disconnect req initiated by peer sending deauth/disassoc
@@ -111,7 +111,7 @@ struct wlan_fils_con_info {
  * @CM_ROAM_DISCONNECT: Disconnect req due to HO failure
  */
 enum wlan_cm_source {
-	CM_OSIF_CONENCT_REQ,
+	CM_OSIF_CONNECT_REQ,
 	CM_ROAMING,
 	CM_OSIF_DISCONNECT,
 	CM_PEER_DISCONNECT,