Browse Source

Merge "qcacmn: Fix for kernel panic in wifi up path"

Linux Build Service Account 7 years ago
parent
commit
5e29e77a44
1 changed files with 57 additions and 12 deletions
  1. 57 12
      dp/wifi3.0/dp_tx.c

+ 57 - 12
dp/wifi3.0/dp_tx.c

@@ -207,8 +207,6 @@ static uint8_t dp_tx_prepare_htt_metadata(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 
 	uint8_t *hdr = NULL;
 
-	qdf_nbuf_unshare(nbuf);
-
 	HTT_TX_TCL_METADATA_VALID_HTT_SET(vdev->htt_tcl_metadata, 1);
 
 	/*
@@ -221,6 +219,12 @@ static uint8_t dp_tx_prepare_htt_metadata(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 
 		/* Fill and add HTT metaheader */
 		hdr = qdf_nbuf_push_head(nbuf, htt_desc_size_aligned);
+		if (hdr == NULL) {
+			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+					"Error in filling HTT metadata\n");
+
+			return 0;
+		}
 		qdf_mem_copy(hdr, desc_ext, htt_desc_size);
 
 	} else if (vdev->opmode == wlan_op_mode_ocb) {
@@ -543,7 +547,12 @@ struct dp_tx_desc_s *dp_tx_prepare_desc_single(struct dp_vdev *vdev,
 	 * start of data through pkt_offset
 	 */
 	align_pad = ((unsigned long) qdf_nbuf_data(nbuf)) & 0x7;
-	qdf_nbuf_push_head(nbuf, align_pad);
+	if (qdf_nbuf_push_head(nbuf, align_pad) == NULL) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				"qdf_nbuf_push_head failed\n");
+		goto failure;
+	}
+
 	tx_desc->pkt_offset = align_pad;
 
 	/*
@@ -579,6 +588,8 @@ struct dp_tx_desc_s *dp_tx_prepare_desc_single(struct dp_vdev *vdev,
 				(vdev->opmode == wlan_op_mode_ocb))) {
 		htt_hdr_size = dp_tx_prepare_htt_metadata(vdev, nbuf,
 				meta_data);
+		if (htt_hdr_size == 0)
+			goto failure;
 		tx_desc->pkt_offset += htt_hdr_size;
 		tx_desc->flags |= DP_TX_DESC_FLAG_TO_FW;
 		is_exception = 1;
@@ -1251,16 +1262,24 @@ static qdf_nbuf_t dp_tx_prepare_sg(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
  * @nbuf: skb
  * @msdu_info: MSDU info to be setup in MSDU descriptor and MSDU extension desc.
  *
- * Return: void
+ * Return: NULL on failure,
+ *         nbuf when extracted successfully
  */
 static
-void dp_tx_extract_mesh_meta_data(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
+qdf_nbuf_t dp_tx_extract_mesh_meta_data(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 				struct dp_tx_msdu_info_s *msdu_info)
 {
 	struct meta_hdr_s *mhdr;
 	struct htt_tx_msdu_desc_ext2_t *meta_data =
 				(struct htt_tx_msdu_desc_ext2_t *)&msdu_info->meta_data[0];
 
+	nbuf = qdf_nbuf_unshare(nbuf);
+	if (nbuf == NULL) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				"qdf_nbuf_unshare failed\n");
+		return nbuf;
+	}
+
 	mhdr = (struct meta_hdr_s *)qdf_nbuf_data(nbuf);
 
 	qdf_mem_set(meta_data, 0, sizeof(struct htt_tx_msdu_desc_ext2_t));
@@ -1296,7 +1315,12 @@ void dp_tx_extract_mesh_meta_data(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 	meta_data->valid_key_flags = 1;
 	meta_data->key_flags = (mhdr->keyix & 0x3);
 
-	qdf_nbuf_pull_head(nbuf, sizeof(struct meta_hdr_s));
+	if (qdf_nbuf_pull_head(nbuf, sizeof(struct meta_hdr_s)) == NULL) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				"qdf_nbuf_pull_head failed\n");
+		qdf_nbuf_free(nbuf);
+		return NULL;
+	}
 
 	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
 			"%s , Meta hdr %0x %0x %0x %0x %0x\n",
@@ -1306,13 +1330,14 @@ void dp_tx_extract_mesh_meta_data(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 			msdu_info->meta_data[3],
 			msdu_info->meta_data[4]);
 
-	return;
+	return nbuf;
 }
 #else
 static
-void dp_tx_extract_mesh_meta_data(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
+qdf_nbuf_t dp_tx_extract_mesh_meta_data(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 				struct dp_tx_msdu_info_s *msdu_info)
 {
+	return nbuf;
 }
 
 #endif
@@ -1379,6 +1404,8 @@ qdf_nbuf_t dp_tx_send(void *vap_dev, qdf_nbuf_t nbuf)
 	struct dp_tx_seg_info_s seg_info;
 	struct dp_vdev *vdev = (struct dp_vdev *) vap_dev;
 	uint16_t peer_id = HTT_INVALID_PEER;
+	qdf_nbuf_t nbuf_mesh = NULL;
+
 	qdf_mem_set(&msdu_info, sizeof(msdu_info), 0x0);
 	qdf_mem_set(&seg_info, sizeof(seg_info), 0x0);
 
@@ -1394,8 +1421,16 @@ qdf_nbuf_t dp_tx_send(void *vap_dev, qdf_nbuf_t nbuf)
 	msdu_info.tid = HTT_TX_EXT_TID_INVALID;
 	DP_STATS_INC_PKT(vdev, tx_i.rcvd, 1, qdf_nbuf_len(nbuf));
 
-	if (qdf_unlikely(vdev->mesh_vdev))
-		dp_tx_extract_mesh_meta_data(vdev, nbuf, &msdu_info);
+	if (qdf_unlikely(vdev->mesh_vdev)) {
+		nbuf_mesh = dp_tx_extract_mesh_meta_data(vdev, nbuf,
+								&msdu_info);
+		if (nbuf_mesh == NULL) {
+			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+					"Extracting mesh metadata failed\n");
+			return nbuf;
+		}
+		nbuf = nbuf_mesh;
+	}
 
 	/*
 	 * Get HW Queue to use for this frame.
@@ -1799,9 +1834,19 @@ void dp_tx_comp_fill_tx_completion_stats(struct dp_tx_desc_s *tx_desc,
 	qdf_nbuf_t netbuf = tx_desc->nbuf;
 
 	if (!tx_desc->msdu_ext_desc) {
-		qdf_nbuf_pull_head(netbuf, tx_desc->pkt_offset);
+		if (qdf_nbuf_pull_head(netbuf, tx_desc->pkt_offset) == NULL) {
+			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				"netbuf %p offset %d\n",
+				netbuf, tx_desc->pkt_offset);
+			return;
+		}
+	}
+	if (qdf_nbuf_push_head(netbuf, sizeof(struct meta_hdr_s)) == NULL) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+			"netbuf %p offset %d\n", netbuf,
+			sizeof(struct meta_hdr_s));
+		return;
 	}
-	qdf_nbuf_push_head(netbuf, sizeof(struct meta_hdr_s));
 
 	mhdr = (struct meta_hdr_s *)qdf_nbuf_data(netbuf);
 	mhdr->rssi = ts->ack_frame_rssi;