diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 40b6375a5de4..bd6b0056ce42 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -583,15 +583,20 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
 EXPORT_SYMBOL(cfg80211_chandef_compatible);
 
 static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
-					 u32 bandwidth,
+					 u32 bandwidth, u16 punctured,
 					 enum nl80211_dfs_state dfs_state)
 {
 	struct ieee80211_channel *c;
 	u32 freq;
+	int subchan = 0;
 
 	for (freq = center_freq - bandwidth/2 + 10;
 	     freq <= center_freq + bandwidth/2 - 10;
 	     freq += 20) {
+		if (punctured & BIT(subchan))
+			continue;
+		subchan++;
+
 		c = ieee80211_get_channel(wiphy, freq);
 		if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
 			continue;
@@ -615,40 +620,12 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
 		return;
 
 	cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
-				     width, dfs_state);
+				     width, chandef->punctured, dfs_state);
 
 	if (!chandef->center_freq2)
 		return;
 	cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
-				     width, dfs_state);
-}
-
-static u32 cfg80211_get_start_freq(u32 center_freq,
-				   u32 bandwidth)
-{
-	u32 start_freq;
-
-	bandwidth = MHZ_TO_KHZ(bandwidth);
-	if (bandwidth <= MHZ_TO_KHZ(20))
-		start_freq = center_freq;
-	else
-		start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
-
-	return start_freq;
-}
-
-static u32 cfg80211_get_end_freq(u32 center_freq,
-				 u32 bandwidth)
-{
-	u32 end_freq;
-
-	bandwidth = MHZ_TO_KHZ(bandwidth);
-	if (bandwidth <= MHZ_TO_KHZ(20))
-		end_freq = center_freq;
-	else
-		end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
-
-	return end_freq;
+				     width, 0, dfs_state);
 }
 
 static bool
@@ -727,24 +704,20 @@ static bool cfg80211_dfs_permissive_chan(struct wiphy *wiphy,
 static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
 					    u32 center_freq,
 					    u32 bandwidth,
+					    u16 punctured,
 					    enum nl80211_iftype iftype)
 {
-	struct ieee80211_channel *c;
-	u32 freq, start_freq, end_freq;
-
-	start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
-	end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+	struct ieee80211_channel *subchan;
 
-	for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
-		c = ieee80211_get_channel_khz(wiphy, freq);
-		if (!c)
-			return -EINVAL;
-
-		if (c->flags & IEEE80211_CHAN_RADAR &&
-		    !cfg80211_dfs_permissive_chan(wiphy, iftype, c))
+	for_each_subchan(wiphy, center_freq, bandwidth, punctured, subchan) {
+		if ((subchan->flags & IEEE80211_CHAN_RADAR) &&
+		    !cfg80211_dfs_permissive_chan(wiphy, iftype, subchan))
 			return 1;
 	}
 
+	if (subchan && IS_ERR(subchan))
+		return PTR_ERR(subchan);
+
 	return 0;
 }
 
@@ -770,7 +743,8 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
 
 		ret = cfg80211_get_chans_dfs_required(wiphy,
 					ieee80211_chandef_to_khz(chandef),
-					width, iftype);
+					width, chandef->punctured, iftype);
+
 		if (ret < 0)
 			return ret;
 		else if (ret > 0)
@@ -781,7 +755,8 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
 
 		ret = cfg80211_get_chans_dfs_required(wiphy,
 					MHZ_TO_KHZ(chandef->center_freq2),
-					width, iftype);
+					width, 0, iftype);
+
 		if (ret < 0)
 			return ret;
 		else if (ret > 0)
@@ -808,38 +783,33 @@ EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
 
 static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
 					 u32 center_freq,
-					 u32 bandwidth)
+					 u32 bandwidth, u16 punctured)
 {
-	struct ieee80211_channel *c;
-	u32 freq, start_freq, end_freq;
+	struct ieee80211_channel *subchan;
 	int count = 0;
 
-	start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
-	end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
-
 	/*
 	 * Check entire range of channels for the bandwidth.
 	 * Check all channels are DFS channels (DFS_USABLE or
 	 * DFS_AVAILABLE). Return number of usable channels
 	 * (require CAC). Allow DFS and non-DFS channel mix.
 	 */
-	for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
-		c = ieee80211_get_channel_khz(wiphy, freq);
-		if (!c)
-			return -EINVAL;
-
-		if (c->flags & IEEE80211_CHAN_DISABLED)
+	for_each_subchan(wiphy, center_freq, bandwidth, punctured, subchan) {
+		if (subchan->flags & IEEE80211_CHAN_DISABLED)
 			return -EINVAL;
 
-		if (c->flags & IEEE80211_CHAN_RADAR) {
-			if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
+		if (subchan->flags & IEEE80211_CHAN_RADAR) {
+			if (subchan->dfs_state == NL80211_DFS_UNAVAILABLE)
 				return -EINVAL;
 
-			if (c->dfs_state == NL80211_DFS_USABLE)
+			if (subchan->dfs_state == NL80211_DFS_USABLE)
 				count++;
 		}
 	}
 
+	if (subchan && IS_ERR(subchan))
+		return PTR_ERR(subchan);
+
 	return count;
 }
 
@@ -858,7 +828,7 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
 
 	r1 = cfg80211_get_chans_dfs_usable(wiphy,
 					   MHZ_TO_KHZ(chandef->center_freq1),
-					   width);
+					   width, chandef->punctured);
 
 	if (r1 < 0)
 		return false;
