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 <[email protected]>
---
 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to