Added get_interfaces() handler to list all NDIS adapters
authorJouni Malinen <j@w1.fi>
Wed, 24 Dec 2008 19:31:14 +0000 (21:31 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 24 Dec 2008 19:31:14 +0000 (21:31 +0200)
src/drivers/driver_ndis.c

index 078f208..b22109b 100644 (file)
@@ -493,7 +493,7 @@ static int ndis_set_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
        char txt[50];
 
        os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
-       wpa_hexdump_key(MSG_MSGDUMP, txt, data, len);
+       wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len);
 
        buflen = sizeof(*o) + len;
        reallen = buflen - sizeof(o->Data);
@@ -2844,6 +2844,240 @@ static void wpa_driver_ndis_deinit(void *priv)
 }
 
 
+static struct wpa_interface_info *
+wpa_driver_ndis_get_interfaces(void *global_priv)
+{
+       struct wpa_interface_info *iface = NULL, *niface;
+
+#ifdef CONFIG_USE_NDISUIO
+       NDISUIO_QUERY_BINDING *b;
+       size_t blen = sizeof(*b) + 1024;
+       int i, error;
+       DWORD written;
+       char name[256], desc[256];
+       WCHAR *pos;
+       size_t j, len;
+       HANDLE ndisuio;
+
+       ndisuio = CreateFile(NDISUIO_DEVICE_NAME,
+                            GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                            OPEN_EXISTING,
+                            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+                            INVALID_HANDLE_VALUE);
+       if (ndisuio == INVALID_HANDLE_VALUE) {
+               wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to "
+                          "NDISUIO: %d", (int) GetLastError());
+               return NULL;
+       }
+
+#ifndef _WIN32_WCE
+       if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0,
+                            NULL, 0, &written, NULL)) {
+               wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: "
+                          "%d", (int) GetLastError());
+               CloseHandle(ndisuio);
+               return NULL;
+       }
+#endif /* _WIN32_WCE */
+
+       b = os_malloc(blen);
+       if (b == NULL) {
+               CloseHandle(ndisuio);
+               return NULL;
+       }
+
+       for (i = 0; ; i++) {
+               os_memset(b, 0, blen);
+               b->BindingIndex = i;
+               if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
+                                    b, sizeof(NDISUIO_QUERY_BINDING), b, blen,
+                                    &written, NULL)) {
+                       error = (int) GetLastError();
+                       if (error == ERROR_NO_MORE_ITEMS)
+                               break;
+                       wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING "
+                                  "failed: %d", error);
+                       break;
+               }
+
+               pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
+               len = b->DeviceNameLength;
+               if (len >= sizeof(name))
+                       len = sizeof(name) - 1;
+               for (j = 0; j < len; j++)
+                       name[j] = (char) pos[j];
+               name[len] = '\0';
+
+               pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
+               len = b->DeviceDescrLength;
+               if (len >= sizeof(desc))
+                       len = sizeof(desc) - 1;
+               for (j = 0; j < len; j++)
+                       desc[j] = (char) pos[j];
+               desc[len] = '\0';
+
+               wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc);
+
+               niface = os_zalloc(sizeof(*niface));
+               if (niface == NULL)
+                       break;
+               niface->drv_name = "ndis";
+               if (os_strncmp(name, "\\DEVICE\\", 8) == 0)
+                       niface->ifname = os_strdup(name + 8);
+               else
+                       niface->ifname = os_strdup(name);
+               if (niface->ifname == NULL) {
+                       os_free(niface);
+                       break;
+               }
+               niface->desc = os_strdup(desc);
+               niface->next = iface;
+               iface = niface;
+       }
+
+       os_free(b);
+       CloseHandle(ndisuio);
+#else /* CONFIG_USE_NDISUIO */
+       PTSTR _names;
+       char *names, *pos, *pos2;
+       ULONG len;
+       BOOLEAN res;
+       char *name[MAX_ADAPTERS];
+       char *desc[MAX_ADAPTERS];
+       int num_name, num_desc, i;
+
+       wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
+                  PacketGetVersion());
+
+       len = 8192;
+       _names = os_zalloc(len);
+       if (_names == NULL)
+               return NULL;
+
+       res = PacketGetAdapterNames(_names, &len);
+       if (!res && len > 8192) {
+               os_free(_names);
+               _names = os_zalloc(len);
+               if (_names == NULL)
+                       return NULL;
+               res = PacketGetAdapterNames(_names, &len);
+       }
+
+       if (!res) {
+               wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
+                          "(PacketGetAdapterNames)");
+               os_free(_names);
+               return NULL;
+       }
+
+       names = (char *) _names;
+       if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
+               wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
+                          "UNICODE");
+               /* Convert to ASCII */
+               pos2 = pos = names;
+               while (pos2 < names + len) {
+                       if (pos2[0] == '\0' && pos2[1] == '\0' &&
+                           pos2[2] == '\0' && pos2[3] == '\0') {
+                               pos2 += 4;
+                               break;
+                       }
+                       *pos++ = pos2[0];
+                       pos2 += 2;
+               }
+               os_memcpy(pos + 2, names, pos - names);
+               pos += 2;
+       } else
+               pos = names;
+
+       num_name = 0;
+       while (pos < names + len) {
+               name[num_name] = pos;
+               while (*pos && pos < names + len)
+                       pos++;
+               if (pos + 1 >= names + len) {
+                       os_free(names);
+                       return NULL;
+               }
+               pos++;
+               num_name++;
+               if (num_name >= MAX_ADAPTERS) {
+                       wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
+                       os_free(names);
+                       return NULL;
+               }
+               if (*pos == '\0') {
+                       wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found",
+                                  num_name);
+                       pos++;
+                       break;
+               }
+       }
+
+       num_desc = 0;
+       while (pos < names + len) {
+               desc[num_desc] = pos;
+               while (*pos && pos < names + len)
+                       pos++;
+               if (pos + 1 >= names + len) {
+                       os_free(names);
+                       return NULL;
+               }
+               pos++;
+               num_desc++;
+               if (num_desc >= MAX_ADAPTERS) {
+                       wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
+                                  "descriptions");
+                       os_free(names);
+                       return NULL;
+               }
+               if (*pos == '\0') {
+                       wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions "
+                                  "found", num_name);
+                       pos++;
+                       break;
+               }
+       }
+
+       /*
+        * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
+        * descriptions. Fill in dummy descriptors to work around this.
+        */
+       while (num_desc < num_name)
+               desc[num_desc++] = "dummy description";
+
+       if (num_name != num_desc) {
+               wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
+                          "description counts (%d != %d)",
+                          num_name, num_desc);
+               os_free(names);
+               return NULL;
+       }
+
+       for (i = 0; i < num_name; i++) {
+               niface = os_zalloc(sizeof(*niface));
+               if (niface == NULL)
+                       break;
+               niface->drv_name = "ndis";
+               if (os_strncmp(name[i], "\\Device\\NPF_", 12) == 0)
+                       niface->ifname = os_strdup(name[i] + 12);
+               else
+                       niface->ifname = os_strdup(name[i]);
+               if (niface->ifname == NULL) {
+                       os_free(niface);
+                       break;
+               }
+               niface->desc = os_strdup(desc[i]);
+               niface->next = iface;
+               iface = niface;
+       }
+
+#endif /* CONFIG_USE_NDISUIO */
+
+       return iface;
+}
+
+
 const struct wpa_driver_ops wpa_driver_ndis_ops = {
        "ndis",
        "Windows NDIS driver",
@@ -2888,5 +3122,5 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
        NULL /* global_init */,
        NULL /* global_deinit */,
        NULL /* init2 */,
-       NULL /* get_interfaces */
+       wpa_driver_ndis_get_interfaces
 };