diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 65f1eb9b5..832ff5517 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -3560,6 +3560,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, } bss->fils_cache_id_set = 1; #endif /* CONFIG_FILS */ + } else if (os_strcmp(buf, "multicast_to_unicast") == 0) { + bss->multicast_to_unicast = atoi(pos); } else { wpa_printf(MSG_ERROR, "Line %d: unknown configuration item '%s'", diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 9ea3d6c96..1fd4fcc95 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -495,6 +495,22 @@ wmm_ac_vo_acm=0 # :: #bss_load_test=12:80:20000 +# Multicast to unicast conversion +# Request that the AP will do multicast-to-unicast conversion for ARP, IPv4, and +# IPv6 frames (possibly within 802.1Q). If enabled, such frames are to be sent +# to each station separately, with the DA replaced by their own MAC address +# rather than the group address. +# +# Note that this may break certain expectations of the receiver, such as the +# ability to drop unicast IP packets received within multicast L2 frames, or the +# ability to not send ICMP destination unreachable messages for packets received +# in L2 multicast (which is required, but the receiver can't tell the difference +# if this new option is enabled). +# +# This also doesn't implement the 802.11 DMS (directed multicast service). +# +#multicast_to_unicast=0 + ##### IEEE 802.11n related configuration ###################################### # ieee80211n: Whether IEEE 802.11n (HT) is enabled diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index b56bb3109..7d8f28317 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -601,6 +601,8 @@ struct hostapd_bss_config { u8 fils_cache_id[FILS_CACHE_ID_LEN]; int fils_cache_id_set; #endif /* CONFIG_FILS */ + + int multicast_to_unicast; }; diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 5b708f5ea..3788a9764 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -1288,6 +1288,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, params->osen = 1; } #endif /* CONFIG_HS20 */ + params->multicast_to_unicast = hapd->conf->multicast_to_unicast; params->pbss = hapd->conf->pbss; return 0; } diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 71ad0069e..212f16ca0 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1170,6 +1170,27 @@ struct wpa_driver_ap_params { * infrastructure BSS. Valid only for DMG network. */ int pbss; + + /** + * multicast_to_unicast - Whether to use multicast_to_unicast + * + * If this is non-zero, the AP is requested to perform multicast to + * unicast conversion for ARP, IPv4, and IPv6 frames (possibly within + * 802.1Q). If enabled, such frames are to be sent to each station + * separately, with the DA replaced by their own MAC address rather + * than the group address. + * + * Note that this may break certain expectations of the receiver, such + * as the ability to drop unicast IP packets received within multicast + * L2 frames, or the ability to not send ICMP destination unreachable + * messages for packets received in L2 multicast (which is required, + * but the receiver can't tell the difference if this new option is + * enabled.) + * + * This also doesn't implement the 802.11 DMS (directed multicast + * service). + */ + int multicast_to_unicast; }; struct wpa_driver_mesh_bss_params { diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 6bd984d56..b23c440fd 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -3666,6 +3666,52 @@ static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags, } +static int nl80211_set_multicast_to_unicast(struct i802_bss *bss, + int multicast_to_unicast) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + + msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_MULTICAST_TO_UNICAST); + if (!msg || + (multicast_to_unicast && + nla_put_flag(msg, NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED))) { + wpa_printf(MSG_ERROR, + "nl80211: Failed to build NL80211_CMD_SET_MULTICAST_TO_UNICAST msg for %s", + bss->ifname); + nlmsg_free(msg); + return -ENOBUFS; + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + + switch (ret) { + case 0: + wpa_printf(MSG_DEBUG, + "nl80211: multicast to unicast %s on interface %s", + multicast_to_unicast ? "enabled" : "disabled", + bss->ifname); + break; + case -EOPNOTSUPP: + if (!multicast_to_unicast) + break; + wpa_printf(MSG_INFO, + "nl80211: multicast to unicast not supported on interface %s", + bss->ifname); + break; + default: + wpa_printf(MSG_ERROR, + "nl80211: %s multicast to unicast failed with %d (%s) on interface %s", + multicast_to_unicast ? "enabling" : "disabling", + ret, strerror(-ret), bss->ifname); + break; + } + + return ret; +} + + static int wpa_driver_nl80211_set_ap(void *priv, struct wpa_driver_ap_params *params) { @@ -3885,6 +3931,8 @@ static int wpa_driver_nl80211_set_ap(void *priv, nl80211_set_bss(bss, params->cts_protect, params->preamble, params->short_slot_time, params->ht_opmode, params->isolate, params->basic_rates); + nl80211_set_multicast_to_unicast(bss, + params->multicast_to_unicast); if (beacon_set && params->freq && params->freq->bandwidth != bss->bandwidth) { wpa_printf(MSG_DEBUG,