Search Linux Wireless

[PATCH] mac80211: filter multicast data packets on AP_VLAN interfaces w/o sta

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Currently, multicast data packets are dropped on AP interfaces if
there are no authorized stations connected. This avoids superflous
data packets to be transmitted on air.

But when using AP_VLAN, this does not happen, as the current check does
not apply to AP_VLAN interfaces. Though, there can easily be more AP_VLAN
interfaces on an AP resulting in more multicast data frames. This is
especially true since hostapd does not remove no-longer-used AP_VLAN
interfaces and bridges.

In order to filter on AP_VLAN interfaces, a per AP_VLAN interface
counter is required (in constrast to the counter on the AP interface
counting the stations on all related AP_VLAN interfaces as well).

If there are multicast data frames on the AP interface and authorized
stations only on the related AP_VLAN interfaces, these multicast data
frames on the AP interface still won't be filtered.
This is just left unchanged by this patch.

Signed-off-by: Michael Braun <michael-dev@xxxxxxxxxxxxx>
---
 net/mac80211/cfg.c            | 12 ++++++++++++
 net/mac80211/debugfs_netdev.c |  9 +++++++++
 net/mac80211/ieee80211_i.h    |  1 +
 net/mac80211/sta_info.c       | 17 +++++++++++++++++
 net/mac80211/tx.c             |  8 ++++++++
 5 files changed, 47 insertions(+)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 74f509c..53db0c3 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1360,6 +1360,18 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 			prev_4addr = true;
 		}
 
+		if (sta->sta_state == IEEE80211_STA_AUTHORIZED &&
+		    sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+		    !sta->sdata->u.vlan.sta &&
+		    sta->sdata != vlansdata)
+			atomic_dec(&sta->sdata->u.vlan.num_mcast_sta);
+
+		if (sta->sta_state == IEEE80211_STA_AUTHORIZED &&
+		    vlansdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+		    !vlansdata->u.vlan.sta &&
+		    sta->sdata != vlansdata)
+			atomic_inc(&vlansdata->u.vlan.num_mcast_sta);
+
 		sta->sdata = vlansdata;
 
 		if (sta->sta_state == IEEE80211_STA_AUTHORIZED &&
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index c68896a..71b71e2 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -428,6 +428,7 @@ IEEE80211_IF_FILE_RW(uapsd_max_sp_len);
 IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
 IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
 IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);
+IEEE80211_IF_FILE(vlan_num_mcast_sta, u.vlan.num_mcast_sta, ATOMIC);
 
 static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -594,6 +595,11 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 	DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
 }
 
+static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
+{
+	DEBUGFS_ADD(vlan_num_mcast_sta);
+}
+
 static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD_MODE(tsf, 0600);
@@ -697,6 +703,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
 	case NL80211_IFTYPE_AP:
 		add_ap_files(sdata);
 		break;
+	case NL80211_IFTYPE_AP_VLAN:
+		add_vlan_files(sdata);
+		break;
 	case NL80211_IFTYPE_WDS:
 		add_wds_files(sdata);
 		break;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8d53d65..722ad28 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -305,6 +305,7 @@ struct ieee80211_if_vlan {
 
 	/* used for all tx if the VLAN is configured to 4-addr mode */
 	struct sta_info __rcu *sta;
+	atomic_t num_mcast_sta; /* number of stations receiving multicast */
 };
 
 struct mesh_stats {
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 00ca8dc..68f9d2b 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -143,6 +143,17 @@ static void __cleanup_single_sta(struct sta_info *sta)
 		ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
 		kfree(tid_tx);
 	}
+
+	if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
+		if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
+		    (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+		     !sta->sdata->u.vlan.sta))
+			atomic_dec(&sta->sdata->bss->num_mcast_sta);
+		if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+		     !sta->sdata->u.vlan.sta)
+			atomic_dec(&sta->sdata->u.vlan.num_mcast_sta);
+		clear_sta_flag(sta, WLAN_STA_AUTHORIZED);
+	}
 }
 
 static void cleanup_single_sta(struct sta_info *sta)
@@ -1694,6 +1705,9 @@ int sta_info_move_state(struct sta_info *sta,
 			    (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
 			     !sta->sdata->u.vlan.sta))
 				atomic_dec(&sta->sdata->bss->num_mcast_sta);
+			if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+			     !sta->sdata->u.vlan.sta)
+				atomic_dec(&sta->sdata->u.vlan.num_mcast_sta);
 			clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
 		}
 		break;
@@ -1703,6 +1717,9 @@ int sta_info_move_state(struct sta_info *sta,
 			    (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
 			     !sta->sdata->u.vlan.sta))
 				atomic_inc(&sta->sdata->bss->num_mcast_sta);
+			if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+			     !sta->sdata->u.vlan.sta)
+				atomic_inc(&sta->sdata->u.vlan.num_mcast_sta);
 			set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
 		}
 		break;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 07bd8db..ff10e00 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -330,6 +330,14 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 		 * frames.
 		 */
 		return TX_DROP;
+	} else if (unlikely(tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+			    ieee80211_is_data(hdr->frame_control) &&
+			    !atomic_read(&tx->sdata->u.vlan.num_mcast_sta))) {
+		/*
+		 * No associated STAs - no need to send multicast
+		 * frames.
+		 */
+		return TX_DROP;
 	}
 
 	return TX_CONTINUE;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux