diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5605cf6d247b..c3246e989828 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -742,6 +742,11 @@ struct key_params {
  *	chan will define the primary channel and all other
  *	parameters are ignored.
  * @freq1_offset: offset from @center_freq1, in KHz
+ * @ru_punct_bitmap: RU puncturing bitmap. Each bit represents a 20 MHz channel
+ *	with lowest bit corresponding to the smallest frequency. Bit set to 1
+ *	indicates that the channel is punctured, otherwise the channel is active
+ * @ru_punct_bitmap_supp_he: Indicates whether RU puncturing bitmap validation
+ *	should include OFDMA bitmaps.
  */
 struct cfg80211_chan_def {
 	struct ieee80211_channel *chan;
@@ -750,6 +755,8 @@ struct cfg80211_chan_def {
 	u32 center_freq2;
 	struct ieee80211_edmg edmg;
 	u16 freq1_offset;
+	u16 ru_punct_bitmap;
+	bool ru_punct_bitmap_supp_he;
 };
 
 /*
@@ -878,7 +885,10 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
 		chandef1->width == chandef2->width &&
 		chandef1->center_freq1 == chandef2->center_freq1 &&
 		chandef1->freq1_offset == chandef2->freq1_offset &&
-		chandef1->center_freq2 == chandef2->center_freq2);
+		chandef1->center_freq2 == chandef2->center_freq2 &&
+		chandef1->ru_punct_bitmap == chandef2->ru_punct_bitmap &&
+		chandef1->ru_punct_bitmap_supp_he ==
+					chandef2->ru_punct_bitmap_supp_he);
 }
 
 /**
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 8b7fb4a9e07b..4390e9297222 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -32,6 +32,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
 	chandef->center_freq2 = 0;
 	chandef->edmg.bw_config = 0;
 	chandef->edmg.channels = 0;
+	chandef->ru_punct_bitmap = 0;
 
 	switch (chan_type) {
 	case NL80211_CHAN_NO_HT:
@@ -196,6 +197,101 @@ static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
 	return nl80211_chan_width_to_mhz(c->width);
 }
 
+/* IEEE P802.11be/D1.31, December 2021, Table 36-30 5-bit punctured channel
+ * indication for the non-OFDMA case in an EHT MU PPDU
+ */
+static const u16 ru_punct_bitmap_80[] = {0xF, 0xE, 0xD, 0xB, 0x7};
+static const u16 ru_punct_bitmap_160[] = {0xFF, 0xFE, 0xFD, 0xFB, 0xF7, 0xEF,
+					  0xDF, 0xBF, 0x7F, 0xFC, 0xF3, 0xCF,
+					  0x3F};
+static const u16 ru_punct_bitmap_320[] = {0xFFFF, 0xFFFC, 0xFFF3, 0xFFCF,
+					  0xFF3F, 0xFCFF, 0xF3FF, 0xCFFF,
+					  0x3FFF, 0xFFF0, 0xFF0F, 0xF0FF,
+					  0x0FFF, 0xFFC0, 0xFF30, 0xFCF0,
+					  0xF3F0, 0xCFF0, 0x3FF0, 0x0FFC,
+					  0x0FF3, 0x0FCF, 0x0F3F, 0x0CFF,
+					  0x03FF};
+
+bool cfg80211_ru_punct_bitmap_valid(const struct cfg80211_chan_def *chandef)
+{
+	u8 i, non_ofdma_bitmap_count, ofdma_block_count = 1;
+	u16 bitmap, pri_ch_bit_pos;
+	const u16 *non_ofdma_bitmap;
+	u32 start_freq;
+
+	if (!chandef->ru_punct_bitmap) /* All channels active */
+		return true;
+
+	bitmap = ~chandef->ru_punct_bitmap;
+	WARN_ON_ONCE(sizeof(bitmap) != sizeof(chandef->ru_punct_bitmap));
+
+	switch (chandef->width) {
+	case NL80211_CHAN_WIDTH_80:
+		bitmap &= 0xF;
+		non_ofdma_bitmap = &ru_punct_bitmap_80[0];
+		non_ofdma_bitmap_count = ARRAY_SIZE(ru_punct_bitmap_80);
+		start_freq = chandef->center_freq1 - 40;
+		break;
+
+	case NL80211_CHAN_WIDTH_160:
+		bitmap &= 0xFF;
+		non_ofdma_bitmap = &ru_punct_bitmap_160[0];
+		non_ofdma_bitmap_count = ARRAY_SIZE(ru_punct_bitmap_160);
+		ofdma_block_count = 2;
+		start_freq = chandef->center_freq1 - 80;
+		break;
+
+	case NL80211_CHAN_WIDTH_320:
+		bitmap &= 0xFFFF;
+		non_ofdma_bitmap = &ru_punct_bitmap_320[0];
+		non_ofdma_bitmap_count = ARRAY_SIZE(ru_punct_bitmap_320);
+		ofdma_block_count = 4;
+		start_freq = chandef->center_freq1 - 160;
+		break;
+
+	default:
+		return false;
+	}
+
+	if (!bitmap) /* No channel active */
+		return false;
+
+	pri_ch_bit_pos = ((chandef->chan->center_freq - start_freq) / 20);
+	if (!(bitmap & BIT(pri_ch_bit_pos)))
+		return false;
+
+	/* Check for non-OFDMA puncturing patterns */
+	for (i = 0; i < non_ofdma_bitmap_count; i++)
+		if (non_ofdma_bitmap[i] == bitmap)
+			return true;
+
+	if (!chandef->ru_punct_bitmap_supp_he)
+		return false;
+
+	/* Check for OFDMA puncturing patterns */
+	for (i = 0; i < ofdma_block_count; i++) {
+		switch ((bitmap >> (i * 4)) & 0xF) {
+		/* IEEE P802.11be/D1.31, December 2021, 36.3.12.11.2 Preamble
+		 * puncturing for PPDUs in an OFDMA transmission
+		 */
+		case 0xF:
+		case 0x7:
+		case 0xB:
+		case 0xD:
+		case 0xE:
+		case 0x3:
+		case 0xC:
+		case 0x9:
+		case 0x0:
+			break;
+		default:
+			return false;
+		}
+	}
+
+	return true;
+}
+
 bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
 {
 	u32 control_freq, oper_freq;
@@ -316,6 +412,9 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
 	    !cfg80211_edmg_chandef_valid(chandef))
 		return false;
 
+	if (!cfg80211_ru_punct_bitmap_valid(chandef))
+		return false;
+
 	return true;
 }
 EXPORT_SYMBOL(cfg80211_chandef_valid);
