From ed4ddb6d77ae0aa35c0338774c7153ec3e63306e Mon Sep 17 00:00:00 2001 From: Kyeyoon Park Date: Wed, 5 Nov 2014 16:15:46 -0800 Subject: [PATCH] AP: Extend the BSS bridge neighbor entry management to support IPv6 This allows adding/deleting an IPv6 neighbor entry to/from the bridge, to which the BSS belongs. This commit adds the needed functionality in driver_nl80211.c for the Linux bridge implementation. In theory, this could be shared with multiple Linux driver interfaces, but for now, only the main nl80211 interface is supported. Signed-off-by: Kyeyoon Park --- src/ap/ap_drv_ops.h | 13 ++++++------ src/ap/dhcp_snoop.c | 7 ++++--- src/ap/ieee802_11.c | 2 +- src/ap/sta_info.c | 4 ++-- src/drivers/driver.h | 14 +++++++------ src/drivers/driver_nl80211.c | 38 +++++++++++++++++++++++++++++------- 6 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index e9f6618c9..65061c93f 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -281,23 +281,24 @@ static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf, } static inline int hostapd_drv_br_add_ip_neigh(struct hostapd_data *hapd, - be32 ipaddr, int prefixlen, - const u8 *addr) + int version, const u8 *ipaddr, + int prefixlen, const u8 *addr) { if (hapd->driver == NULL || hapd->drv_priv == NULL || hapd->driver->br_add_ip_neigh == NULL) return -1; - return hapd->driver->br_add_ip_neigh(hapd->drv_priv, ipaddr, prefixlen, - addr); + return hapd->driver->br_add_ip_neigh(hapd->drv_priv, version, ipaddr, + prefixlen, addr); } static inline int hostapd_drv_br_delete_ip_neigh(struct hostapd_data *hapd, - be32 ipaddr) + u8 version, const u8 *ipaddr) { if (hapd->driver == NULL || hapd->drv_priv == NULL || hapd->driver->br_delete_ip_neigh == NULL) return -1; - return hapd->driver->br_delete_ip_neigh(hapd->drv_priv, ipaddr); + return hapd->driver->br_delete_ip_neigh(hapd->drv_priv, version, + ipaddr); } static inline int hostapd_drv_br_port_set_attr(struct hostapd_data *hapd, diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c index 24ac446d0..40f5421aa 100644 --- a/src/ap/dhcp_snoop.c +++ b/src/ap/dhcp_snoop.c @@ -114,11 +114,12 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf, wpa_printf(MSG_DEBUG, "dhcp_snoop: Removing IPv4 address %X from the ip neigh table", sta->ipaddr); - hostapd_drv_br_delete_ip_neigh(hapd, sta->ipaddr); + hostapd_drv_br_delete_ip_neigh(hapd, 4, + (u8 *) &sta->ipaddr); } - res = hostapd_drv_br_add_ip_neigh(hapd, b->your_ip, prefixlen, - sta->addr); + res = hostapd_drv_br_add_ip_neigh(hapd, 4, (u8 *) &b->your_ip, + prefixlen, sta->addr); if (res) { wpa_printf(MSG_DEBUG, "dhcp_snoop: Adding ip neigh table failed: %d", diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 8b903b3f8..1982942dc 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1717,7 +1717,7 @@ static void handle_disassoc(struct hostapd_data *hapd, accounting_sta_stop(hapd, sta); ieee802_1x_free_station(sta); if (sta->ipaddr) - hostapd_drv_br_delete_ip_neigh(hapd, sta->ipaddr); + hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); hostapd_drv_sta_remove(hapd, sta->addr); if (sta->timeout_next == STA_NULLFUNC || diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 19292a445..19ebe9ccf 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -157,7 +157,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); if (sta->ipaddr) - hostapd_drv_br_delete_ip_neigh(hapd, sta->ipaddr); + hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); if (!hapd->iface->driver_ap_teardown && !(sta->flags & WLAN_STA_PREAUTH)) @@ -615,7 +615,7 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta) ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); if (sta->ipaddr) - hostapd_drv_br_delete_ip_neigh(hapd, sta->ipaddr); + hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver", MAC2STR(sta->addr)); diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 68fe31f45..edad03092 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2632,21 +2632,23 @@ struct wpa_driver_ops { /** * br_add_ip_neigh - Add a neigh to the bridge ip neigh table * @priv: Private driver interface data - * @ipaddr: IPv4 address for the neigh entry - * @prefixlen: IPv4 address netmask prefix length + * @version: IP version of the IP address, 4 or 6 + * @ipaddr: IP address for the neigh entry + * @prefixlen: IP address prefix length * @addr: Corresponding MAC address * Returns: 0 on success, negative (<0) on failure */ - int (*br_add_ip_neigh)(void *priv, be32 ipaddr, int prefixlen, - const u8 *addr); + int (*br_add_ip_neigh)(void *priv, u8 version, const u8 *ipaddr, + int prefixlen, const u8 *addr); /** * br_delete_ip_neigh - Remove a neigh from the bridge ip neigh table * @priv: Private driver interface data - * @ipaddr: IPv4 address for the neigh entry + * @version: IP version of the IP address, 4 or 6 + * @ipaddr: IP address for the neigh entry * Returns: 0 on success, negative (<0) on failure */ - int (*br_delete_ip_neigh)(void *priv, be32 ipaddr); + int (*br_delete_ip_neigh)(void *priv, u8 version, const u8 *ipaddr); /** * br_port_set_attr - Set a bridge port attribute diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 2e296e97d..fc5807c62 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -8949,8 +8949,9 @@ nla_put_failure: #endif /* CONFIG_MESH */ -static int wpa_driver_br_add_ip_neigh(void *priv, be32 ipaddr, - int prefixlen, const u8 *addr) +static int wpa_driver_br_add_ip_neigh(void *priv, u8 version, + const u8 *ipaddr, int prefixlen, + const u8 *addr) { #ifdef CONFIG_LIBNL3_ROUTE struct i802_bss *bss = priv; @@ -8958,9 +8959,10 @@ static int wpa_driver_br_add_ip_neigh(void *priv, be32 ipaddr, struct rtnl_neigh *rn; struct nl_addr *nl_ipaddr = NULL; struct nl_addr *nl_lladdr = NULL; + int family, addrsize; int res; - if (ipaddr == 0 || prefixlen == 0 || !addr) + if (!ipaddr || prefixlen == 0 || !addr) return -EINVAL; if (bss->br_ifindex == 0) { @@ -8975,12 +8977,22 @@ static int wpa_driver_br_add_ip_neigh(void *priv, be32 ipaddr, return -1; } + if (version == 4) { + family = AF_INET; + addrsize = 4; + } else if (version == 6) { + family = AF_INET6; + addrsize = 16; + } else { + return -EINVAL; + } + rn = rtnl_neigh_alloc(); if (rn == NULL) return -ENOMEM; /* set the destination ip address for neigh */ - nl_ipaddr = nl_addr_build(AF_INET, &ipaddr, sizeof(ipaddr)); + nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize); if (nl_ipaddr == NULL) { wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed"); res = -ENOMEM; @@ -9026,18 +9038,30 @@ errout: } -static int wpa_driver_br_delete_ip_neigh(void *priv, be32 ipaddr) +static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version, + const u8 *ipaddr) { #ifdef CONFIG_LIBNL3_ROUTE struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct rtnl_neigh *rn; struct nl_addr *nl_ipaddr; + int family, addrsize; int res; - if (ipaddr == 0) + if (!ipaddr) return -EINVAL; + if (version == 4) { + family = AF_INET; + addrsize = 4; + } else if (version == 6) { + family = AF_INET6; + addrsize = 16; + } else { + return -EINVAL; + } + if (bss->br_ifindex == 0) { wpa_printf(MSG_DEBUG, "nl80211: bridge must be set to delete an ip neigh"); @@ -9055,7 +9079,7 @@ static int wpa_driver_br_delete_ip_neigh(void *priv, be32 ipaddr) return -ENOMEM; /* set the destination ip address for neigh */ - nl_ipaddr = nl_addr_build(AF_INET, &ipaddr, sizeof(ipaddr)); + nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize); if (nl_ipaddr == NULL) { wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed"); res = -ENOMEM;