[PATCH] wpa_supplicant: always have data frame filtering
Johannes Berg
johannes at sipsolutions.net
Wed Feb 25 08:23:35 PST 2026
From: Johannes Berg <johannes.berg at intel.com>
Always enable IP unicast in L2/WiFi multicast filtering for
all networks (not just HS2.0 non-DGAF ones) by default, but
provide an option to turn it off in case someone finds it
breaks something.
Also provide an option (but off by default) to always (and
not just in HS2.0 networks) rely on proxy ARP/NS if the AP
advertises it and in that case drop gratuitous ARP (IPv4)
and unsolicited NA (IPv6) packets.
Signed-off-by: Johannes Berg <johannes.berg at intel.com>
---
wpa_supplicant/config.c | 3 ++
wpa_supplicant/config_file.c | 2 +
wpa_supplicant/config_ssid.h | 12 ++++++
wpa_supplicant/hs20_supplicant.c | 37 ------------------
wpa_supplicant/hs20_supplicant.h | 1 -
wpa_supplicant/sme.c | 4 +-
wpa_supplicant/wpa_supplicant.c | 63 ++++++++++++++++++++++++++++--
wpa_supplicant/wpa_supplicant.conf | 15 +++++++
wpa_supplicant/wpa_supplicant_i.h | 1 +
9 files changed, 93 insertions(+), 45 deletions(-)
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 623ab720bf52..49101879df82 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2840,6 +2840,8 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(ssid_protection, 0, 1)},
{ INT_RANGE(rsn_overriding, 0, 2)},
{ INT_RANGE(sae_password_id_change, 0, 1)},
+ { INT_RANGE(drop_unicast_ip_in_l2_multicast, 0, 1)},
+ { INT_RANGE(always_use_proxy_arp, 0, 1)},
};
#undef OFFSET
@@ -3405,6 +3407,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->mac_addr = WPAS_MAC_ADDR_STYLE_NOT_SET;
ssid->max_oper_chwidth = DEFAULT_MAX_OPER_CHWIDTH;
ssid->rsn_overriding = RSN_OVERRIDING_NOT_SET;
+ ssid->drop_unicast_ip_in_l2_multicast = 1;
}
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index f9d18137f964..1d96aa6259ad 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1037,6 +1037,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid,
}
}
#endif /* CONFIG_SAE */
+ INT_DEF(drop_unicast_ip_in_l2_multicast, 1);
+ INT_DEF(always_use_proxy_arp, 0);
#undef STR
#undef INT
#undef INT_DEF
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 3f22c44d70f8..dbf4924bb33c 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -1344,6 +1344,18 @@ struct wpa_ssid {
* sae_password_id_change - Whether to use changing SAE password IDs
*/
bool sae_password_id_change;
+
+ /**
+ * drop_unicast_ip_in_l2_multicast - drop unicast IP in L2 multicast
+ * in all networks, not just HS2.0 non-DGAF networks
+ */
+ bool drop_unicast_ip_in_l2_multicast;
+
+ /**
+ * always_use_proxy_arp - always rely on proxy ARP even in non-HS2.0
+ * networks
+ */
+ bool always_use_proxy_arp;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 627935474f42..ef53c4cf361f 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -29,43 +29,6 @@
#include "notify.h"
-void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s)
-{
- struct wpa_bss *bss = wpa_s->current_bss;
- const u8 *ie;
- const u8 *ext_capa;
- u32 filter = 0;
-
- if (!bss || !is_hs20_network(wpa_s, wpa_s->current_ssid, bss)) {
- /* Not configuring frame filtering - BSS is not a Hotspot 2.0
- * network */
- return;
- }
-
- ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE);
-
- /* Check if DGAF disabled bit is zero (5th byte in the IE) */
- if (!ie || ie[1] < 5)
- wpa_printf(MSG_DEBUG,
- "Not configuring frame filtering - Can't extract DGAF bit");
- else if (!(ie[6] & HS20_DGAF_DISABLED))
- filter |= WPA_DATA_FRAME_FILTER_FLAG_GTK;
-
- ext_capa = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
- if (!ext_capa || ext_capa[1] < 2) {
- wpa_printf(MSG_DEBUG,
- "Not configuring frame filtering - Can't extract Proxy ARP bit");
- return;
- }
-
- if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_PROXY_ARP))
- filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP |
- WPA_DATA_FRAME_FILTER_FLAG_NA;
-
- wpa_drv_configure_frame_filters(wpa_s, filter);
-}
-
-
void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id, int ap_release)
{
int release;
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index ce12bfb0ee0b..0bfdd847e7e5 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -8,7 +8,6 @@
#ifndef HS20_SUPPLICANT_H
#define HS20_SUPPLICANT_H
-void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s);
void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id,
int ap_release);
void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf,
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 09b0c0582489..bc7d5f8ade7f 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1176,9 +1176,7 @@ no_fils:
if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s);
-#ifdef CONFIG_HS20
- hs20_configure_frame_filters(wpa_s);
-#endif /* CONFIG_HS20 */
+ wpas_configure_frame_filters(wpa_s);
#ifdef CONFIG_P2P
/*
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 878bd8b67472..0e146aec724e 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -4050,11 +4050,12 @@ static u8 * wpas_populate_assoc_ies(
}
wpabuf_free(hs20);
- hs20_configure_frame_filters(wpa_s);
}
}
#endif /* CONFIG_HS20 */
+ wpas_configure_frame_filters(wpa_s);
+
if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
size_t len;
@@ -5044,9 +5045,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
#endif /* CONFIG_P2P */
ssid->bssid_set) {
wpa_s->current_bss = bss;
-#ifdef CONFIG_HS20
- hs20_configure_frame_filters(wpa_s);
-#endif /* CONFIG_HS20 */
+ wpas_configure_frame_filters(wpa_s);
}
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
@@ -10226,3 +10225,59 @@ void wpas_update_dfs_ap_info(struct wpa_supplicant *wpa_s, int freq,
disconnect_evt);
#endif /* CONFIG_P2P */
}
+
+
+void wpas_configure_frame_filters(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss = wpa_s->current_bss;
+ const u8 *ie;
+ const u8 *ext_capa;
+ u32 filter = 0;
+ bool hs20;
+
+ if (!bss)
+ return;
+
+#ifdef CONFIG_HS20
+ hs20 = is_hs20_network(wpa_s, wpa_s->current_ssid, bss);
+#else
+ hs20 = false;
+#endif
+
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->drop_unicast_ip_in_l2_multicast) {
+ filter |= WPA_DATA_FRAME_FILTER_FLAG_GTK;
+ } else {
+ if (!hs20) {
+ /* Not configuring frame filtering - BSS is not a
+ * Hotspot 2.0 network */
+ return;
+ }
+
+ ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE);
+
+ /* Check if DGAF disabled bit is zero (5th byte in the IE) */
+ if (!ie || ie[1] < 5)
+ wpa_printf(MSG_DEBUG,
+ "Not configuring frame filtering - Can't extract DGAF bit");
+ else if (!(ie[6] & HS20_DGAF_DISABLED))
+ filter |= WPA_DATA_FRAME_FILTER_FLAG_GTK;
+ }
+
+ if (!hs20 && wpa_s->current_ssid &&
+ !wpa_s->current_ssid->always_use_proxy_arp)
+ return;
+
+ ext_capa = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
+ if (!ext_capa || ext_capa[1] < 2) {
+ wpa_printf(MSG_DEBUG,
+ "Not configuring frame filtering - Can't extract Proxy ARP bit");
+ return;
+ }
+
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_PROXY_ARP))
+ filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP |
+ WPA_DATA_FRAME_FILTER_FLAG_NA;
+
+ wpa_drv_configure_frame_filters(wpa_s, filter);
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 2ff7b2ebeb31..de6ca39c84fd 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1795,6 +1795,21 @@ fast_reauth=1
# 2 = Supports Multi-AP profile 2 as defined in Wi-Fi EasyMesh specification
#multi_ap_profile=2
+# IP unicast in L2 multicast frame filtering
+# Allow turning off IP unicast in L2 multicast frame filtering,
+# which is enabled by default. This option can also be given in
+# the global section to apply to all network blocks.
+#drop_unicast_ip_in_l2_multicast=1
+
+# Proxy ARP/NS reliance
+# Enable Proxy ARP/NS reliance, dropping gratuitous ARP and unsolicited NA
+# frames when the AP supports proxy ARP even on networks that aren't HS2.0.
+# Note the Proxy ARP/NS support is required, and therefore checked in the
+# AP's extended capabilities. If the AP/network doesn't support it, nothing
+# will be filtered. This option can also be given in the global section to
+# apply to all network blocks.
+#always_use_proxy_arp=0
+
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 3d0f4a69029a..dbb33961bcd9 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -2104,5 +2104,6 @@ int wpas_get_owe_trans_network(const u8 *owe_ie, const u8 **bssid,
void wpas_update_dfs_ap_info(struct wpa_supplicant *wpa_s, int freq,
enum chan_width ap_ch_width,
bool disconnect_evt);
+void wpas_configure_frame_filters(struct wpa_supplicant *wpa_s);
#endif /* WPA_SUPPLICANT_I_H */
--
2.53.0
More information about the Hostap
mailing list