Allow multiple driver wrappers to be specified on command line
authorJouni Malinen <j@w1.fi>
Sat, 14 Feb 2009 14:43:43 +0000 (16:43 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 14 Feb 2009 14:43:43 +0000 (16:43 +0200)
For example, -Dnl80211,wext could be used to automatically select
between nl80211 and wext. The first driver wrapper that is able to
initialize the interface will be used.

src/drivers/driver_nl80211.c
src/drivers/driver_wext.c
wpa_supplicant/ChangeLog
wpa_supplicant/README
wpa_supplicant/doc/docbook/wpa_supplicant.sgml
wpa_supplicant/main.c
wpa_supplicant/wpa_supplicant.c

index 5629588..ed73597 100644 (file)
@@ -89,7 +89,7 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
 static int wpa_driver_nl80211_set_mode(void *priv, int mode);
 static int wpa_driver_nl80211_flush_pmkid(void *priv);
 static int wpa_driver_nl80211_get_range(void *priv);
-static void
+static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
 
 
@@ -1548,10 +1548,14 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
                                 ctx);
        drv->wext_event_sock = s;
 
-       wpa_driver_nl80211_finish_drv_init(drv);
+       if (wpa_driver_nl80211_finish_drv_init(drv))
+               goto err7;
 
        return drv;
 
+err7:
+       eloop_unregister_read_sock(drv->wext_event_sock);
+       close(drv->wext_event_sock);
 err6:
        close(drv->ioctl_sock);
 err5:
@@ -1568,17 +1572,21 @@ err1:
 }
 
 
-static void
+static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
 {
        int flags;
 
-       if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0)
-               printf("Could not get interface '%s' flags\n", drv->ifname);
-       else if (!(flags & IFF_UP)) {
+       if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0) {
+               wpa_printf(MSG_ERROR, "Could not get interface '%s' flags",
+                          drv->ifname);
+               return -1;
+       }
+       if (!(flags & IFF_UP)) {
                if (wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP) != 0) {
-                       printf("Could not set interface '%s' UP\n",
-                              drv->ifname);
+                       wpa_printf(MSG_ERROR, "Could not set interface '%s' "
+                                  "UP", drv->ifname);
+                       return -1;
                }
        }
 
@@ -1598,6 +1606,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
        wpa_driver_nl80211_capa(drv);
 
        wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+
+       return 0;
 }
 
 
index bc2137b..f21c379 100644 (file)
@@ -34,7 +34,7 @@
 
 static int wpa_driver_wext_flush_pmkid(void *priv);
 static int wpa_driver_wext_get_range(void *priv);
-static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
 
 
 static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
@@ -913,50 +913,60 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
        drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
        if (drv->ioctl_sock < 0) {
                perror("socket(PF_INET,SOCK_DGRAM)");
-               os_free(drv);
-               return NULL;
+               goto err1;
        }
 
        s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        if (s < 0) {
                perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
-               close(drv->ioctl_sock);
-               os_free(drv);
-               return NULL;
+               goto err2;
        }
+       drv->event_sock = s;
 
        os_memset(&local, 0, sizeof(local));
        local.nl_family = AF_NETLINK;
        local.nl_groups = RTMGRP_LINK;
        if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
                perror("bind(netlink)");
-               close(s);
-               close(drv->ioctl_sock);
-               os_free(drv);
-               return NULL;
+               goto err3;
        }
 
        eloop_register_read_sock(s, wpa_driver_wext_event_receive, drv, ctx);
-       drv->event_sock = s;
 
        drv->mlme_sock = -1;
 
-       wpa_driver_wext_finish_drv_init(drv);
+       if (wpa_driver_wext_finish_drv_init(drv) < 0)
+               goto err4;
 
        return drv;
+
+err4:
+       eloop_unregister_read_sock(drv->event_sock);
+err3:
+       close(drv->event_sock);
+err2:
+       close(drv->ioctl_sock);
+err1:
+       os_free(drv);
+       return NULL;
 }
 
 
