From 34f7c699a6bcb5c45f82ceb6743354ad79296078 Mon Sep 17 00:00:00 2001 From: Michael Braun Date: Mon, 31 Oct 2016 14:58:08 +0100 Subject: [PATCH] Add multicast to unicast support This adds support for nl80211 NL80211_CMD_SET_MULTICAST_TO_UNICAST command. By setting the new hostapd configuration option multicast_to_unicast=1, hostapd configures this AP to perform multicast to unicast conversion. When enabled, all multicast packets with ethertype ARP, IPv4, or IPv6 (possibly within an 802.1Q header) will be sent out to each station once with the destination (multicast) MAC address replaced by the station's MAC address. Note that this may break certain expectations of the receiver, e.g., the ability to drop unicast IP packets encapsulated in multicast L2 frames, or the ability to not send destination unreachable messages in such cases. This also does not implement Directed Multicast Service (DMS). Signed-off-by: Michael Braun --- hostapd/config_file.c | 2 ++ hostapd/hostapd.conf | 16 ++++++++++++ src/ap/ap_config.h | 2 ++ src/ap/beacon.c | 1 + src/drivers/driver.h | 21 ++++++++++++++++ src/drivers/driver_nl80211.c | 48 ++++++++++++++++++++++++++++++++++++ 6 files changed, 90 insertions(+) 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,