nl80211: Extend bridge add/del operations for secondary BSSes
authorJouni Malinen <jouni.malinen@atheros.com>
Tue, 15 Mar 2011 11:02:49 +0000 (13:02 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 15 Mar 2011 11:02:49 +0000 (13:02 +0200)
Previously, only the main interface was added to a bridge. Extend this
to apply to all configured BSSes.

src/ap/ap_drv_ops.c
src/ap/ap_drv_ops.h
src/ap/hostapd.c
src/drivers/driver.h
src/drivers/driver_nl80211.c
src/drivers/driver_test.c
wpa_supplicant/driver_i.h
wpa_supplicant/p2p_supplicant.c

index 22a7b91..5017cbf 100644 (file)
@@ -281,7 +281,7 @@ int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
        char force_ifname[IFNAMSIZ];
        u8 if_addr[ETH_ALEN];
        return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
-                             NULL, NULL, force_ifname, if_addr);
+                             NULL, NULL, force_ifname, if_addr, NULL);
 }
 
 
@@ -367,12 +367,14 @@ int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
 
 int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
                   const char *ifname, const u8 *addr, void *bss_ctx,
-                  void **drv_priv, char *force_ifname, u8 *if_addr)
+                  void **drv_priv, char *force_ifname, u8 *if_addr,
+                  const char *bridge)
 {
        if (hapd->driver == NULL || hapd->driver->if_add == NULL)
                return -1;
        return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
-                                   bss_ctx, drv_priv, force_ifname, if_addr);
+                                   bss_ctx, drv_priv, force_ifname, if_addr,
+                                   bridge);
 }
 
 
index 5bc9d01..3af9eca 100644 (file)
@@ -43,7 +43,8 @@ int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len);
 int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len);
 int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
                   const char *ifname, const u8 *addr, void *bss_ctx,
-                  void **drv_priv, char *force_ifname, u8 *if_addr);
+                  void **drv_priv, char *force_ifname, u8 *if_addr,
+                  const char *bridge);
 int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
                      const char *ifname);
 int hostapd_set_ieee8021x(struct hostapd_data *hapd,
index ae960b2..c7faee6 100644 (file)
@@ -510,7 +510,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                hapd->interface_added = 1;
                if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
                                   hapd->conf->iface, hapd->own_addr, hapd,
-                                  &hapd->drv_priv, force_ifname, if_addr)) {
+                                  &hapd->drv_priv, force_ifname, if_addr,
+                                  hapd->conf->bridge[0] ? hapd->conf->bridge :
+                                  NULL)) {
                        wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
                                   MACSTR ")", MAC2STR(hapd->own_addr));
                        return -1;
index df76302..04b2a10 100644 (file)
@@ -1604,11 +1604,13 @@ struct wpa_driver_ops {
         * @if_addr: Buffer for returning the allocated interface address
         *      (this may differ from the requested addr if the driver cannot
         *      change interface address)
+        * @bridge: Bridge interface to use or %NULL if no bridge configured
         * Returns: 0 on success, -1 on failure
         */
        int (*if_add)(void *priv, enum wpa_driver_if_type type,
                      const char *ifname, const u8 *addr, void *bss_ctx,
-                     void **drv_priv, char *force_ifname, u8 *if_addr);
+                     void **drv_priv, char *force_ifname, u8 *if_addr,
+                     const char *bridge);
 
        /**
         * if_remove - Remove a virtual interface
index a64b091..e50d767 100644 (file)
@@ -112,7 +112,10 @@ struct i802_bss {
        struct i802_bss *next;
        int ifindex;
        char ifname[IFNAMSIZ + 1];
+       char brname[IFNAMSIZ];
        unsigned int beacon_set:1;
+       unsigned int added_if_into_bridge:1;
+       unsigned int added_bridge:1;
 };
 
 struct wpa_driver_nl80211_data {
@@ -123,7 +126,6 @@ struct wpa_driver_nl80211_data {
        void *ctx;
        struct netlink_data *netlink;
        int ioctl_sock; /* socket for ioctl() use */
-       char brname[IFNAMSIZ];
        int ifindex;
        int if_removed;
        int if_disabled;
@@ -158,8 +160,6 @@ struct wpa_driver_nl80211_data {
        int disable_11b_rates;
 
        unsigned int pending_remain_on_chan:1;
-       unsigned int added_bridge:1;
-       unsigned int added_if_into_bridge:1;
 
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
@@ -2069,18 +2069,18 @@ static void wpa_driver_nl80211_deinit(void *priv)
 
        if (drv->nl_handle_preq)
                wpa_driver_nl80211_probe_req_report(bss, 0);
-       if (drv->added_if_into_bridge) {
-               if (linux_br_del_if(drv->ioctl_sock, drv->brname, bss->ifname)
+       if (bss->added_if_into_bridge) {
+               if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
                    < 0)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "interface %s from bridge %s: %s",
-                                  bss->ifname, drv->brname, strerror(errno));
+                                  bss->ifname, bss->brname, strerror(errno));
        }
