Added a mechanism for quering driver wrappers for available interfaces
authorJouni Malinen <j@w1.fi>
Wed, 24 Dec 2008 18:25:19 +0000 (20:25 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 24 Dec 2008 18:25:19 +0000 (20:25 +0200)
The new INTERFACE_LIST global control interface command can be used to
request a list of all available network interfaces that could be used
with the enabled driver wrappers. This could be used to enable
interfaces automatically by external programs (e.g., wpa_gui).

src/drivers/driver.h
src/drivers/driver_ndis.c
src/drivers/driver_privsep.c
src/drivers/driver_test.c
wpa_supplicant/ctrl_iface.c
wpa_supplicant/wpa_cli.c

index 67d0181..ef51e9a 100644 (file)
@@ -126,6 +126,23 @@ struct wpa_scan_results {
 };
 
 /**
+ * struct wpa_interface_info - Network interface information
+ * @next: Pointer to the next interface or NULL if this is the last one
+ * @ifname: Interface name that can be used with init() or init2()
+ * @desc: Human readable adapter description (e.g., vendor/model) or NULL if
+ *     not available
+ * @drv_bame: struct wpa_driver_ops::name (note: unlike other strings, this one
+ *     is not an allocated copy, i.e., get_interfaces() caller will not free
+ *     this)
+ */
+struct wpa_interface_info {
+       struct wpa_interface_info *next;
+       char *ifname;
+       char *desc;
+       const char *drv_name;
+};
+
+/**
  * struct wpa_driver_associate_params - Association parameters
  * Data for struct wpa_driver_ops::associate().
  */
@@ -991,6 +1008,15 @@ struct wpa_driver_ops {
         * uses global data.
         */
        void * (*init2)(void *ctx, const char *ifname, void *global_priv);
+
+       /**
+        * get_interfaces - Get information about available interfaces
+        * @global_priv: private driver global data from global_init()
+        * Returns: Allocated buffer of interface information (caller is
+        * responsible for freeing the data structure) on success, NULL on
+        * failure
+        */
+       struct wpa_interface_info * (*get_interfaces)(void *global_priv);
 };
 
 /* Function to check whether a driver is for wired connections */
index 20425bb..078f208 100644 (file)
@@ -2887,5 +2887,6 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
        NULL /* set_country */,
        NULL /* global_init */,
        NULL /* global_deinit */,
-       NULL /* init2 */
+       NULL /* init2 */,
+       NULL /* get_interfaces */
 };
index 8aa05aa..fb472ac 100644 (file)
@@ -778,7 +778,8 @@ struct wpa_driver_ops wpa_driver_privsep_ops = {
        NULL /* set_country */,
        NULL /* global_init */,
        NULL /* global_deinit */,
-       NULL /* init2 */
+       NULL /* init2 */,
+       NULL /* get_interfaces */
 };
 
 
index 9bd4ff3..92137da 100644 (file)
@@ -1147,6 +1147,29 @@ static void wpa_driver_test_global_deinit(void *priv)
 }
 
 
+static struct wpa_interface_info *
+wpa_driver_test_get_interfaces(void *global_priv)
+{
+       /* struct wpa_driver_test_global *global = priv; */
+       struct wpa_interface_info *iface;
+
+       iface = os_zalloc(sizeof(*iface));
+       if (iface == NULL)
+               return iface;
+       iface->ifname = os_strdup("sta0");
+       iface->desc = os_strdup("test interface 0");
+       iface->drv_name = "test";
+       iface->next = os_zalloc(sizeof(*iface));
+       if (iface->next) {
+               iface->next->ifname = os_strdup("sta1");
+               iface->next->desc = os_strdup("test interface 1");
+               iface->next->drv_name = "test";
+       }
+
+       return iface;
+}
+
+
 const struct wpa_driver_ops wpa_driver_test_ops = {
        "test",
        "wpa_supplicant test driver",
@@ -1200,5 +1223,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        NULL /* set_country */,
        wpa_driver_test_global_init,
        wpa_driver_test_global_deinit,
-       wpa_driver_test_init2
+       wpa_driver_test_init2,
+       wpa_driver_test_get_interfaces
 };
index 4154583..650368b 100644 (file)
 #include "wps_supplicant.h"
 #include "wps/wps.h"
 
+extern struct wpa_driver_ops *wpa_supplicant_drivers[];
 
+static int wpa_supplicant_global_iface_list(struct wpa_global *global,
+                                           char *buf, int len);
 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
                                                  char *buf, int len);
 
@@ -1624,6 +1627,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
                        reply_len = -1;
+       } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
+               reply_len = wpa_supplicant_global_iface_list(
+                       wpa_s->global, reply, reply_size);
        } else if (os_strcmp(buf, "INTERFACES") == 0) {
                reply_len = wpa_supplicant_global_iface_interfaces(
                        wpa_s->global, reply, reply_size);
@@ -1739,6 +1745,63 @@ static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
 }
 
 
+static void wpa_free_iface_info(struct wpa_interface_info *iface)
+{
+       struct wpa_interface_info *prev;
+
+       while (iface) {
+               prev = iface;
+               iface = iface->next;
+
+               os_free(prev->ifname);
+               os_free(prev->desc);
+               os_free(prev);
+       }
+}
+
+
+static int wpa_supplicant_global_iface_list(struct wpa_global *global,
+                                           char *buf, int len)
+{
+       int i, res;
+       struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
+       char *pos, *end;
+
+       for (i = 0; wpa_supplicant_drivers[i]; i++) {
+               struct wpa_driver_ops *drv = wpa_supplicant_drivers[i];
+               if (drv->get_interfaces == NULL)
+                       continue;
+               tmp = drv->get_interfaces(global->drv_priv);
+               if (tmp == NULL)
+                       continue;
+
+               if (last == NULL)
+                       iface = last = tmp;
+               else
+                       last->next = tmp;
+               while (last->next)
+                       last = last->next;
+       }
+
+       pos = buf;
+       end = buf + len;
+       for (tmp = iface; tmp; tmp = tmp->next) {
+               res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
+                                 tmp->drv_name, tmp->ifname,
+                                 tmp->desc ? tmp->desc : "");
+               if (res < 0 || res >= end - pos) {
+                       *pos = '\0';
+                       break;
+               }
+               pos += res;
+       }
+
+       wpa_free_iface_info(iface);
+
+       return pos - buf;
+}
+
+
 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
                                                  char *buf, int len)
 {
@@ -1791,6 +1854,9 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
        } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
                if (wpa_supplicant_global_iface_remove(global, buf + 17))
                        reply_len = -1;
+       } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
+               reply_len = wpa_supplicant_global_iface_list(
+                       global, reply, reply_size);
        } else if (os_strcmp(buf, "INTERFACES") == 0) {
                reply_len = wpa_supplicant_global_iface_interfaces(
                        global, reply, reply_size);
index 51892f6..bd1a5a6 100644 (file)
@@ -1120,6 +1120,13 @@ static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
+                                     char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "INTERFACE_LIST");
+}
+
+
 struct wpa_cli_cmd {
        const char *cmd;
        int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -1166,6 +1173,7 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "terminate", wpa_cli_cmd_terminate },
        { "interface_add", wpa_cli_cmd_interface_add },
        { "interface_remove", wpa_cli_cmd_interface_remove },
+       { "interface_list", wpa_cli_cmd_interface_list },
        { "ap_scan", wpa_cli_cmd_ap_scan },
        { "stkstart", wpa_cli_cmd_stkstart },
        { "ft_ds", wpa_cli_cmd_ft_ds },