@@ -868,7 +838,7 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
 		WARN_ON(!chandef->center_freq2);
 		r2 = cfg80211_get_chans_dfs_usable(wiphy,
 					MHZ_TO_KHZ(chandef->center_freq2),
-					width);
+					width, 0);
 		if (r2 < 0)
 			return false;
 		break;
@@ -1053,37 +1023,32 @@ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
 
 static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
 					     u32 center_freq,
-					     u32 bandwidth)
+					     u32 bandwidth, u16 punctured)
 {
-	struct ieee80211_channel *c;
-	u32 freq, start_freq, end_freq;
+	struct ieee80211_channel *subchan;
 	bool dfs_offload;
 
 	dfs_offload = wiphy_ext_feature_isset(wiphy,
 					      NL80211_EXT_FEATURE_DFS_OFFLOAD);
 
-	start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
-	end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
-
 	/*
 	 * Check entire range of channels for the bandwidth.
 	 * If any channel in between is disabled or has not
 	 * had gone through CAC return false
 	 */
-	for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
-		c = ieee80211_get_channel_khz(wiphy, freq);
-		if (!c)
+	for_each_subchan(wiphy, center_freq, bandwidth, punctured, subchan) {
+		if (subchan->flags & IEEE80211_CHAN_DISABLED)
 			return false;
 
-		if (c->flags & IEEE80211_CHAN_DISABLED)
-			return false;
-
-		if ((c->flags & IEEE80211_CHAN_RADAR) &&
-		    (c->dfs_state != NL80211_DFS_AVAILABLE) &&
-		    !(c->dfs_state == NL80211_DFS_USABLE && dfs_offload))
+		if ((subchan->flags & IEEE80211_CHAN_RADAR) &&
+		    subchan->dfs_state != NL80211_DFS_AVAILABLE &&
+		    !(subchan->dfs_state == NL80211_DFS_USABLE && dfs_offload))
 			return false;
 	}
 
+	if (subchan && IS_ERR(subchan))
+		return false;
+
 	return true;
 }
 
@@ -1102,7 +1067,7 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
 
 	r = cfg80211_get_chans_dfs_available(wiphy,
 					     MHZ_TO_KHZ(chandef->center_freq1),
-					     width);
+					     width, chandef->punctured);
 
 	/* If any of channels unavailable for cf1 just return */
 	if (!r)
@@ -1113,7 +1078,7 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
 		WARN_ON(!chandef->center_freq2);
 		r = cfg80211_get_chans_dfs_available(wiphy,
 					MHZ_TO_KHZ(chandef->center_freq2),
-					width);
+					width, 0);
 		break;
 	default:
 		WARN_ON(chandef->center_freq2);
@@ -1125,30 +1090,25 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
 
 static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
 						    u32 center_freq,
-						    u32 bandwidth)
+						    u32 bandwidth, u16 punctured)
 {
-	struct ieee80211_channel *c;
-	u32 start_freq, end_freq, freq;
+	struct ieee80211_channel *subchan;
 	unsigned int dfs_cac_ms = 0;
 
-	start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
-	end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
-
-	for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
-		c = ieee80211_get_channel_khz(wiphy, freq);
-		if (!c)
-			return 0;
-
-		if (c->flags & IEEE80211_CHAN_DISABLED)
+	for_each_subchan(wiphy, center_freq, bandwidth, punctured, subchan) {
+		if (subchan->flags & IEEE80211_CHAN_DISABLED)
 			return 0;
 
-		if (!(c->flags & IEEE80211_CHAN_RADAR))
+		if (!(subchan->flags & IEEE80211_CHAN_RADAR))
 			continue;
 
-		if (c->dfs_cac_ms > dfs_cac_ms)
-			dfs_cac_ms = c->dfs_cac_ms;
+		if (subchan->dfs_cac_ms > dfs_cac_ms)
+			dfs_cac_ms = subchan->dfs_cac_ms;
 	}
 
+	if (subchan && IS_ERR(subchan))
+		return 0;
+
 	return dfs_cac_ms;
 }
 
@@ -1168,14 +1128,14 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
 
 	t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
 					     MHZ_TO_KHZ(chandef->center_freq1),