-static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
 {
        int flags;
 
-       if (wpa_driver_wext_get_ifflags(drv, &flags) != 0)
-               printf("Could not get interface '%s' flags\n", drv->ifname);
-       else if (!(flags & IFF_UP)) {
+       if (wpa_driver_wext_get_ifflags(drv, &flags) != 0) {
+               wpa_printf(MSG_ERROR, "Could not get interface '%s' flags",
+                          drv->ifname);
+               return -1;
+       }
+
+       if (!(flags & IFF_UP)) {
                if (wpa_driver_wext_set_ifflags(drv, flags | IFF_UP) != 0) {
-                       printf("Could not set interface '%s' UP\n",
-                              drv->ifname);
+                       wpa_printf(MSG_ERROR, "Could not set interface '%s' "
+                                  "UP", drv->ifname);
+                       return -1;
                } else {
                        /*
                         * Wait some time to allow driver to initialize before
@@ -977,7 +987,9 @@ static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
        wpa_driver_wext_flush_pmkid(drv);
 
        if (wpa_driver_wext_set_mode(drv, 0) < 0) {
-               printf("Could not configure driver to use managed mode\n");
+               wpa_printf(MSG_DEBUG, "Could not configure driver to use "
+                          "managed mode");
+               /* Try to use it anyway */
        }
 
        wpa_driver_wext_get_range(drv);
@@ -1000,6 +1012,8 @@ static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
        }
 
        wpa_driver_wext_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+
+       return 0;
 }
 
 
index 1d46ff9..c96c6f7 100644 (file)
@@ -5,6 +5,9 @@ ChangeLog for wpa_supplicant
          configurable with a new command line options (-G<seconds>)
        * fixed scan buffer processing with WEXT to handle up to 65535
          byte result buffer (previously, limited to 32768 bytes)
+       * allow multiple driver wrappers to be specified on command line
+         (e.g., -Dnl80211,wext); the first one that is able to initialize the
+         interface will be used
 
 2009-01-06 - v0.6.7
        * added support for Wi-Fi Protected Setup (WPS)
index 2b94c23..760d64a 100644 (file)
@@ -500,7 +500,7 @@ options:
   -C = ctrl_interface parameter (only used if -c is not)
   -i = interface name
   -d = increase debugging verbosity (-dd even more)
-  -D = driver name
+  -D = driver name (can be multiple drivers: nl80211,wext)
   -f = Log output to default log location (normally /tmp)
   -g = global ctrl_interface
   -K = include keys (passwords, etc.) in debug output
@@ -544,6 +544,13 @@ enabled:
 
 wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
 
+If the specific driver wrapper is not known beforehand, it is possible
+to specify multiple comma separated driver wrappers on the command
+line. wpa_supplicant will use the first driver wrapper that is able to
+initialize the interface.
+
+wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
+
 
 wpa_supplicant can control multiple interfaces (radios) either by
 running one process for each interface separately or by running just
index 9798ced..3aae51b 100644 (file)
       <varlistentry>
        <term>-D driver</term>
        <listitem>
-         <para>Driver to use. (Per interface, see the available options
-                 below.)</para>
+         <para>Driver to use (can be multiple drivers: nl80211,wext).
+                 (Per interface, see the available options below.)</para>
        </listitem>
       </varlistentry>
 
@@ -509,6 +509,15 @@ wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0
 wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
 </programlisting></blockquote>
 
+    <para>If the specific driver wrapper is not known beforehand, it is
+    possible to specify multiple comma separated driver wrappers on the command
+    line. <command>wpa_supplicant</command> will use the first driver
+    wrapper that is able to initialize the interface.</para>
+
+<blockquote><programlisting>
+wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
+</programlisting></blockquote>
+
     <para><command>wpa_supplicant</command> can control multiple
     interfaces (radios) either by running one process for each
     interface separately or by running just one process and list of
index 6f90cc5..7e9919b 100644 (file)
@@ -52,7 +52,7 @@ static void usage(void)
               "  -C = ctrl_interface parameter (only used if -c is not)\n"
               "  -i = interface name\n"
               "  -d = increase debugging verbosity (-dd even more)\n"
-              "  -D = driver name\n"
+              "  -D = driver name (can be multiple drivers: nl80211,wext)\n"
 #ifdef CONFIG_DEBUG_FILE
               "  -f = log output to debug file instead of stdout\n"
 #endif /* CONFIG_DEBUG_FILE */
index 6eb0eec..9b6f088 100644 (file)
@@ -1491,6 +1491,8 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
                                     const char *name)
 {
        int i;
+       size_t len;
+       const char *pos;
 
        if (wpa_s == NULL)
                return -1;
@@ -1507,14 +1509,21 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
                return 0;
        }
 