-       if (drv->added_bridge) {
-               if (linux_br_del(drv->ioctl_sock, drv->brname) < 0)
+       if (bss->added_bridge) {
+               if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "bridge %s: %s",
-                                  drv->brname, strerror(errno));
+                                  bss->brname, strerror(errno));
        }
 
        nl80211_remove_monitor_interface(drv);
@@ -5518,12 +5518,13 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
 
 
 static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
+                            struct i802_bss *bss,
                             const char *brname, const char *ifname)
 {
        int ifindex;
        char in_br[IFNAMSIZ];
 
-       os_strlcpy(drv->brname, brname, IFNAMSIZ);
+       os_strlcpy(bss->brname, brname, IFNAMSIZ);
        ifindex = if_nametoindex(brname);
        if (ifindex == 0) {
                /*
@@ -5536,7 +5537,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
                                   brname, strerror(errno));
                        return -1;
                }
-               drv->added_bridge = 1;
+               bss->added_bridge = 1;
                add_ifidx(drv, if_nametoindex(brname));
        }
 
@@ -5563,7 +5564,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
                           ifname, brname, strerror(errno));
                return -1;
        }
-       drv->added_if_into_bridge = 1;
+       bss->added_if_into_bridge = 1;
 
        return 0;
 }
@@ -5628,7 +5629,7 @@ static void *i802_init(struct hostapd_data *hapd,
        }
 
        if (params->num_bridge && params->bridge[0] &&
-           i802_check_bridge(drv, params->bridge[0], params->ifname) < 0)
+           i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
                goto failed;
 
        if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
@@ -5741,7 +5742,8 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
 static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                                     const char *ifname, const u8 *addr,
                                     void *bss_ctx, void **drv_priv,
-                                    char *force_ifname, u8 *if_addr)
+                                    char *force_ifname, u8 *if_addr,
+                                    const char *bridge)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -5806,6 +5808,15 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
 #endif /* CONFIG_P2P */
 
 #ifdef HOSTAPD
+       if (bridge &&
+           i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
+                          "interface %s to a bridge %s", ifname, bridge);
+               nl80211_remove_iface(drv, ifidx);
+               os_free(new_bss);
+               return -1;
+       }
+
        if (type == WPA_IF_AP_BSS) {
                if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) {
                        nl80211_remove_iface(drv, ifidx);
@@ -5838,6 +5849,23 @@ static int wpa_driver_nl80211_if_remove(void *priv,
                   __func__, type, ifname, ifindex);
        if (ifindex <= 0)
                return -1;
+
+#ifdef HOSTAPD
+       if (bss->added_if_into_bridge) {
+               if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
+                   < 0)
+                       wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+                                  "interface %s from bridge %s: %s",
+                                  bss->ifname, bss->brname, strerror(errno));
+       }
+       if (bss->added_bridge) {
+               if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
+                       wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+                                  "bridge %s: %s",
+                                  bss->brname, strerror(errno));
+       }
+#endif /* HOSTAPD */
+
        nl80211_remove_iface(drv, ifindex);
 
 #ifdef HOSTAPD
index c335225..5f9354f 100644 (file)
@@ -1064,7 +1064,8 @@ static int test_driver_bss_remove(void *priv, const char *ifname)
 static int test_driver_if_add(void *priv, enum wpa_driver_if_type type,
                              const char *ifname, const u8 *addr,
                              void *bss_ctx, void **drv_priv,
-                             char *force_ifname, u8 *if_addr)
+                             char *force_ifname, u8 *if_addr,
+                             const char *bridge)
 {
        struct test_driver_bss *dbss = priv;
        struct wpa_driver_test_data *drv = dbss->drv;
index 682c56c..2f57af4 100644 (file)
@@ -413,12 +413,12 @@ static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s,
                                 enum wpa_driver_if_type type,
                                 const char *ifname, const u8 *addr,
                                 void *bss_ctx, char *force_ifname,
-                                u8 *if_addr)
+                                u8 *if_addr, const char *bridge)
 {
        if (wpa_s->driver->if_add)
                return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname,
                                             addr, bss_ctx, NULL, force_ifname,
-                                            if_addr);
+                                            if_addr, bridge);
        return -1;
 }
 
index 431987a..b311493 100644 (file)
@@ -973,7 +973,7 @@ static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
 
        wpa_s->pending_interface_type = type;
        if (wpa_drv_if_add(wpa_s, type, ifname, NULL, NULL, force_ifname,
-                          wpa_s->pending_interface_addr) < 0) {
+                          wpa_s->pending_interface_addr, NULL) < 0) {
                wpa_printf(MSG_ERROR, "P2P: Failed to create new group "
                           "interface");
                return -1;