-					     width);
+					     width, chandef->punctured);
 
 	if (!chandef->center_freq2)
 		return t1;
 
 	t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
 					     MHZ_TO_KHZ(chandef->center_freq2),
-					     width);
+					     width, 0);
 
 	return max(t1, t2);
 }
@@ -1183,25 +1143,21 @@ EXPORT_SYMBOL(cfg80211_chandef_dfs_cac_time);
 
 static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
 					u32 center_freq, u32 bandwidth,
-					u32 prohibited_flags,
+					u16 punctured, u32 prohibited_flags,
 					u32 permitting_flags)
 {
-	struct ieee80211_channel *c;
-	u32 freq, start_freq, end_freq;
-
-	start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
-	end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+	struct ieee80211_channel *subchan;
 
-	for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
-		c = ieee80211_get_channel_khz(wiphy, freq);
-		if (!c)
-			return false;
-		if (c->flags & permitting_flags)
+	for_each_subchan(wiphy, center_freq, bandwidth, punctured, subchan) {
+		if (subchan->flags & permitting_flags)
 			continue;
-		if (c->flags & prohibited_flags)
+		if (subchan->flags & prohibited_flags)
 			return false;
 	}
 
+	if (subchan && IS_ERR(subchan))
+		return false;
+
 	return true;
 }
 
@@ -1423,7 +1379,8 @@ bool _cfg80211_chandef_usable(struct wiphy *wiphy,
 
 	if (!cfg80211_secondary_chans_ok(wiphy,
 					 ieee80211_chandef_to_khz(chandef),
-					 width, prohibited_flags,
+					 width, chandef->punctured,
+					 prohibited_flags,
 					 permitting_flags))
 		return false;
 
@@ -1431,7 +1388,7 @@ bool _cfg80211_chandef_usable(struct wiphy *wiphy,
 		return true;
 	return cfg80211_secondary_chans_ok(wiphy,
 					   MHZ_TO_KHZ(chandef->center_freq2),
-					   width, prohibited_flags,
+					   width, 0, prohibited_flags,
 					   permitting_flags);
 }
 
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 4c45f994a8c0..f4583e0494d7 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -505,6 +505,18 @@ bool _cfg80211_chandef_usable(struct wiphy *wiphy,
 			      u32 prohibited_flags,
 			      u32 permitting_flags);
 
+#define for_each_subchan(wiphy, center_freq, bandwidth, punctured,	\
+			       subchan)						\
+	for (subchan = ieee80211_next_subchan(wiphy, center_freq, bandwidth,	\
+					      punctured, NULL);			\
+	     subchan && !IS_ERR(subchan);					\
+	     subchan = ieee80211_next_subchan(wiphy, center_freq, bandwidth,	\
+					      punctured, subchan))
+
+struct ieee80211_channel *
+ieee80211_next_subchan(struct wiphy *wiphy, u32 center_freq, u32 bandwidth,
+		       u16 punctured, struct ieee80211_channel *subchan);
+
 static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
 {
 	unsigned long end = jiffies;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 040d62051eb9..2e2f362b7548 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -184,6 +184,70 @@ struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(ieee80211_get_channel_khz);
 
+static u32 cfg80211_get_start_freq(u32 center_freq,
+				   u32 bandwidth)
+{
+	u32 start_freq;
+
+	bandwidth = MHZ_TO_KHZ(bandwidth);
+	if (bandwidth <= MHZ_TO_KHZ(20))
+		start_freq = center_freq;
+	else
+		start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
+
+	return start_freq;
+}
+
+static u32 cfg80211_get_end_freq(u32 center_freq,
+				 u32 bandwidth)
+{
+	u32 end_freq;
+
+	bandwidth = MHZ_TO_KHZ(bandwidth);
+	if (bandwidth <= MHZ_TO_KHZ(20))
+		end_freq = center_freq;
+	else
+		end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
+
+	return end_freq;
+}
+
+struct ieee80211_channel *ieee80211_next_subchan(struct wiphy *wiphy,
+						 u32 center_freq, u32 bandwidth,
+						 u16 punctured,
+						 struct ieee80211_channel *subchan)
+{
+	struct ieee80211_channel *next_subchan;
+	u32 freq, start_freq, end_freq;
+	int pos;
+
+	start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+	end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+
+	if (!subchan) {
+		freq = start_freq;
+	} else {
+		freq = ieee80211_channel_to_khz(subchan);
+		freq += MHZ_TO_KHZ(20);
+	}
+
+	while (freq <= end_freq) {
+		next_subchan = ieee80211_get_channel_khz(wiphy, freq);
+
+		if (!next_subchan)
+			return ERR_PTR(-EINVAL);
+
+		pos = (freq - start_freq) / MHZ_TO_KHZ(20);
+
+		if (!(punctured & BIT(pos)))
+			return next_subchan;
+
+		freq += MHZ_TO_KHZ(20);
+	}
+
+	return NULL;
+}
+
 static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
 {
 	int i, want;
