Add driver ops for allocating interface addresses
authorJouni Malinen <jouni.malinen@atheros.com>
Sun, 3 Jan 2010 11:42:06 +0000 (13:42 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 3 Jan 2010 11:42:06 +0000 (13:42 +0200)
This adds placeholder code for allowing the virtual interfaces to be
pre-allocated a MAC address before the interface type is known with
drivers that do not handle interface type changes.

src/drivers/driver.h
src/drivers/driver_ndis.c
src/drivers/driver_nl80211.c
src/drivers/driver_test.c
wpa_supplicant/driver_i.h

index 1dd358a..5fb936a 100644 (file)
@@ -1520,6 +1520,36 @@ struct wpa_driver_ops {
        int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val);
 
        /**
+        * alloc_interface_addr - Allocate a virtual interface address
+        * @priv: Private driver interface data
+        * @addr: Buffer for returning the address
+        * Returns: 0 on success, -1 on failure
+        *
+        * This command pre-allocates an interface address for a new virtual
+        * interface. This can be used before creating a virtual interface if
+        * the interface mode (e.g., AP vs. station) is not yet known, but the
+        * address of the virtual interface is already needed. This helps with
+        * drivers that cannot change interface mode without destroying and
+        * re-creating the interface.
+        *
+        * The allocated address can be used in a bss_add() call to request a
+        * specific bssid.
+        */
+       int (*alloc_interface_addr)(void *priv, u8 *addr);
+
+       /**
+        * release_interface_addr - Release a virtual interface address
+        * @priv: Private driver interface data
+        * @addr: Address to be freed from alloc_interface_addr()
+        *
+        * This command is used to release a virtual interface address that was
+        * allocated with alloc_interface_addr(), but has not yet been used
+        * with bss_add() to actually create the interface. This allows the
+        * driver to release the pending allocation for a new interface.
+        */
+       void (*release_interface_addr)(void *priv, const u8 *addr);
+
+       /**
         * probe_req_report - Request Probe Request frames to be indicated
         * @priv: Private driver interface data
         * @report: Whether to report received Probe Request frames
index d3e56cf..0789e08 100644 (file)
@@ -3246,5 +3246,7 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
        NULL /* set_ap_wps_ie */,
        NULL /* set_supp_port */,
        NULL /* set_wds_sta */,
+       NULL /* alloc_interface_addr */,
+       NULL /* release_interface_addr */,
        NULL /* probe_req_report */
 };
index b669c87..fc3e974 100644 (file)
@@ -266,7 +266,6 @@ nla_put_failure:
 }
 
 
-#ifdef HOSTAPD
 static int get_ifhwaddr(struct wpa_driver_nl80211_data *drv,
                        const char *ifname, u8 *addr)
 {
@@ -309,7 +308,6 @@ static int set_ifhwaddr(struct wpa_driver_nl80211_data *drv,
 
        return 0;
 }
-#endif /* HOSTAPD */
 
 
 static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
@@ -2661,13 +2659,13 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 #ifdef HOSTAPD
        /* start listening for EAPOL on this interface */
        add_ifidx(drv, ifidx);
+#endif /* HOSTAPD */
 
-       if (addr && iftype == NL80211_IFTYPE_AP &&
+       if (addr && iftype != NL80211_IFTYPE_MONITOR &&
            set_ifhwaddr(drv, ifname, addr)) {
                nl80211_remove_iface(drv, ifidx);
                return -1;
        }
-#endif /* HOSTAPD */
 
        return ifidx;
 }
@@ -4473,6 +4471,30 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
 }
 
 
+static int wpa_driver_nl80211_alloc_interface_addr(void *priv, u8 *addr)
+{
+       struct wpa_driver_nl80211_data *drv = priv;
+
+       if (get_ifhwaddr(drv, drv->ifname, addr) < 0)
+               return -1;
+
+       if (addr[0] & 0x02) {
+               /* TODO: add support for generating multiple addresses */
+               addr[0] ^= 0x80;
+       } else
+               addr[0] = 0x02; /* locally administered */
+
+       return 0;
+}
+
+
+static void wpa_driver_nl80211_release_interface_addr(void *priv,
+                                                     const u8 *addr)
+{
+       /* TODO: keep list of allocated address and release them here */
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -4522,4 +4544,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_wds_sta = i802_set_wds_sta,
 #endif /* HOSTAPD */
        .probe_req_report = wpa_driver_nl80211_probe_req_report,
+       .alloc_interface_addr = wpa_driver_nl80211_alloc_interface_addr,
+       .release_interface_addr = wpa_driver_nl80211_release_interface_addr,
 };
index 9cdeac1..5596f20 100644 (file)
@@ -101,6 +101,8 @@ struct wpa_driver_test_data {
        struct test_driver_bss *bss;
        int udp_port;
 
+       int alloc_iface_idx;
+
        int probe_req_report;
 };
 
@@ -2462,6 +2464,24 @@ fail:
 }
 
 
+static int wpa_driver_test_alloc_interface_addr(void *priv, u8 *addr)
+{
+       struct wpa_driver_test_data *drv = priv;
+       drv->alloc_iface_idx++;
+       addr[0] = 0x02; /* locally administered */
+       sha1_prf(drv->own_addr, ETH_ALEN, "hostapd test addr generation",
+                (const u8 *) &drv->alloc_iface_idx,
+                sizeof(drv->alloc_iface_idx),
+                addr + 1, ETH_ALEN - 1);
+       return 0;
+}
+
+
+static void wpa_driver_test_release_interface_addr(void *priv, const u8 *addr)
+{
+}
+
+
 static int wpa_driver_test_probe_req_report(void *priv, int report)
 {
        struct wpa_driver_test_data *drv = priv;
@@ -2514,5 +2534,7 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        .init2 = wpa_driver_test_init2,
        .get_interfaces = wpa_driver_test_get_interfaces,
        .scan2 = wpa_driver_test_scan,
+       .alloc_interface_addr = wpa_driver_test_alloc_interface_addr,
+       .release_interface_addr = wpa_driver_test_release_interface_addr,
        .probe_req_report = wpa_driver_test_probe_req_report,
 };
index 9dbbc85..4a701f1 100644 (file)
@@ -383,6 +383,22 @@ static inline int wpa_drv_set_supp_port(struct wpa_supplicant *wpa_s,
        return 0;
 }
 
+static inline int wpa_drv_alloc_interface_addr(struct wpa_supplicant *wpa_s,
+                                              u8 *addr)
+{
+       if (wpa_s->driver->alloc_interface_addr)
+               return wpa_s->driver->alloc_interface_addr(wpa_s->drv_priv,
+                                                          addr);
+       return -1;
+}
+
+static inline void wpa_drv_release_interface_addr(struct wpa_supplicant *wpa_s,
+                                                 const u8 *addr)
+{
+       if (wpa_s->driver->release_interface_addr)
+               wpa_s->driver->release_interface_addr(wpa_s->drv_priv, addr);
+}
+
 static inline int wpa_drv_probe_req_report(struct wpa_supplicant *wpa_s,
                                           int report)
 {