+       pos = os_strchr(name, ',');
+       if (pos)
+               len = pos - name;
+       else
+               len = os_strlen(name);
        for (i = 0; wpa_supplicant_drivers[i]; i++) {
-               if (os_strcmp(name, wpa_supplicant_drivers[i]->name) == 0) {
+               if (os_strlen(wpa_supplicant_drivers[i]->name) == len &&
+                   os_strncmp(name, wpa_supplicant_drivers[i]->name, len) ==
+                   0) {
                        wpa_s->driver = wpa_supplicant_drivers[i];
                        return 0;
                }
        }
 
-       wpa_printf(MSG_ERROR, "Unsupported driver '%s'.\n", name);
+       wpa_printf(MSG_ERROR, "Unsupported driver '%s'.", name);
        return -1;
 }
 
@@ -1710,6 +1719,9 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
 static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                                     struct wpa_interface *iface)
 {
+       const char *ifname, *driver;
+       struct wpa_driver_capa capa;
+
        wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
                   "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
                   iface->confname ? iface->confname : "N/A",
@@ -1717,10 +1729,6 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                   iface->ctrl_interface ? iface->ctrl_interface : "N/A",
                   iface->bridge_ifname ? iface->bridge_ifname : "N/A");
 
-       if (wpa_supplicant_set_driver(wpa_s, iface->driver) < 0) {
-               return -1;
-       }
-
        if (iface->confname) {
 #ifdef CONFIG_BACKEND_FILE
                wpa_s->confname = os_rel2abs_path(iface->confname);
@@ -1788,18 +1796,6 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                           sizeof(wpa_s->bridge_ifname));
        }
 
-       return 0;
-}
-
-
-static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s)
-{
-       const char *ifname;
-       struct wpa_driver_capa capa;
-
-       wpa_printf(MSG_DEBUG, "Initializing interface (2) '%s'",
-                  wpa_s->ifname);
-
        /* RSNA Supplicant Key Management - INITIALIZE */
        eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
        eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
@@ -1808,8 +1804,21 @@ static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s)
         * L2 receive handler so that association events are processed before
         * EAPOL-Key packets if both become available for the same select()
         * call. */
+       driver = iface->driver;
+next_driver:
+       if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
+               return -1;
+
        wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
        if (wpa_s->drv_priv == NULL) {
+               const char *pos;
+               pos = os_strchr(driver, ',');
+               if (pos) {
+                       wpa_printf(MSG_DEBUG, "Failed to initialize driver "
+                                  "interface - try next driver wrapper");
+                       driver = pos + 1;
+                       goto next_driver;
+               }
                wpa_printf(MSG_ERROR, "Failed to initialize driver interface");
                return -1;
        }
@@ -1965,8 +1974,7 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
        if (wpa_s == NULL)
                return NULL;
 
-       if (wpa_supplicant_init_iface(wpa_s, iface) ||
-           wpa_supplicant_init_iface2(wpa_s)) {
+       if (wpa_supplicant_init_iface(wpa_s, iface)) {
                wpa_printf(MSG_DEBUG, "Failed to add interface %s",
                           iface->ifname);
                wpa_supplicant_deinit_iface(wpa_s);