AP: Extend the BSS bridge neighbor entry management to support IPv6
authorKyeyoon Park <kyeyoonp@qca.qualcomm.com>
Thu, 6 Nov 2014 00:15:46 +0000 (16:15 -0800)
committerJouni Malinen <j@w1.fi>
Wed, 19 Nov 2014 14:23:38 +0000 (16:23 +0200)
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>
src/ap/ap_drv_ops.h
src/ap/dhcp_snoop.c
src/ap/ieee802_11.c
src/ap/sta_info.c
src/drivers/driver.h
src/drivers/driver_nl80211.c

index e9f6618..65061c9 100644 (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,
-                                             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,
index 24ac446..40f5421 100644 (file)
@@ -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",
index 8b903b3..1982942 100644 (file)
@@ -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 ||
index 19292a4..19ebe9c 100644 (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);
 
        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));
index 68fe31f..edad030 100644 (file)
@@ -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
index 2e296e9..fc5807c 100644 (file)
@@ -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;