From: Michael Braun <michael-dev@xxxxxxxxxxxxx> Enable using a different interface for RRB messages. In order to receive messages for the local BSSID (FT_OVER_DS), that interface needs to have the mac address configured as BSSID. If hostapd is build with IEEE80211R_MACVLAN, hostapd will add and use an macvlan interface on top of ft_iface. Signed-off-by: Michael Braun <michael-dev@xxxxxxxxxxxxx> --- hostapd/Makefile | 17 +++++++ hostapd/config_file.c | 4 ++ hostapd/defconfig | 5 ++ hostapd/hostapd.conf | 28 +++++++++++ src/ap/ap_config.h | 6 +++ src/ap/macvlan.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ src/ap/macvlan.h | 10 ++++ src/ap/wpa_auth_glue.c | 40 +++++++++++++-- 8 files changed, 237 insertions(+), 3 deletions(-) create mode 100644 src/ap/macvlan.c create mode 100644 src/ap/macvlan.h diff --git a/hostapd/Makefile b/hostapd/Makefile index 20f7ef3..47ba052 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -296,6 +296,10 @@ endif ifdef CONFIG_IEEE80211R CFLAGS += -DCONFIG_IEEE80211R OBJS += ../src/ap/wpa_auth_ft.o +ifdef CONFIG_IEEE80211R_MACVLAN +CFLAGS += -DCONFIG_IEEE80211R_MACVLAN +NEED_MACVLAN=y +endif NEED_SHA256=y NEED_AES_OMAC1=y NEED_AES_UNWRAP=y @@ -851,6 +855,19 @@ endif endif endif +ifdef NEED_MACVLAN +ifdef CONFIG_LIBNL32 +ifdef CONFIG_LIBNL3_ROUTE +OBJS += ../src/ap/macvlan.o +LIBS += -lnl-3 +LIBS += -lnl-genl-3 +LIBS += -lnl-route-3 +CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3 +CFLAGS += -DCONFIG_LIBNL3_ROUTE +endif +endif +endif + ifdef NEED_SHA256 CFLAGS += -DCONFIG_SHA256 ifneq ($(CONFIG_TLS), openssl) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index e1b5026..0cba230 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -1999,6 +1999,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge)); } else if (os_strcmp(buf, "wds_bridge") == 0) { os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge)); +#ifdef CONFIG_IEEE80211R + } else if (os_strcmp(buf, "ft_iface") == 0) { + os_strlcpy(bss->ft_iface, pos, sizeof(bss->ft_iface)); +#endif /* CONFIG_IEEE80211R */ } else if (os_strcmp(buf, "driver") == 0) { int j; /* clear to get error below if setting is invalid */ diff --git a/hostapd/defconfig b/hostapd/defconfig index 4659dd1..db35e0b 100644 --- a/hostapd/defconfig +++ b/hostapd/defconfig @@ -33,6 +33,8 @@ CONFIG_DRIVER_NL80211=y # Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored) #CONFIG_LIBNL32=y +# Use libnl3-route (used by driver_nl80211.c and required by 80211R_MACVLAN) +#CONFIG_LIBNL3_ROUTE=y # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) #CONFIG_DRIVER_BSD=y @@ -143,6 +145,9 @@ CONFIG_IPV6=y # IEEE Std 802.11r-2008 (Fast BSS Transition) #CONFIG_IEEE80211R=y +# ft_iface autoconf support +#CONFIG_IEEE80211R_MACVLAN=y + # Use the hostapd's IEEE 802.11 authentication (ACL), but without # the IEEE 802.11 Management capability (e.g., FreeBSD/net80211) #CONFIG_DRIVER_RADIUS_ACL=y diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index c749501..62bac5a 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1304,6 +1304,34 @@ own_ip_addr=127.0.0.1 # (dot11FTReassociationDeadline) #reassociation_deadline=1000 +# 802.11r Inter-AP communication +# When a station roams, it is connected to a current AP and wants to connect to +# a target AP (R1KH). The station initially connected to an AP (R0KH) before +# it roams around to the current AP. +# +# Now there are two communication patterns you need to be aware of: +# Over-Air: STA <--> target AP (R1KH) <--> initial AP (R0KH) +# Over-DS: STA <--> current AP <--> target AP (R1KH) <--> initial AP (R0KH) +# +# Communication between the APs is done using a layer-2 protocol, that is to +# say that addressing is done using MAC addresses. +# The current AP <--> target AP communication uses the BSSID for addressing and +# is unencrypted. Thus, both ends need to be listening to their BSSID. +# The R1KH <--> R0KH communication uses the mac addresses and keys given in the +# r0kh and r1kh lists below. R1KH looks up the R0KH configuration using R0KH-ID +# when sending and using MAC address when receiving. Thus both need to be +# unique. R0KH looks up r1kh configuration using mac address when receiving and +# replying; it will use R1KH-ID to derive 802.11r data only when pushing to all +# R1KH in its list. +# Sending and receiving is done using ft_iface, which defaults to bridge or +# iface if unset. + +# Use a different interface for 802.11r inter-AP communication +# This interface needs to listen to packets destined for BSSID. +# If hostapd is build with CONFIG_IEEE80211R_MACVLAN and ft_iface set, hostapd +# will add an macvlan interace name ft%iface on top of ft_iface given. +#ft_iface= + # List of R0KHs in the same Mobility Domain # format: <MAC address> <NAS Identifier> <128-bit key as hex string> # This list is used to map R0KH-ID (NAS Identifier) to a destination MAC diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 5aeaa0d..2b50c3d 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -233,6 +233,12 @@ struct hostapd_bss_config { char bridge[IFNAMSIZ + 1]; char vlan_bridge[IFNAMSIZ + 1]; char wds_bridge[IFNAMSIZ + 1]; +#ifdef CONFIG_IEEE80211R + char ft_iface[IFNAMSIZ + 1]; +#ifdef CONFIG_IEEE80211R_MACVLAN + char ft_macvlan[IFNAMSIZ + 1]; +#endif /* CONFIG_IEEE80211R_MACVLAN */ +#endif /* CONFIG_IEEE80211R */ enum hostapd_logger_level logger_syslog_level, logger_stdout_level; diff --git a/src/ap/macvlan.c b/src/ap/macvlan.c new file mode 100644 index 0000000..683d632 --- /dev/null +++ b/src/ap/macvlan.c @@ -0,0 +1,130 @@ +/* + * hostapd / WPA authenticator glue code + * Copyright (c) 2002-2012, Jouni Malinen <j@xxxxx> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" + +#ifdef CONFIG_LIBNL3_ROUTE +#include <netlink/route/link.h> +#include <netlink/route/link/macvlan.h> +#include "macvlan.h" + + +int macvlan_add(const char *if_name, const u8 *addr, const char *if_base) +{ + int err; + struct rtnl_link *link = NULL; + struct rtnl_link *base = NULL; + struct nl_addr *nl_addr = NULL; + struct nl_sock *handle = NULL; + int ret = -1; + + handle = nl_socket_alloc(); + if (!handle) { + wpa_printf(MSG_ERROR, "MACVLAN: failed to open netlink socket"); + goto macvlan_add_error; + } + + if (nl_connect(handle, NETLINK_ROUTE) < 0) { + wpa_printf(MSG_ERROR, "MACVLAN: failed to connect to netlink"); + goto macvlan_add_error; + } + + if (rtnl_link_get_kernel(handle, 0, if_base, &base) < 0) { + /* link does not exist */ + wpa_printf(MSG_ERROR, "MACVLAN: interface %s does not exists", + if_base); + goto macvlan_add_error; + } + + link = rtnl_link_macvlan_alloc(); + if (!link) { + wpa_printf(MSG_ERROR, "MACVLAN: failed to allocate link"); + goto macvlan_add_error; + } + + err = rtnl_link_macvlan_set_mode(link, + rtnl_link_macvlan_str2mode("bridge")); + if (err < 0) { + wpa_printf(MSG_ERROR, + "MACVLAN: failed to set link type to macvlan"); + goto macvlan_add_error; + } + + nl_addr = nl_addr_build(AF_LLC, (void *) addr, ETH_ALEN); + if (!nl_addr) { + wpa_printf(MSG_ERROR, "MACVLAN: failed to parse addr"); + goto macvlan_add_error; + } + rtnl_link_set_addr(link, nl_addr); + nl_addr_put(nl_addr); + + rtnl_link_set_name(link, if_name); + + rtnl_link_set_link(link, rtnl_link_get_ifindex(base)); + + err = rtnl_link_add(handle, link, NLM_F_CREATE); + if (err < 0) { + wpa_printf(MSG_ERROR, "MACVLAN: failed to create link"); + goto macvlan_add_error; + } + ret = 0; + +macvlan_add_error: + if (link) + rtnl_link_put(link); + + if (handle) + nl_socket_free(handle); + return ret; +} + + +int macvlan_del(const char *if_name) +{ + int ret = -1; + struct nl_sock *handle = NULL; + struct rtnl_link *rlink = NULL; + + wpa_printf(MSG_DEBUG, "MACVLAN: macvlan_del(if_name=%s)", if_name); + + handle = nl_socket_alloc(); + if (!handle) { + wpa_printf(MSG_ERROR, "MACVLAN: failed to open netlink socket"); + goto macvlan_del_error; + } + + if (nl_connect(handle, NETLINK_ROUTE) < 0) { + wpa_printf(MSG_ERROR, "MACVLAN: failed to connect to netlink"); + goto macvlan_del_error; + } + + if (rtnl_link_get_kernel(handle, 0, if_name, &rlink) < 0) { + /* link does not exist */ + wpa_printf(MSG_ERROR, "MACVLAN: interface %s does not exists", + if_name); + goto macvlan_del_error; + } + + if (rtnl_link_delete(handle, rlink) < 0) { + wpa_printf(MSG_ERROR, "MACVLAN: failed to remove link %s", + if_name); + goto macvlan_del_error; + } + + ret = 0; + +macvlan_del_error: + if (rlink) + rtnl_link_put(rlink); + if (handle) + nl_socket_free(handle); + return ret; +} +#endif /* CONFIG_LIBNL3_ROUTE */ diff --git a/src/ap/macvlan.h b/src/ap/macvlan.h new file mode 100644 index 0000000..c97373b --- /dev/null +++ b/src/ap/macvlan.h @@ -0,0 +1,10 @@ +#ifndef HOSTAPD_MACVLAN_H +#define HOSTAPD_MACVLAN_H + +#ifdef CONFIG_LIBNL3_ROUTE +int macvlan_add(const char *if_name, const u8 *addr, const char *if_base); +int macvlan_del(const char *if_name); +#endif /* CONFIG_LIBNL3_ROUTE */ + +#endif + diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index fd1c4aa..da45433 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -28,6 +28,12 @@ #include "ap_config.h" #include "wpa_auth.h" #include "wpa_auth_glue.h" +#include <stdlib.h> + +#ifdef CONFIG_IEEE80211R_MACVLAN +#include "macvlan.h" +#include "vlan_ifconfig.h" +#endif /* CONFIG_IEEE80211R_MACVLAN */ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, @@ -738,6 +744,9 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) struct wpa_auth_callbacks cb; const u8 *wpa_ie; size_t wpa_ie_len; +#ifdef CONFIG_IEEE80211R + const char *ft_iface; +#endif /* CONFIG_IEEE80211R */ hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf); if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS) @@ -795,9 +804,28 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) #ifdef CONFIG_IEEE80211R if (!hostapd_drv_none(hapd) && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) { - hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ? - hapd->conf->bridge : - hapd->conf->iface, NULL, ETH_P_RRB, + ft_iface = hapd->conf->iface; + if (hapd->conf->bridge[0]) + ft_iface = hapd->conf->bridge; + if (hapd->conf->ft_iface[0]) { + ft_iface = hapd->conf->ft_iface; +#ifdef CONFIG_IEEE80211R_MACVLAN + snprintf(hapd->conf->ft_macvlan, + sizeof(hapd->conf->ft_macvlan), + "ft%s", hapd->conf->iface); + if (macvlan_add(hapd->conf->ft_macvlan, + hapd->own_addr, ft_iface) < 0 || + ifconfig_up(hapd->conf->ft_macvlan) < 0) { + wpa_printf(MSG_ERROR, "Failed to add bssid to " + "ft_iface %s", ft_iface); + hapd->conf->ft_macvlan[0] = '\0'; + } else + ft_iface = hapd->conf->ft_macvlan; + } else { + hapd->conf->ft_macvlan[0] = '\0'; +#endif /* CONFIG_IEEE80211R_MACVLAN */ + } + hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB, hostapd_rrb_receive, hapd, 1); if (hapd->l2 == NULL && (hapd->driver == NULL || @@ -846,6 +874,12 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd) ieee802_1x_deinit(hapd); #ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_MACVLAN + if (hapd->conf->ft_macvlan[0]) { + ifconfig_down(hapd->conf->ft_macvlan); + macvlan_del(hapd->conf->ft_macvlan); + } +#endif /* CONFIG_IEEE80211R_MACVLAN */ l2_packet_deinit(hapd->l2); hapd->l2 = NULL; #endif /* CONFIG_IEEE80211R */ -- 2.1.4 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap