Commit 72f15d53 authored by Michael Braun's avatar Michael Braun Committed by Johannes Berg

mac80211: filter multicast data packets on AP / AP_VLAN

This patch adds filtering for multicast data packets on AP_VLAN
interfaces that have no authorized station connected and changes
filtering on AP interfaces to not count stations assigned to
AP_VLAN interfaces.

This saves airtime and avoids waking up other stations currently
authorized in this BSS. When using WPA, the packets dropped could
not be decrypted by any station.

The behaviour when there are no AP_VLAN interfaces is left unchanged.

When there are AP_VLAN interfaces, this patch
1. adds filtering multicast data packets sent on AP_VLAN interfaces
   that have no authorized station connected.
   No filtering happens on 4addr AP_VLAN interfaces.
2. makes filtering of multicast data packets sent on AP interfaces
   depend on the number of authorized stations in this bss not
   assigned to an AP_VLAN interface.

Therefore, a new num_mcast_sta counter is added for AP_VLAN interfaces.
The existing one for AP interfaces is altered to not track stations
assigned to an AP_VLAN interface.

The new counter is exposed in debugfs.
Signed-off-by: default avatarMichael Braun <michael-dev@fami-braun.de>
[reformat commit message a bit, unline ieee80211_vif_{inc,dec}_num_mcast]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 5f9994bd
...@@ -1520,9 +1520,6 @@ static int ieee80211_change_station(struct wiphy *wiphy, ...@@ -1520,9 +1520,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
goto out_err; goto out_err;
if (params->vlan && params->vlan != sta->sdata->dev) { if (params->vlan && params->vlan != sta->sdata->dev) {
bool prev_4addr = false;
bool new_4addr = false;
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
if (params->vlan->ieee80211_ptr->use_4addr) { if (params->vlan->ieee80211_ptr->use_4addr) {
...@@ -1532,26 +1529,21 @@ static int ieee80211_change_station(struct wiphy *wiphy, ...@@ -1532,26 +1529,21 @@ static int ieee80211_change_station(struct wiphy *wiphy,
} }
rcu_assign_pointer(vlansdata->u.vlan.sta, sta); rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
new_4addr = true;
__ieee80211_check_fast_rx_iface(vlansdata); __ieee80211_check_fast_rx_iface(vlansdata);
} }
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
sta->sdata->u.vlan.sta) { sta->sdata->u.vlan.sta)
RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL); RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL);
prev_4addr = true;
} if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
ieee80211_vif_dec_num_mcast(sta->sdata);
sta->sdata = vlansdata; sta->sdata = vlansdata;
ieee80211_check_fast_xmit(sta); ieee80211_check_fast_xmit(sta);
if (sta->sta_state == IEEE80211_STA_AUTHORIZED && if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
prev_4addr != new_4addr) { ieee80211_vif_inc_num_mcast(sta->sdata);
if (new_4addr)
atomic_dec(&sta->sdata->bss->num_mcast_sta);
else
atomic_inc(&sta->sdata->bss->num_mcast_sta);
}
ieee80211_send_layer2_update(sta); ieee80211_send_layer2_update(sta);
} }
......
...@@ -477,6 +477,7 @@ IEEE80211_IF_FILE_RW(tdls_wider_bw); ...@@ -477,6 +477,7 @@ IEEE80211_IF_FILE_RW(tdls_wider_bw);
IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC); 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(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC); IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);
IEEE80211_IF_FILE(num_mcast_sta_vlan, u.vlan.num_mcast_sta, ATOMIC);
static ssize_t ieee80211_if_fmt_num_buffered_multicast( static ssize_t ieee80211_if_fmt_num_buffered_multicast(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
...@@ -684,6 +685,13 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) ...@@ -684,6 +685,13 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD_MODE(tkip_mic_test, 0200); DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
} }
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
{
/* add num_mcast_sta_vlan using name num_mcast_sta */
debugfs_create_file("num_mcast_sta", 0400, sdata->vif.debugfs_dir,
sdata, &num_mcast_sta_vlan_ops);
}
static void add_ibss_files(struct ieee80211_sub_if_data *sdata) static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_ADD_MODE(tsf, 0600); DEBUGFS_ADD_MODE(tsf, 0600);
...@@ -787,6 +795,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata) ...@@ -787,6 +795,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
add_ap_files(sdata); add_ap_files(sdata);
break; break;
case NL80211_IFTYPE_AP_VLAN:
add_vlan_files(sdata);
break;
case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_WDS:
add_wds_files(sdata); add_wds_files(sdata);
break; break;
......
...@@ -307,6 +307,7 @@ struct ieee80211_if_vlan { ...@@ -307,6 +307,7 @@ struct ieee80211_if_vlan {
/* used for all tx if the VLAN is configured to 4-addr mode */ /* used for all tx if the VLAN is configured to 4-addr mode */
struct sta_info __rcu *sta; struct sta_info __rcu *sta;
atomic_t num_mcast_sta; /* number of stations receiving multicast */
}; };
struct mesh_stats { struct mesh_stats {
...@@ -1527,6 +1528,23 @@ ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status) ...@@ -1527,6 +1528,23 @@ ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status)
return false; return false;
} }
void ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata);
void ieee80211_vif_dec_num_mcast(struct ieee80211_sub_if_data *sdata);
/* This function returns the number of multicast stations connected to this
* interface. It returns -1 if that number is not tracked, that is for netdevs
* not in AP or AP_VLAN mode or when using 4addr.
*/
static inline int
ieee80211_vif_get_num_mcast_if(struct ieee80211_sub_if_data *sdata)
{
if (sdata->vif.type == NL80211_IFTYPE_AP)
return atomic_read(&sdata->u.ap.num_mcast_sta);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
return atomic_read(&sdata->u.vlan.num_mcast_sta);
return -1;
}
u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
struct ieee80211_rx_status *status, struct ieee80211_rx_status *status,
unsigned int mpdu_len, unsigned int mpdu_len,
......
...@@ -2005,3 +2005,19 @@ void ieee80211_iface_exit(void) ...@@ -2005,3 +2005,19 @@ void ieee80211_iface_exit(void)
{ {
unregister_netdevice_notifier(&mac80211_netdev_notifier); unregister_netdevice_notifier(&mac80211_netdev_notifier);
} }
void ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata)
{
if (sdata->vif.type == NL80211_IFTYPE_AP)
atomic_inc(&sdata->u.ap.num_mcast_sta);
else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
atomic_inc(&sdata->u.vlan.num_mcast_sta);
}
void ieee80211_vif_dec_num_mcast(struct ieee80211_sub_if_data *sdata)
{
if (sdata->vif.type == NL80211_IFTYPE_AP)
atomic_dec(&sdata->u.ap.num_mcast_sta);
else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
atomic_dec(&sdata->u.vlan.num_mcast_sta);
}
...@@ -2215,7 +2215,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) ...@@ -2215,7 +2215,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) { (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
if (is_multicast_ether_addr(ehdr->h_dest)) { if (is_multicast_ether_addr(ehdr->h_dest) &&
ieee80211_vif_get_num_mcast_if(sdata) != 0) {
/* /*
* send multicast frames both to higher layers in * send multicast frames both to higher layers in
* local net stack and back to the wireless medium * local net stack and back to the wireless medium
...@@ -2224,7 +2225,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) ...@@ -2224,7 +2225,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
if (!xmit_skb) if (!xmit_skb)
net_info_ratelimited("%s: failed to clone multicast frame\n", net_info_ratelimited("%s: failed to clone multicast frame\n",
dev->name); dev->name);
} else { } else if (!is_multicast_ether_addr(ehdr->h_dest)) {
dsta = sta_info_get(sdata, skb->data); dsta = sta_info_get(sdata, skb->data);
if (dsta) { if (dsta) {
/* /*
......
...@@ -1871,10 +1871,7 @@ int sta_info_move_state(struct sta_info *sta, ...@@ -1871,10 +1871,7 @@ int sta_info_move_state(struct sta_info *sta,
if (!sta->sta.support_p2p_ps) if (!sta->sta.support_p2p_ps)
ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
if (sta->sdata->vif.type == NL80211_IFTYPE_AP || ieee80211_vif_dec_num_mcast(sta->sdata);
(sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
!sta->sdata->u.vlan.sta))
atomic_dec(&sta->sdata->bss->num_mcast_sta);
clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_clear_fast_xmit(sta); ieee80211_clear_fast_xmit(sta);
ieee80211_clear_fast_rx(sta); ieee80211_clear_fast_rx(sta);
...@@ -1882,10 +1879,7 @@ int sta_info_move_state(struct sta_info *sta, ...@@ -1882,10 +1879,7 @@ int sta_info_move_state(struct sta_info *sta,
break; break;
case IEEE80211_STA_AUTHORIZED: case IEEE80211_STA_AUTHORIZED:
if (sta->sta_state == IEEE80211_STA_ASSOC) { if (sta->sta_state == IEEE80211_STA_ASSOC) {
if (sta->sdata->vif.type == NL80211_IFTYPE_AP || ieee80211_vif_inc_num_mcast(sta->sdata);
(sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
!sta->sdata->u.vlan.sta))
atomic_inc(&sta->sdata->bss->num_mcast_sta);
set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_check_fast_xmit(sta); ieee80211_check_fast_xmit(sta);
ieee80211_check_fast_rx(sta); ieee80211_check_fast_rx(sta);
......
...@@ -331,9 +331,8 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) ...@@ -331,9 +331,8 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
return TX_DROP; return TX_DROP;
} }
} else if (unlikely(tx->sdata->vif.type == NL80211_IFTYPE_AP && } else if (unlikely(ieee80211_is_data(hdr->frame_control) &&
ieee80211_is_data(hdr->frame_control) && ieee80211_vif_get_num_mcast_if(tx->sdata) == 0)) {
!atomic_read(&tx->sdata->u.ap.num_mcast_sta))) {
/* /*
* No associated STAs - no need to send multicast * No associated STAs - no need to send multicast
* frames. * frames.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment