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 <kyeyoonp@qca.qualcomm.com>
This commit is contained in:
Kyeyoon Park 2014-11-05 16:15:46 -08:00 committed by Jouni Malinen
parent 7e4d893978
commit ed4ddb6d77
6 changed files with 53 additions and 25 deletions

View file

@ -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, static inline int hostapd_drv_br_add_ip_neigh(struct hostapd_data *hapd,
be32 ipaddr, int prefixlen, int version, const u8 *ipaddr,
const u8 *addr) int prefixlen, const u8 *addr)
{ {
if (hapd->driver == NULL || hapd->drv_priv == NULL || if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->br_add_ip_neigh == NULL) hapd->driver->br_add_ip_neigh == NULL)
return -1; return -1;
return hapd->driver->br_add_ip_neigh(hapd->drv_priv, ipaddr, prefixlen, return hapd->driver->br_add_ip_neigh(hapd->drv_priv, version, ipaddr,
addr); prefixlen, addr);
} }
static inline int hostapd_drv_br_delete_ip_neigh(struct hostapd_data *hapd, 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 || if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->br_delete_ip_neigh == NULL) hapd->driver->br_delete_ip_neigh == NULL)
return -1; 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, static inline int hostapd_drv_br_port_set_attr(struct hostapd_data *hapd,

View file

@ -114,11 +114,12 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"dhcp_snoop: Removing IPv4 address %X from the ip neigh table", "dhcp_snoop: Removing IPv4 address %X from the ip neigh table",
sta->ipaddr); 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, res = hostapd_drv_br_add_ip_neigh(hapd, 4, (u8 *) &b->your_ip,
sta->addr); prefixlen, sta->addr);
if (res) { if (res) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"dhcp_snoop: Adding ip neigh table failed: %d", "dhcp_snoop: Adding ip neigh table failed: %d",

View file

@ -1717,7 +1717,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
accounting_sta_stop(hapd, sta); accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(sta); ieee802_1x_free_station(sta);
if (sta->ipaddr) 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); hostapd_drv_sta_remove(hapd, sta->addr);
if (sta->timeout_next == STA_NULLFUNC || if (sta->timeout_next == STA_NULLFUNC ||

View file

@ -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); hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
if (sta->ipaddr) 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 && if (!hapd->iface->driver_ap_teardown &&
!(sta->flags & WLAN_STA_PREAUTH)) !(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); ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
if (sta->ipaddr) 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", wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
MAC2STR(sta->addr)); MAC2STR(sta->addr));

View file

@ -2632,21 +2632,23 @@ struct wpa_driver_ops {
/** /**
* br_add_ip_neigh - Add a neigh to the bridge ip neigh table * br_add_ip_neigh - Add a neigh to the bridge ip neigh table
* @priv: Private driver interface data * @priv: Private driver interface data
* @ipaddr: IPv4 address for the neigh entry * @version: IP version of the IP address, 4 or 6
* @prefixlen: IPv4 address netmask prefix length * @ipaddr: IP address for the neigh entry
* @prefixlen: IP address prefix length
* @addr: Corresponding MAC address * @addr: Corresponding MAC address
* Returns: 0 on success, negative (<0) on failure * Returns: 0 on success, negative (<0) on failure
*/ */
int (*br_add_ip_neigh)(void *priv, be32 ipaddr, int prefixlen, int (*br_add_ip_neigh)(void *priv, u8 version, const u8 *ipaddr,
const u8 *addr); int prefixlen, const u8 *addr);
/** /**
* br_delete_ip_neigh - Remove a neigh from the bridge ip neigh table * br_delete_ip_neigh - Remove a neigh from the bridge ip neigh table
* @priv: Private driver interface data * @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 * 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 * br_port_set_attr - Set a bridge port attribute

View file

@ -8949,8 +8949,9 @@ nla_put_failure:
#endif /* CONFIG_MESH */ #endif /* CONFIG_MESH */
static int wpa_driver_br_add_ip_neigh(void *priv, be32 ipaddr, static int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
int prefixlen, const u8 *addr) const u8 *ipaddr, int prefixlen,
const u8 *addr)
{ {
#ifdef CONFIG_LIBNL3_ROUTE #ifdef CONFIG_LIBNL3_ROUTE
struct i802_bss *bss = priv; 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 rtnl_neigh *rn;
struct nl_addr *nl_ipaddr = NULL; struct nl_addr *nl_ipaddr = NULL;
struct nl_addr *nl_lladdr = NULL; struct nl_addr *nl_lladdr = NULL;
int family, addrsize;
int res; int res;
if (ipaddr == 0 || prefixlen == 0 || !addr) if (!ipaddr || prefixlen == 0 || !addr)
return -EINVAL; return -EINVAL;
if (bss->br_ifindex == 0) { if (bss->br_ifindex == 0) {
@ -8975,12 +8977,22 @@ static int wpa_driver_br_add_ip_neigh(void *priv, be32 ipaddr,
return -1; 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(); rn = rtnl_neigh_alloc();
if (rn == NULL) if (rn == NULL)
return -ENOMEM; return -ENOMEM;
/* set the destination ip address for neigh */ /* 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) { if (nl_ipaddr == NULL) {
wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed"); wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
res = -ENOMEM; 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 #ifdef CONFIG_LIBNL3_ROUTE
struct i802_bss *bss = priv; struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv; struct wpa_driver_nl80211_data *drv = bss->drv;
struct rtnl_neigh *rn; struct rtnl_neigh *rn;
struct nl_addr *nl_ipaddr; struct nl_addr *nl_ipaddr;
int family, addrsize;
int res; int res;
if (ipaddr == 0) if (!ipaddr)
return -EINVAL; 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) { if (bss->br_ifindex == 0) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"nl80211: bridge must be set to delete an ip neigh"); "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; return -ENOMEM;
/* set the destination ip address for neigh */ /* 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) { if (nl_ipaddr == NULL) {
wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed"); wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
res = -ENOMEM; res = -ENOMEM;