Przeglądaj źródła

qcacmn: Fix potential memory leak when post scheduler msg in P2P

To avoid potential memory leak, add flush callback for some of P2P
messages, handle post scheduler messages fail case.

Change-Id: If700eba689bb2423ca84fbba08f7434cc75dbd14
CRs-Fixed: 2341756
Wu Gao 6 lat temu
rodzic
commit
43520acbbf

+ 76 - 4
core/src/wlan_p2p_main.c

@@ -429,6 +429,7 @@ static QDF_STATUS p2p_send_noa_to_pe(struct p2p_noa_info *noa_info)
 {
 	struct p2p_noa_attr *noa_attr;
 	struct scheduler_msg msg = {0};
+	QDF_STATUS status;
 
 	if (!noa_info) {
 		p2p_err("noa info is null");
@@ -474,11 +475,16 @@ static QDF_STATUS p2p_send_noa_to_pe(struct p2p_noa_info *noa_info)
 	msg.type = P2P_NOA_ATTR_IND;
 	msg.bodyval = 0;
 	msg.bodyptr = noa_attr;
-	scheduler_post_message(QDF_MODULE_ID_P2P,
-			       QDF_MODULE_ID_P2P,
-			       QDF_MODULE_ID_PE,  &msg);
+	status = scheduler_post_message(QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_PE,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(noa_attr);
+		p2p_err("post msg fail:%d", status);
+	}
 
-	return QDF_STATUS_SUCCESS;
+	return status;
 }
 
 /**
@@ -1044,6 +1050,72 @@ QDF_STATUS p2p_process_evt(struct scheduler_msg *msg)
 	return status;
 }
 
+QDF_STATUS p2p_msg_flush_callback(struct scheduler_msg *msg)
+{
+	struct tx_action_context *tx_action;
+
+	if (!msg || !(msg->bodyptr)) {
+		p2p_err("invalid msg");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_debug("flush msg, type:%d", msg->type);
+	switch (msg->type) {
+	case P2P_MGMT_TX:
+		tx_action = (struct tx_action_context *)msg->bodyptr;
+		qdf_mem_free(tx_action->buf);
+		qdf_mem_free(tx_action);
+		break;
+	default:
+		qdf_mem_free(msg->bodyptr);
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS p2p_event_flush_callback(struct scheduler_msg *msg)
+{
+	struct p2p_noa_event *noa_event;
+	struct p2p_rx_mgmt_event *rx_mgmt_event;
+	struct p2p_tx_conf_event *tx_conf_event;
+	struct p2p_lo_stop_event *lo_stop_event;
+
+	if (!msg || !(msg->bodyptr)) {
+		p2p_err("invalid msg");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_debug("flush event, type:%d", msg->type);
+	switch (msg->type) {
+	case P2P_EVENT_NOA:
+		noa_event = (struct p2p_noa_event *)msg->bodyptr;
+		qdf_mem_free(noa_event->noa_info);
+		qdf_mem_free(noa_event);
+		break;
+	case P2P_EVENT_RX_MGMT:
+		rx_mgmt_event = (struct p2p_rx_mgmt_event *)msg->bodyptr;
+		qdf_mem_free(rx_mgmt_event->rx_mgmt);
+		qdf_mem_free(rx_mgmt_event);
+		break;
+	case P2P_EVENT_MGMT_TX_ACK_CNF:
+		tx_conf_event = (struct p2p_tx_conf_event *)msg->bodyptr;
+		qdf_mem_free(tx_conf_event);
+		qdf_nbuf_free(tx_conf_event->nbuf);
+		break;
+	case P2P_EVENT_LO_STOPPED:
+		lo_stop_event = (struct p2p_lo_stop_event *)msg->bodyptr;
+		qdf_mem_free(lo_stop_event->lo_event);
+		qdf_mem_free(lo_stop_event);
+		break;
+	default:
+		qdf_mem_free(msg->bodyptr);
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 #ifdef FEATURE_P2P_LISTEN_OFFLOAD
 QDF_STATUS p2p_process_lo_stop(
 	struct p2p_lo_stop_event *lo_stop_event)

+ 20 - 0
core/src/wlan_p2p_main.h

@@ -445,6 +445,26 @@ QDF_STATUS p2p_process_cmd(struct scheduler_msg *msg);
  */
 QDF_STATUS p2p_process_evt(struct scheduler_msg *msg);
 
+/**
+ * p2p_msg_flush_callback() - Callback used to flush P2P messages
+ * @msg: message information
+ *
+ * This callback will be called when scheduler flush some of P2P messages.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_msg_flush_callback(struct scheduler_msg *msg);
+
+/**
+ * p2p_event_flush_callback() - Callback used to flush P2P events
+ * @msg: event information
+ *
+ * This callback will be called when scheduler flush some of P2P events.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_event_flush_callback(struct scheduler_msg *msg);
+
 #ifdef FEATURE_P2P_LISTEN_OFFLOAD
 /**
  * p2p_process_lo_stop() - Process lo stop event

+ 44 - 20
dispatcher/src/wlan_p2p_tgt_api.c

@@ -80,6 +80,7 @@ QDF_STATUS tgt_p2p_lo_event_cb(struct wlan_objmgr_psoc *psoc,
 	struct p2p_lo_stop_event *lo_stop_event;
 	struct scheduler_msg msg = {0};
 	struct p2p_soc_priv_obj *p2p_soc_obj;
+	QDF_STATUS status;
 
 	p2p_debug("soc:%pK, event_info:%pK", psoc, event_info);
 
@@ -116,11 +117,18 @@ QDF_STATUS tgt_p2p_lo_event_cb(struct wlan_objmgr_psoc *psoc,
 	msg.type = P2P_EVENT_LO_STOPPED;
 	msg.bodyptr = lo_stop_event;
 	msg.callback = p2p_process_evt;
+	msg.flush_callback = p2p_event_flush_callback;
+	status = scheduler_post_message(QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_TARGET_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(lo_stop_event->lo_event);
+		qdf_mem_free(lo_stop_event);
+		p2p_err("post msg fail:%d", status);
+	}
 
-        scheduler_post_message(QDF_MODULE_ID_P2P,
-                               QDF_MODULE_ID_P2P,
-                               QDF_MODULE_ID_TARGET_IF, &msg);
-	return QDF_STATUS_SUCCESS;
+	return status;
 }
 #endif /* FEATURE_P2P_LISTEN_OFFLOAD */
 
@@ -163,7 +171,7 @@ tgt_p2p_add_mac_addr_status_event_cb(struct wlan_objmgr_psoc *psoc,
 	msg.bodyptr = mac_filter_rsp;
 	msg.callback = p2p_process_evt;
 	status = scheduler_post_msg(QDF_MODULE_ID_TARGET_IF, &msg);
-	if (status != QDF_STATUS_SUCCESS)
+	if (QDF_IS_STATUS_ERROR(status))
 		qdf_mem_free(mac_filter_rsp);
 
 	return status;
@@ -261,17 +269,18 @@ QDF_STATUS tgt_p2p_mgmt_ota_comp_cb(void *context, qdf_nbuf_t buf,
 	msg.type = P2P_EVENT_MGMT_TX_ACK_CNF;
 	msg.bodyptr = tx_conf_event;
 	msg.callback = p2p_process_evt;
+	msg.flush_callback = p2p_event_flush_callback;
 	ret = scheduler_post_message(QDF_MODULE_ID_P2P,
 				     QDF_MODULE_ID_P2P,
-				     QDF_MODULE_ID_TARGET_IF, &msg);
-	if (ret != QDF_STATUS_SUCCESS) {
+				     QDF_MODULE_ID_TARGET_IF,
+				     &msg);
+	if (QDF_IS_STATUS_ERROR(ret)) {
 		qdf_mem_free(tx_conf_event);
-		qdf_mem_free(buf);
-		p2p_err("failed to post message");
-		return status;
+		qdf_nbuf_free(buf);
+		p2p_err("post msg fail:%d", status);
 	}
 
-	return QDF_STATUS_SUCCESS;
+	return ret;
 }
 
 QDF_STATUS tgt_p2p_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc,
@@ -286,6 +295,7 @@ QDF_STATUS tgt_p2p_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc,
 	struct wlan_objmgr_vdev *vdev;
 	uint32_t vdev_id;
 	uint8_t *pdata;
+	QDF_STATUS status;
 
 	p2p_debug("psoc:%pK, peer:%pK, type:%d", psoc, peer, frm_type);
 
@@ -349,13 +359,19 @@ QDF_STATUS tgt_p2p_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc,
 	msg.type = P2P_EVENT_RX_MGMT;
 	msg.bodyptr = rx_mgmt_event;
 	msg.callback = p2p_process_evt;
-	scheduler_post_message(QDF_MODULE_ID_P2P,
-			       QDF_MODULE_ID_P2P,
-			       QDF_MODULE_ID_TARGET_IF, &msg);
-
+	msg.flush_callback = p2p_event_flush_callback;
+	status = scheduler_post_message(QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_TARGET_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(rx_mgmt_event->rx_mgmt);
+		qdf_mem_free(rx_mgmt_event);
+		p2p_err("post msg fail:%d", status);
+	}
 	qdf_nbuf_free(buf);
 
-	return QDF_STATUS_SUCCESS;
+	return status;
 }
 
 QDF_STATUS  tgt_p2p_noa_event_cb(struct wlan_objmgr_psoc *psoc,
@@ -364,6 +380,7 @@ QDF_STATUS  tgt_p2p_noa_event_cb(struct wlan_objmgr_psoc *psoc,
 	struct p2p_noa_event *noa_event;
 	struct scheduler_msg msg = {0};
 	struct p2p_soc_priv_obj *p2p_soc_obj;
+	QDF_STATUS status;
 
 	p2p_debug("soc:%pK, event_info:%pK", psoc, event_info);
 
@@ -400,9 +417,16 @@ QDF_STATUS  tgt_p2p_noa_event_cb(struct wlan_objmgr_psoc *psoc,
 	msg.type = P2P_EVENT_NOA;
 	msg.bodyptr = noa_event;
 	msg.callback = p2p_process_evt;
-	scheduler_post_message(QDF_MODULE_ID_P2P,
-			       QDF_MODULE_ID_P2P,
-			       QDF_MODULE_ID_TARGET_IF, &msg);
+	msg.flush_callback = p2p_event_flush_callback;
+	status = scheduler_post_message(QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_TARGET_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(noa_event->noa_info);
+		qdf_mem_free(noa_event);
+		p2p_err("post msg fail:%d", status);
+	}
 
-	return QDF_STATUS_SUCCESS;
+	return status;
 }

+ 52 - 22
dispatcher/src/wlan_p2p_ucfg_api.c

@@ -141,7 +141,7 @@ QDF_STATUS ucfg_p2p_roc_req(struct wlan_objmgr_psoc *soc,
 	}
 
 	status = qdf_idr_alloc(&p2p_soc_obj->p2p_idr, roc_ctx, &id);
-	if (status != QDF_STATUS_SUCCESS) {
+	if (QDF_IS_STATUS_ERROR(status)) {
 		qdf_mem_free(roc_ctx);
 		p2p_err("failed to alloc idr, status %d", status);
 		return status;
@@ -159,12 +159,18 @@ QDF_STATUS ucfg_p2p_roc_req(struct wlan_objmgr_psoc *soc,
 	msg.type = P2P_ROC_REQ;
 	msg.bodyptr = roc_ctx;
 	msg.callback = p2p_process_cmd;
-	scheduler_post_message(QDF_MODULE_ID_HDD,
-			       QDF_MODULE_ID_P2P,
-			       QDF_MODULE_ID_OS_IF, &msg);
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_OS_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(roc_ctx);
+		qdf_idr_remove(&p2p_soc_obj->p2p_idr, id);
+		p2p_err("post msg fail:%d", status);
+	}
 	p2p_debug("cookie = 0x%llx", *cookie);
 
-	return QDF_STATUS_SUCCESS;
+	return status;
 }
 
 QDF_STATUS ucfg_p2p_roc_cancel_req(struct wlan_objmgr_psoc *soc,
@@ -174,6 +180,7 @@ QDF_STATUS ucfg_p2p_roc_cancel_req(struct wlan_objmgr_psoc *soc,
 	struct p2p_soc_priv_obj *p2p_soc_obj;
 	struct cancel_roc_context *cancel_roc;
 	void *roc_ctx = NULL;
+	QDF_STATUS status;
 
 	p2p_debug("soc:%pK, cookie:0x%llx", soc, cookie);
 
@@ -189,8 +196,9 @@ QDF_STATUS ucfg_p2p_roc_cancel_req(struct wlan_objmgr_psoc *soc,
 		return QDF_STATUS_E_FAILURE;
 	}
 
-	if (QDF_STATUS_SUCCESS != qdf_idr_find(&p2p_soc_obj->p2p_idr,
-					       cookie, &roc_ctx)) {
+	status = qdf_idr_find(&p2p_soc_obj->p2p_idr,
+			      cookie, &roc_ctx);
+	if (QDF_IS_STATUS_ERROR(status)) {
 		p2p_err("invalid id");
 		return QDF_STATUS_E_INVAL;
 	}
@@ -206,11 +214,17 @@ QDF_STATUS ucfg_p2p_roc_cancel_req(struct wlan_objmgr_psoc *soc,
 	msg.type = P2P_CANCEL_ROC_REQ;
 	msg.bodyptr = cancel_roc;
 	msg.callback = p2p_process_cmd;
-	scheduler_post_message(QDF_MODULE_ID_HDD,
-			       QDF_MODULE_ID_P2P,
-			       QDF_MODULE_ID_OS_IF, &msg);
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_OS_IF,
+					&msg);
 
-	return QDF_STATUS_SUCCESS;
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(cancel_roc);
+		p2p_err("post msg fail:%d", status);
+	}
+
+	return status;
 }
 
 QDF_STATUS ucfg_p2p_cleanup_roc_by_vdev(struct wlan_objmgr_vdev *vdev)
@@ -342,7 +356,7 @@ QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc,
 	else {
 		status = qdf_idr_alloc(&p2p_soc_obj->p2p_idr,
 				       tx_action, &id);
-		if (status != QDF_STATUS_SUCCESS) {
+		if (QDF_IS_STATUS_ERROR(status)) {
 			qdf_mem_free(tx_action);
 			p2p_err("failed to alloc idr, status :%d", status);
 			return status;
@@ -373,11 +387,20 @@ QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc,
 	msg.type = P2P_MGMT_TX;
 	msg.bodyptr = tx_action;
 	msg.callback = p2p_process_cmd;
-	scheduler_post_message(QDF_MODULE_ID_HDD,
-			       QDF_MODULE_ID_P2P,
-			       QDF_MODULE_ID_OS_IF, &msg);
+	msg.flush_callback = p2p_msg_flush_callback;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_OS_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		if (id)
+			qdf_idr_remove(&p2p_soc_obj->p2p_idr, id);
+		qdf_mem_free(tx_action->buf);
+		qdf_mem_free(tx_action);
+		p2p_err("post msg fail:%d", status);
+	}
 
-	return QDF_STATUS_SUCCESS;
+	return status;
 }
 
 QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc,
@@ -387,6 +410,7 @@ QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc,
 	struct p2p_soc_priv_obj *p2p_soc_obj;
 	struct cancel_roc_context *cancel_tx;
 	void *tx_ctx;
+	QDF_STATUS status;
 
 	p2p_debug("soc:%pK, cookie:0x%llx", soc, cookie);
 
@@ -402,8 +426,9 @@ QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc,
 		return QDF_STATUS_E_FAILURE;
 	}
 
-	if (QDF_STATUS_SUCCESS != qdf_idr_find(&p2p_soc_obj->p2p_idr,
-					       (int32_t)cookie, &tx_ctx)) {
+	status = qdf_idr_find(&p2p_soc_obj->p2p_idr,
+			      (int32_t)cookie, &tx_ctx);
+	if (QDF_IS_STATUS_ERROR(status)) {
 		p2p_debug("invalid id");
 		return QDF_STATUS_E_INVAL;
 	}
@@ -420,11 +445,16 @@ QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc,
 	msg.type = P2P_MGMT_TX_CANCEL;
 	msg.bodyptr = cancel_tx;
 	msg.callback = p2p_process_cmd;
-	scheduler_post_message(QDF_MODULE_ID_HDD,
-			       QDF_MODULE_ID_P2P,
-			       QDF_MODULE_ID_OS_IF, &msg);
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_OS_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(cancel_tx);
+		p2p_err("post msg fail: %d", status);
+	}
 
-	return QDF_STATUS_SUCCESS;
+	return status;
 }
 
 bool ucfg_p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,