Fix the OID_802_3_MULTICAST_LIST issue.
[dragonfly.git] / contrib / wpa_supplicant / src / drivers / driver_ndis.c
1 /*
2  * WPA Supplicant - Windows/NDIS driver interface
3  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #ifdef __CYGWIN__
16 /* Avoid some header file conflicts by not including standard headers for
17  * cygwin builds when Packet32.h is included. */
18 #include "build_config.h"
19 int close(int fd);
20 #else /* __CYGWIN__ */
21 #include "includes.h"
22 #endif /* __CYGWIN__ */
23 #ifdef CONFIG_USE_NDISUIO
24 #include <winsock2.h>
25 #else /* CONFIG_USE_NDISUIO */
26 #include <Packet32.h>
27 #endif /* CONFIG_USE_NDISUIO */
28 #ifdef __MINGW32_VERSION
29 #include <ddk/ntddndis.h>
30 #else /* __MINGW32_VERSION */
31 #include <ntddndis.h>
32 #endif /* __MINGW32_VERSION */
33
34 #ifdef _WIN32_WCE
35 #include <winioctl.h>
36 #include <nuiouser.h>
37 #include <devload.h>
38 #endif /* _WIN32_WCE */
39
40 #include "common.h"
41 #include "driver.h"
42 #include "eloop.h"
43 #include "ieee802_11_defs.h"
44 #include "driver_ndis.h"
45
46 int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv);
47 #ifdef CONFIG_NDIS_EVENTS_INTEGRATED
48 void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data);
49 #endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
50
51 static void wpa_driver_ndis_deinit(void *priv);
52 static void wpa_driver_ndis_poll(void *drv);
53 static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx);
54 static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv);
55 static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv);
56 static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv);
57
58
59 static const u8 pae_group_addr[ETH_ALEN] =
60 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
61
62
63 /* FIX: to be removed once this can be compiled with the complete NDIS
64  * header files */
65 #ifndef OID_802_11_BSSID
66 #define OID_802_11_BSSID                        0x0d010101
67 #define OID_802_11_SSID                         0x0d010102
68 #define OID_802_11_INFRASTRUCTURE_MODE          0x0d010108
69 #define OID_802_11_ADD_WEP                      0x0D010113
70 #define OID_802_11_REMOVE_WEP                   0x0D010114
71 #define OID_802_11_DISASSOCIATE                 0x0D010115
72 #define OID_802_11_BSSID_LIST                   0x0d010217
73 #define OID_802_11_AUTHENTICATION_MODE          0x0d010118
74 #define OID_802_11_PRIVACY_FILTER               0x0d010119
75 #define OID_802_11_BSSID_LIST_SCAN              0x0d01011A
76 #define OID_802_11_WEP_STATUS                   0x0d01011B
77 #define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS
78 #define OID_802_11_ADD_KEY                      0x0d01011D
79 #define OID_802_11_REMOVE_KEY                   0x0d01011E
80 #define OID_802_11_ASSOCIATION_INFORMATION      0x0d01011F
81 #define OID_802_11_TEST                         0x0d010120
82 #define OID_802_11_CAPABILITY                   0x0d010122
83 #define OID_802_11_PMKID                        0x0d010123
84
85 #define NDIS_802_11_LENGTH_SSID 32
86 #define NDIS_802_11_LENGTH_RATES 8
87 #define NDIS_802_11_LENGTH_RATES_EX 16
88
89 typedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
90
91 typedef struct NDIS_802_11_SSID {
92         ULONG SsidLength;
93         UCHAR Ssid[NDIS_802_11_LENGTH_SSID];
94 } NDIS_802_11_SSID;
95
96 typedef LONG NDIS_802_11_RSSI;
97
98 typedef enum NDIS_802_11_NETWORK_TYPE {
99         Ndis802_11FH,
100         Ndis802_11DS,
101         Ndis802_11OFDM5,
102         Ndis802_11OFDM24,
103         Ndis802_11NetworkTypeMax
104 } NDIS_802_11_NETWORK_TYPE;
105
106 typedef struct NDIS_802_11_CONFIGURATION_FH {
107         ULONG Length;
108         ULONG HopPattern;
109         ULONG HopSet;
110         ULONG DwellTime;
111 } NDIS_802_11_CONFIGURATION_FH;
112
113 typedef struct NDIS_802_11_CONFIGURATION {
114         ULONG Length;
115         ULONG BeaconPeriod;
116         ULONG ATIMWindow;
117         ULONG DSConfig;
118         NDIS_802_11_CONFIGURATION_FH FHConfig;
119 } NDIS_802_11_CONFIGURATION;
120
121 typedef enum NDIS_802_11_NETWORK_INFRASTRUCTURE {
122         Ndis802_11IBSS,
123         Ndis802_11Infrastructure,
124         Ndis802_11AutoUnknown,
125         Ndis802_11InfrastructureMax
126 } NDIS_802_11_NETWORK_INFRASTRUCTURE;
127
128 typedef enum NDIS_802_11_AUTHENTICATION_MODE {
129         Ndis802_11AuthModeOpen,
130         Ndis802_11AuthModeShared,
131         Ndis802_11AuthModeAutoSwitch,
132         Ndis802_11AuthModeWPA,
133         Ndis802_11AuthModeWPAPSK,
134         Ndis802_11AuthModeWPANone,
135         Ndis802_11AuthModeWPA2,
136         Ndis802_11AuthModeWPA2PSK,
137         Ndis802_11AuthModeMax
138 } NDIS_802_11_AUTHENTICATION_MODE;
139
140 typedef enum NDIS_802_11_WEP_STATUS {
141         Ndis802_11WEPEnabled,
142         Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
143         Ndis802_11WEPDisabled,
144         Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
145         Ndis802_11WEPKeyAbsent,
146         Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
147         Ndis802_11WEPNotSupported,
148         Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
149         Ndis802_11Encryption2Enabled,
150         Ndis802_11Encryption2KeyAbsent,
151         Ndis802_11Encryption3Enabled,
152         Ndis802_11Encryption3KeyAbsent
153 } NDIS_802_11_WEP_STATUS, NDIS_802_11_ENCRYPTION_STATUS;
154
155 typedef enum NDIS_802_11_PRIVACY_FILTER {
156         Ndis802_11PrivFilterAcceptAll,
157         Ndis802_11PrivFilter8021xWEP
158 } NDIS_802_11_PRIVACY_FILTER;
159
160 typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES];
161 typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX];
162
163 typedef struct NDIS_WLAN_BSSID_EX {
164         ULONG Length;
165         NDIS_802_11_MAC_ADDRESS MacAddress; /* BSSID */
166         UCHAR Reserved[2];
167         NDIS_802_11_SSID Ssid;
168         ULONG Privacy;
169         NDIS_802_11_RSSI Rssi;
170         NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
171         NDIS_802_11_CONFIGURATION Configuration;
172         NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
173         NDIS_802_11_RATES_EX SupportedRates;
174         ULONG IELength;
175         UCHAR IEs[1];
176 } NDIS_WLAN_BSSID_EX;
177
178 typedef struct NDIS_802_11_BSSID_LIST_EX {
179         ULONG NumberOfItems;
180         NDIS_WLAN_BSSID_EX Bssid[1];
181 } NDIS_802_11_BSSID_LIST_EX;
182
183 typedef struct NDIS_802_11_FIXED_IEs {
184         UCHAR Timestamp[8];
185         USHORT BeaconInterval;
186         USHORT Capabilities;
187 } NDIS_802_11_FIXED_IEs;
188
189 typedef struct NDIS_802_11_WEP {
190         ULONG Length;
191         ULONG KeyIndex;
192         ULONG KeyLength;
193         UCHAR KeyMaterial[1];
194 } NDIS_802_11_WEP;
195
196 typedef ULONG NDIS_802_11_KEY_INDEX;
197 typedef ULONGLONG NDIS_802_11_KEY_RSC;
198
199 typedef struct NDIS_802_11_KEY {
200         ULONG Length;
201         ULONG KeyIndex;
202         ULONG KeyLength;
203         NDIS_802_11_MAC_ADDRESS BSSID;
204         NDIS_802_11_KEY_RSC KeyRSC;
205         UCHAR KeyMaterial[1];
206 } NDIS_802_11_KEY;
207
208 typedef struct NDIS_802_11_REMOVE_KEY {
209         ULONG Length;
210         ULONG KeyIndex;
211         NDIS_802_11_MAC_ADDRESS BSSID;
212 } NDIS_802_11_REMOVE_KEY;
213
214 typedef struct NDIS_802_11_AI_REQFI {
215         USHORT Capabilities;
216         USHORT ListenInterval;
217         NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
218 } NDIS_802_11_AI_REQFI;
219
220 typedef struct NDIS_802_11_AI_RESFI {
221         USHORT Capabilities;
222         USHORT StatusCode;
223         USHORT AssociationId;
224 } NDIS_802_11_AI_RESFI;
225
226 typedef struct NDIS_802_11_ASSOCIATION_INFORMATION {
227         ULONG Length;
228         USHORT AvailableRequestFixedIEs;
229         NDIS_802_11_AI_REQFI RequestFixedIEs;
230         ULONG RequestIELength;
231         ULONG OffsetRequestIEs;
232         USHORT AvailableResponseFixedIEs;
233         NDIS_802_11_AI_RESFI ResponseFixedIEs;
234         ULONG ResponseIELength;
235         ULONG OffsetResponseIEs;
236 } NDIS_802_11_ASSOCIATION_INFORMATION;
237
238 typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION {
239         NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported;
240         NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported;
241 } NDIS_802_11_AUTHENTICATION_ENCRYPTION;
242
243 typedef struct NDIS_802_11_CAPABILITY {
244         ULONG Length;
245         ULONG Version;
246         ULONG NoOfPMKIDs;
247         ULONG NoOfAuthEncryptPairsSupported;
248         NDIS_802_11_AUTHENTICATION_ENCRYPTION
249                 AuthenticationEncryptionSupported[1];
250 } NDIS_802_11_CAPABILITY;
251
252 typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
253
254 typedef struct BSSID_INFO {
255         NDIS_802_11_MAC_ADDRESS BSSID;
256         NDIS_802_11_PMKID_VALUE PMKID;
257 } BSSID_INFO;
258
259 typedef struct NDIS_802_11_PMKID {
260         ULONG Length;
261         ULONG BSSIDInfoCount;
262         BSSID_INFO BSSIDInfo[1];
263 } NDIS_802_11_PMKID;
264
265 typedef enum NDIS_802_11_STATUS_TYPE {
266         Ndis802_11StatusType_Authentication,
267         Ndis802_11StatusType_PMKID_CandidateList = 2,
268         Ndis802_11StatusTypeMax
269 } NDIS_802_11_STATUS_TYPE;
270
271 typedef struct NDIS_802_11_STATUS_INDICATION {
272         NDIS_802_11_STATUS_TYPE StatusType;
273 } NDIS_802_11_STATUS_INDICATION;
274
275 typedef struct PMKID_CANDIDATE {
276         NDIS_802_11_MAC_ADDRESS BSSID;
277         ULONG Flags;
278 } PMKID_CANDIDATE;
279
280 #define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
281
282 typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST {
283         ULONG Version;
284         ULONG NumCandidates;
285         PMKID_CANDIDATE CandidateList[1];
286 } NDIS_802_11_PMKID_CANDIDATE_LIST;
287
288 typedef struct NDIS_802_11_AUTHENTICATION_REQUEST {
289         ULONG Length;
290         NDIS_802_11_MAC_ADDRESS Bssid;
291         ULONG Flags;
292 } NDIS_802_11_AUTHENTICATION_REQUEST;
293
294 #define NDIS_802_11_AUTH_REQUEST_REAUTH                 0x01
295 #define NDIS_802_11_AUTH_REQUEST_KEYUPDATE              0x02
296 #define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR         0x06
297 #define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR            0x0E
298
299 #endif /* OID_802_11_BSSID */
300
301
302 #ifndef OID_802_11_PMKID
303 /* Platform SDK for XP did not include WPA2, so add needed definitions */
304
305 #define OID_802_11_CAPABILITY                   0x0d010122
306 #define OID_802_11_PMKID                        0x0d010123
307
308 #define Ndis802_11AuthModeWPA2 6
309 #define Ndis802_11AuthModeWPA2PSK 7
310
311 #define Ndis802_11StatusType_PMKID_CandidateList 2
312
313 typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION {
314         NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported;
315         NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported;
316 } NDIS_802_11_AUTHENTICATION_ENCRYPTION;
317
318 typedef struct NDIS_802_11_CAPABILITY {
319         ULONG Length;
320         ULONG Version;
321         ULONG NoOfPMKIDs;
322         ULONG NoOfAuthEncryptPairsSupported;
323         NDIS_802_11_AUTHENTICATION_ENCRYPTION
324                 AuthenticationEncryptionSupported[1];
325 } NDIS_802_11_CAPABILITY;
326
327 typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
328
329 typedef struct BSSID_INFO {
330         NDIS_802_11_MAC_ADDRESS BSSID;
331         NDIS_802_11_PMKID_VALUE PMKID;
332 } BSSID_INFO;
333
334 typedef struct NDIS_802_11_PMKID {
335         ULONG Length;
336         ULONG BSSIDInfoCount;
337         BSSID_INFO BSSIDInfo[1];
338 } NDIS_802_11_PMKID;
339
340 typedef struct PMKID_CANDIDATE {
341         NDIS_802_11_MAC_ADDRESS BSSID;
342         ULONG Flags;
343 } PMKID_CANDIDATE;
344
345 #define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
346
347 typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST {
348         ULONG Version;
349         ULONG NumCandidates;
350         PMKID_CANDIDATE CandidateList[1];
351 } NDIS_802_11_PMKID_CANDIDATE_LIST;
352
353 #endif /* OID_802_11_CAPABILITY */
354
355
356 #ifdef CONFIG_USE_NDISUIO
357 #ifndef _WIN32_WCE
358 #ifdef __MINGW32_VERSION
359 typedef ULONG NDIS_OID;
360 #endif /* __MINGW32_VERSION */
361 /* from nuiouser.h */
362 #define FSCTL_NDISUIO_BASE      FILE_DEVICE_NETWORK
363
364 #define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
365         CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
366
367 #define IOCTL_NDISUIO_OPEN_DEVICE \
368         _NDISUIO_CTL_CODE(0x200, METHOD_BUFFERED, \
369                           FILE_READ_ACCESS | FILE_WRITE_ACCESS)
370
371 #define IOCTL_NDISUIO_QUERY_OID_VALUE \
372         _NDISUIO_CTL_CODE(0x201, METHOD_BUFFERED, \
373                           FILE_READ_ACCESS | FILE_WRITE_ACCESS)
374
375 #define IOCTL_NDISUIO_SET_OID_VALUE \
376         _NDISUIO_CTL_CODE(0x205, METHOD_BUFFERED, \
377                           FILE_READ_ACCESS | FILE_WRITE_ACCESS)
378
379 #define IOCTL_NDISUIO_SET_ETHER_TYPE \
380         _NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \
381                           FILE_READ_ACCESS | FILE_WRITE_ACCESS)
382
383 #define IOCTL_NDISUIO_QUERY_BINDING \
384         _NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \
385                           FILE_READ_ACCESS | FILE_WRITE_ACCESS)
386
387 #define IOCTL_NDISUIO_BIND_WAIT \
388         _NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \
389                           FILE_READ_ACCESS | FILE_WRITE_ACCESS)
390
391 typedef struct _NDISUIO_QUERY_OID
392 {
393     NDIS_OID Oid;
394     UCHAR Data[sizeof(ULONG)];
395 } NDISUIO_QUERY_OID, *PNDISUIO_QUERY_OID;
396
397 typedef struct _NDISUIO_SET_OID
398 {
399     NDIS_OID Oid;
400     UCHAR Data[sizeof(ULONG)];
401 } NDISUIO_SET_OID, *PNDISUIO_SET_OID;
402
403 typedef struct _NDISUIO_QUERY_BINDING
404 {
405         ULONG BindingIndex;
406         ULONG DeviceNameOffset;
407         ULONG DeviceNameLength;
408         ULONG DeviceDescrOffset;
409         ULONG DeviceDescrLength;
410 } NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING;
411 #endif /* _WIN32_WCE */
412 #endif /* CONFIG_USE_NDISUIO */
413
414
415 static int ndis_get_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
416                         char *data, size_t len)
417 {
418 #ifdef CONFIG_USE_NDISUIO
419         NDISUIO_QUERY_OID *o;
420         size_t buflen = sizeof(*o) + len;
421         DWORD written;
422         int ret;
423         size_t hdrlen;
424
425         o = os_zalloc(buflen);
426         if (o == NULL)
427                 return -1;
428         o->Oid = oid;
429 #ifdef _WIN32_WCE
430         o->ptcDeviceName = drv->adapter_name;
431 #endif /* _WIN32_WCE */
432         if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_OID_VALUE,
433                              o, sizeof(NDISUIO_QUERY_OID), o, buflen, &written,
434                              NULL)) {
435                 wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_QUERY_OID_VALUE "
436                            "failed (oid=%08x): %d", oid, (int) GetLastError());
437                 os_free(o);
438                 return -1;
439         }
440         hdrlen = sizeof(NDISUIO_QUERY_OID) - sizeof(o->Data);
441         if (written < hdrlen) {
442                 wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d); "
443                            "too short", oid, (unsigned int) written);
444                 os_free(o);
445                 return -1;
446         }
447         written -= hdrlen;
448         if (written > len) {
449                 wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d) > "
450                            "len (%d)",oid, (unsigned int) written, len);
451                 os_free(o);
452                 return -1;
453         }
454         os_memcpy(data, o->Data, written);
455         ret = written;
456         os_free(o);
457         return ret;
458 #else /* CONFIG_USE_NDISUIO */
459         char *buf;
460         PACKET_OID_DATA *o;
461         int ret;
462
463         buf = os_zalloc(sizeof(*o) + len);
464         if (buf == NULL)
465                 return -1;
466         o = (PACKET_OID_DATA *) buf;
467         o->Oid = oid;
468         o->Length = len;
469
470         if (!PacketRequest(drv->adapter, FALSE, o)) {
471                 wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
472                            __func__, oid, len);
473                 os_free(buf);
474                 return -1;
475         }
476         if (o->Length > len) {
477                 wpa_printf(MSG_DEBUG, "%s: oid=0x%x Length (%d) > len (%d)",
478                            __func__, oid, (unsigned int) o->Length, len);
479                 os_free(buf);
480                 return -1;
481         }
482         os_memcpy(data, o->Data, o->Length);
483         ret = o->Length;
484         os_free(buf);
485         return ret;
486 #endif /* CONFIG_USE_NDISUIO */
487 }
488
489
490 static int ndis_set_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
491                         const char *data, size_t len)
492 {
493 #ifdef CONFIG_USE_NDISUIO
494         NDISUIO_SET_OID *o;
495         size_t buflen, reallen;
496         DWORD written;
497         char txt[50];
498
499         os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
500         wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len);
501
502         buflen = sizeof(*o) + len;
503         reallen = buflen - sizeof(o->Data);
504         o = os_zalloc(buflen);
505         if (o == NULL)
506                 return -1;
507         o->Oid = oid;
508 #ifdef _WIN32_WCE
509         o->ptcDeviceName = drv->adapter_name;
510 #endif /* _WIN32_WCE */
511         if (data)
512                 os_memcpy(o->Data, data, len);
513         if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_SET_OID_VALUE,
514                              o, reallen, NULL, 0, &written, NULL)) {
515                 wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_SET_OID_VALUE "
516                            "(oid=%08x) failed: %d", oid, (int) GetLastError());
517                 os_free(o);
518                 return -1;
519         }
520         os_free(o);
521         return 0;
522 #else /* CONFIG_USE_NDISUIO */
523         char *buf;
524         PACKET_OID_DATA *o;
525         char txt[50];
526
527         os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
528         wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len);
529
530         buf = os_zalloc(sizeof(*o) + len);
531         if (buf == NULL)
532                 return -1;
533         o = (PACKET_OID_DATA *) buf;
534         o->Oid = oid;
535         o->Length = len;
536         if (data)
537                 os_memcpy(o->Data, data, len);
538
539         if (!PacketRequest(drv->adapter, TRUE, o)) {
540                 wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
541                            __func__, oid, len);
542                 os_free(buf);
543                 return -1;
544         }
545         os_free(buf);
546         return 0;
547 #endif /* CONFIG_USE_NDISUIO */
548 }
549
550
551 static int ndis_set_auth_mode(struct wpa_driver_ndis_data *drv, int mode)
552 {
553         u32 auth_mode = mode;
554         if (ndis_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
555                          (char *) &auth_mode, sizeof(auth_mode)) < 0) {
556                 wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
557                            "OID_802_11_AUTHENTICATION_MODE (%d)",
558                            (int) auth_mode);
559                 return -1;
560         }
561         return 0;
562 }
563
564
565 static int ndis_get_auth_mode(struct wpa_driver_ndis_data *drv)
566 {
567         u32 auth_mode;
568         int res;
569         res = ndis_get_oid(drv, OID_802_11_AUTHENTICATION_MODE,
570                            (char *) &auth_mode, sizeof(auth_mode));
571         if (res != sizeof(auth_mode)) {
572                 wpa_printf(MSG_DEBUG, "NDIS: Failed to get "
573                            "OID_802_11_AUTHENTICATION_MODE");
574                 return -1;
575         }
576         return auth_mode;
577 }
578
579
580 static int ndis_set_encr_status(struct wpa_driver_ndis_data *drv, int encr)
581 {
582         u32 encr_status = encr;
583         if (ndis_set_oid(drv, OID_802_11_ENCRYPTION_STATUS,
584                          (char *) &encr_status, sizeof(encr_status)) < 0) {
585                 wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
586                            "OID_802_11_ENCRYPTION_STATUS (%d)", encr);
587                 return -1;
588         }
589         return 0;
590 }
591
592
593 static int ndis_get_encr_status(struct wpa_driver_ndis_data *drv)
594 {
595         u32 encr;
596         int res;
597         res = ndis_get_oid(drv, OID_802_11_ENCRYPTION_STATUS,
598                            (char *) &encr, sizeof(encr));
599         if (res != sizeof(encr)) {
600                 wpa_printf(MSG_DEBUG, "NDIS: Failed to get "
601                            "OID_802_11_ENCRYPTION_STATUS");
602                 return -1;
603         }
604         return encr;
605 }
606
607
608 static int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid)
609 {
610         struct wpa_driver_ndis_data *drv = priv;
611
612         if (drv->wired) {
613                 /*
614                  * Report PAE group address as the "BSSID" for wired
615                  * connection.
616                  */
617                 os_memcpy(bssid, pae_group_addr, ETH_ALEN);
618                 return 0;
619         }
620
621         return ndis_get_oid(drv, OID_802_11_BSSID, (char *) bssid, ETH_ALEN) <
622                 0 ? -1 : 0;
623 }
624
625
626 static int wpa_driver_ndis_get_ssid(void *priv, u8 *ssid)
627 {
628         struct wpa_driver_ndis_data *drv = priv;
629         NDIS_802_11_SSID buf;
630         int res;
631
632         res = ndis_get_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
633         if (res < 4) {
634                 wpa_printf(MSG_DEBUG, "NDIS: Failed to get SSID");
635                 if (drv->wired) {
636                         wpa_printf(MSG_DEBUG, "NDIS: Allow get_ssid failure "
637                                    "with a wired interface");
638                         return 0;
639                 }
640                 return -1;
641         }
642         os_memcpy(ssid, buf.Ssid, buf.SsidLength);
643         return buf.SsidLength;
644 }
645
646
647 static int wpa_driver_ndis_set_ssid(struct wpa_driver_ndis_data *drv,
648                                     const u8 *ssid, size_t ssid_len)
649 {
650         NDIS_802_11_SSID buf;
651
652         os_memset(&buf, 0, sizeof(buf));
653         buf.SsidLength = ssid_len;
654         os_memcpy(buf.Ssid, ssid, ssid_len);
655         /*
656          * Make sure radio is marked enabled here so that scan request will not
657          * force SSID to be changed to a random one in order to enable radio at
658          * that point.
659          */
660         drv->radio_enabled = 1;
661         return ndis_set_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
662 }
663
664
665 /* Disconnect using OID_802_11_DISASSOCIATE. This will also turn the radio off.
666  */
667 static int wpa_driver_ndis_radio_off(struct wpa_driver_ndis_data *drv)
668 {
669         drv->radio_enabled = 0;
670         return ndis_set_oid(drv, OID_802_11_DISASSOCIATE, "    ", 4);
671 }
672
673
674 /* Disconnect by setting SSID to random (i.e., likely not used). */
675 static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv)
676 {
677         char ssid[32];
678         int i;
679         for (i = 0; i < 32; i++)
680                 ssid[i] = rand() & 0xff;
681         return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32);
682 }
683
684
685 static int wpa_driver_ndis_deauthenticate(void *priv, const u8 *addr,
686                                           int reason_code)
687 {
688         struct wpa_driver_ndis_data *drv = priv;
689         return wpa_driver_ndis_disconnect(drv);
690 }
691
692
693 static int wpa_driver_ndis_disassociate(void *priv, const u8 *addr,
694                                         int reason_code)
695 {
696         struct wpa_driver_ndis_data *drv = priv;
697         return wpa_driver_ndis_disconnect(drv);
698 }
699
700
701 static int wpa_driver_ndis_set_wpa(void *priv, int enabled)
702 {
703         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
704         return 0;
705 }
706
707
708 static void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx)
709 {
710         wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
711         wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
712 }
713
714
715 static int wpa_driver_ndis_scan(void *priv, const u8 *ssid, size_t ssid_len)
716 {
717         struct wpa_driver_ndis_data *drv = priv;
718         int res;
719
720         if (!drv->radio_enabled) {
721                 wpa_printf(MSG_DEBUG, "NDIS: turning radio on before the first"
722                            " scan");
723                 if (wpa_driver_ndis_disconnect(drv) < 0) {
724                         wpa_printf(MSG_DEBUG, "NDIS: failed to enable radio");
725                 }
726                 drv->radio_enabled = 1;
727         }
728
729         res = ndis_set_oid(drv, OID_802_11_BSSID_LIST_SCAN, "    ", 4);
730         eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
731         eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv,
732                                drv->ctx);
733         return res;
734 }
735
736
737 static struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid(
738         struct wpa_scan_res *r, NDIS_802_11_SSID *ssid)
739 {
740         struct wpa_scan_res *nr;
741         u8 *pos;
742
743         if (wpa_scan_get_ie(r, WLAN_EID_SSID))
744                 return r; /* SSID IE already present */
745
746         if (ssid->SsidLength == 0 || ssid->SsidLength > 32)
747                 return r; /* No valid SSID inside scan data */
748
749         nr = os_realloc(r, sizeof(*r) + r->ie_len + 2 + ssid->SsidLength);
750         if (nr == NULL)
751                 return r;
752
753         pos = ((u8 *) (nr + 1)) + nr->ie_len;
754         *pos++ = WLAN_EID_SSID;
755         *pos++ = ssid->SsidLength;
756         os_memcpy(pos, ssid->Ssid, ssid->SsidLength);
757         nr->ie_len += 2 + ssid->SsidLength;
758
759         return nr;
760 }
761
762
763 static struct wpa_scan_results * wpa_driver_ndis_get_scan_results(void *priv)
764 {
765         struct wpa_driver_ndis_data *drv = priv;
766         NDIS_802_11_BSSID_LIST_EX *b;
767         size_t blen, count, i;
768         int len;
769         char *pos;
770         struct wpa_scan_results *results;
771         struct wpa_scan_res *r;
772
773         blen = 65535;
774         b = os_zalloc(blen);
775         if (b == NULL)
776                 return NULL;
777         len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
778         if (len < 0) {
779                 wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
780                 os_free(b);
781                 return NULL;
782         }
783         count = b->NumberOfItems;
784
785         results = os_zalloc(sizeof(*results));
786         if (results == NULL) {
787                 os_free(b);
788                 return NULL;
789         }
790         results->res = os_zalloc(count * sizeof(struct wpa_scan_res *));
791         if (results->res == NULL) {
792                 os_free(results);
793                 os_free(b);
794                 return NULL;
795         }
796
797         pos = (char *) &b->Bssid[0];
798         for (i = 0; i < count; i++) {
799                 NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
800                 NDIS_802_11_FIXED_IEs *fixed;
801
802                 if (bss->IELength < sizeof(NDIS_802_11_FIXED_IEs)) {
803                         wpa_printf(MSG_DEBUG, "NDIS: too small IELength=%d",
804                                    (int) bss->IELength);
805                         break;
806                 }
807                 if (((char *) bss->IEs) + bss->IELength  > (char *) b + blen) {
808                         /*
809                          * Some NDIS drivers have been reported to include an
810                          * entry with an invalid IELength in scan results and
811                          * this has crashed wpa_supplicant, so validate the
812                          * returned value before using it.
813                          */
814                         wpa_printf(MSG_DEBUG, "NDIS: skipped invalid scan "
815                                    "result IE (BSSID=" MACSTR ") IELength=%d",
816                                    MAC2STR(bss->MacAddress),
817                                    (int) bss->IELength);
818                         break;
819                 }
820
821                 r = os_zalloc(sizeof(*r) + bss->IELength -
822                               sizeof(NDIS_802_11_FIXED_IEs));
823                 if (r == NULL)
824                         break;
825
826                 os_memcpy(r->bssid, bss->MacAddress, ETH_ALEN);
827                 r->level = (int) bss->Rssi;
828                 r->freq = bss->Configuration.DSConfig / 1000;
829                 fixed = (NDIS_802_11_FIXED_IEs *) bss->IEs;
830                 r->beacon_int = WPA_GET_LE16((u8 *) &fixed->BeaconInterval);
831                 r->caps = WPA_GET_LE16((u8 *) &fixed->Capabilities);
832                 r->tsf = WPA_GET_LE64(fixed->Timestamp);
833                 os_memcpy(r + 1, bss->IEs + sizeof(NDIS_802_11_FIXED_IEs),
834                           bss->IELength - sizeof(NDIS_802_11_FIXED_IEs));
835                 r->ie_len = bss->IELength - sizeof(NDIS_802_11_FIXED_IEs);
836                 r = wpa_driver_ndis_add_scan_ssid(r, &bss->Ssid);
837
838                 results->res[results->num++] = r;
839
840                 pos += bss->Length;
841                 if (pos > (char *) b + blen)
842                         break;
843         }
844
845         os_free(b);
846
847         return results;
848 }
849
850
851 static int wpa_driver_ndis_remove_key(struct wpa_driver_ndis_data *drv,
852                                       int key_idx, const u8 *addr,
853                                       const u8 *bssid, int pairwise)
854 {
855         NDIS_802_11_REMOVE_KEY rkey;
856         NDIS_802_11_KEY_INDEX index;
857         int res, res2;
858
859         os_memset(&rkey, 0, sizeof(rkey));
860
861         rkey.Length = sizeof(rkey);
862         rkey.KeyIndex = key_idx;
863         if (pairwise)
864                 rkey.KeyIndex |= 1 << 30;
865         os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
866
867         res = ndis_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
868                            sizeof(rkey));
869         if (!pairwise) {
870                 index = key_idx;
871                 res2 = ndis_set_oid(drv, OID_802_11_REMOVE_WEP,
872                                     (char *) &index, sizeof(index));
873         } else
874                 res2 = 0;
875
876         if (res < 0 && res2 < 0)
877                 return -1;
878         return 0;
879 }
880
881
882 static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv,
883                                    int pairwise, int key_idx, int set_tx,
884                                    const u8 *key, size_t key_len)
885 {
886         NDIS_802_11_WEP *wep;
887         size_t len;
888         int res;
889
890         len = 12 + key_len;
891         wep = os_zalloc(len);
892         if (wep == NULL)
893                 return -1;
894         wep->Length = len;
895         wep->KeyIndex = key_idx;
896         if (set_tx)
897                 wep->KeyIndex |= 1 << 31;
898 #if 0 /* Setting bit30 does not seem to work with some NDIS drivers */
899         if (pairwise)
900                 wep->KeyIndex |= 1 << 30;
901 #endif
902         wep->KeyLength = key_len;
903         os_memcpy(wep->KeyMaterial, key, key_len);
904
905         wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_WEP",
906                         (u8 *) wep, len);
907         res = ndis_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
908
909         os_free(wep);
910
911         return res;
912 }
913
914
915 static int wpa_driver_ndis_set_key(void *priv, wpa_alg alg, const u8 *addr,
916                                    int key_idx, int set_tx,
917                                    const u8 *seq, size_t seq_len,
918                                    const u8 *key, size_t key_len)
919 {
920         struct wpa_driver_ndis_data *drv = priv;
921         size_t len, i;
922         NDIS_802_11_KEY *nkey;
923         int res, pairwise;
924         u8 bssid[ETH_ALEN];
925
926         if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
927                                       ETH_ALEN) == 0) {
928                 /* Group Key */
929                 pairwise = 0;
930                 if (wpa_driver_ndis_get_bssid(drv, bssid) < 0)
931                         os_memset(bssid, 0xff, ETH_ALEN);
932         } else {
933                 /* Pairwise Key */
934                 pairwise = 1;
935                 os_memcpy(bssid, addr, ETH_ALEN);
936         }
937
938         if (alg == WPA_ALG_NONE || key_len == 0) {
939                 return wpa_driver_ndis_remove_key(drv, key_idx, addr, bssid,
940                                                   pairwise);
941         }
942
943         if (alg == WPA_ALG_WEP) {
944                 return wpa_driver_ndis_add_wep(drv, pairwise, key_idx, set_tx,
945                                                key, key_len);
946         }
947
948         len = 12 + 6 + 6 + 8 + key_len;
949
950         nkey = os_zalloc(len);
951         if (nkey == NULL)
952                 return -1;
953
954         nkey->Length = len;
955         nkey->KeyIndex = key_idx;
956         if (set_tx)
957                 nkey->KeyIndex |= 1 << 31;
958         if (pairwise)
959                 nkey->KeyIndex |= 1 << 30;
960         if (seq && seq_len)
961                 nkey->KeyIndex |= 1 << 29;
962         nkey->KeyLength = key_len;
963         os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
964         if (seq && seq_len) {
965                 for (i = 0; i < seq_len; i++)
966                         nkey->KeyRSC |= (ULONGLONG) seq[i] << (i * 8);
967         }
968         if (alg == WPA_ALG_TKIP && key_len == 32) {
969                 os_memcpy(nkey->KeyMaterial, key, 16);
970                 os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
971                 os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
972         } else {
973                 os_memcpy(nkey->KeyMaterial, key, key_len);
974         }
975
976         wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_KEY",
977                         (u8 *) nkey, len);
978         res = ndis_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
979         os_free(nkey);
980
981         return res;
982 }
983
984
985 static int
986 wpa_driver_ndis_associate(void *priv,
987                           struct wpa_driver_associate_params *params)
988 {
989         struct wpa_driver_ndis_data *drv = priv;
990         u32 auth_mode, encr, priv_mode, mode;
991
992         drv->mode = params->mode;
993
994         /* Note: Setting OID_802_11_INFRASTRUCTURE_MODE clears current keys,
995          * so static WEP keys needs to be set again after this. */
996         if (params->mode == IEEE80211_MODE_IBSS) {
997                 mode = Ndis802_11IBSS;
998                 /* Need to make sure that BSSID polling is enabled for
999                  * IBSS mode. */
1000                 eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
1001                 eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout,
1002                                        drv, NULL);
1003         } else
1004                 mode = Ndis802_11Infrastructure;
1005         if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
1006                          (char *) &mode, sizeof(mode)) < 0) {
1007                 wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
1008                            "OID_802_11_INFRASTRUCTURE_MODE (%d)",
1009                            (int) mode);
1010                 /* Try to continue anyway */
1011         }
1012
1013         if (params->key_mgmt_suite == KEY_MGMT_NONE ||
1014             params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
1015                 /* Re-set WEP keys if static WEP configuration is used. */
1016                 u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1017                 int i;
1018                 for (i = 0; i < 4; i++) {
1019                         if (!params->wep_key[i])
1020                                 continue;
1021                         wpa_printf(MSG_DEBUG, "NDIS: Re-setting static WEP "
1022                                    "key %d", i);
1023                         wpa_driver_ndis_set_key(drv, WPA_ALG_WEP, bcast, i,
1024                                                 i == params->wep_tx_keyidx,
1025                                                 NULL, 0, params->wep_key[i],
1026                                                 params->wep_key_len[i]);
1027                 }
1028         }
1029
1030         if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
1031                 if (params->auth_alg & AUTH_ALG_SHARED_KEY) {
1032                         if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
1033                                 auth_mode = Ndis802_11AuthModeAutoSwitch;
1034                         else
1035                                 auth_mode = Ndis802_11AuthModeShared;
1036                 } else
1037                         auth_mode = Ndis802_11AuthModeOpen;
1038                 priv_mode = Ndis802_11PrivFilterAcceptAll;
1039         } else if (params->wpa_ie[0] == WLAN_EID_RSN) {
1040                 priv_mode = Ndis802_11PrivFilter8021xWEP;
1041                 if (params->key_mgmt_suite == KEY_MGMT_PSK)
1042                         auth_mode = Ndis802_11AuthModeWPA2PSK;
1043                 else
1044                         auth_mode = Ndis802_11AuthModeWPA2;
1045 #ifdef CONFIG_WPS
1046         } else if (params->key_mgmt_suite == KEY_MGMT_WPS) {
1047                 auth_mode = Ndis802_11AuthModeOpen;
1048                 priv_mode = Ndis802_11PrivFilterAcceptAll;
1049 #endif /* CONFIG_WPS */
1050         } else {
1051                 priv_mode = Ndis802_11PrivFilter8021xWEP;
1052                 if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
1053                         auth_mode = Ndis802_11AuthModeWPANone;
1054                 else if (params->key_mgmt_suite == KEY_MGMT_PSK)
1055                         auth_mode = Ndis802_11AuthModeWPAPSK;
1056                 else
1057                         auth_mode = Ndis802_11AuthModeWPA;
1058         }
1059
1060         switch (params->pairwise_suite) {
1061         case CIPHER_CCMP:
1062                 encr = Ndis802_11Encryption3Enabled;
1063                 break;
1064         case CIPHER_TKIP:
1065                 encr = Ndis802_11Encryption2Enabled;
1066                 break;
1067         case CIPHER_WEP40:
1068         case CIPHER_WEP104:
1069                 encr = Ndis802_11Encryption1Enabled;
1070                 break;
1071         case CIPHER_NONE:
1072                 if (params->group_suite == CIPHER_CCMP)
1073                         encr = Ndis802_11Encryption3Enabled;
1074                 else if (params->group_suite == CIPHER_TKIP)
1075                         encr = Ndis802_11Encryption2Enabled;
1076                 else
1077                         encr = Ndis802_11EncryptionDisabled;
1078                 break;
1079         default:
1080                 encr = Ndis802_11EncryptionDisabled;
1081         };
1082
1083         if (ndis_set_oid(drv, OID_802_11_PRIVACY_FILTER,
1084                          (char *) &priv_mode, sizeof(priv_mode)) < 0) {
1085                 wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
1086                            "OID_802_11_PRIVACY_FILTER (%d)",
1087                            (int) priv_mode);
1088                 /* Try to continue anyway */
1089         }
1090
1091         ndis_set_auth_mode(drv, auth_mode);
1092         ndis_set_encr_status(drv, encr);
1093
1094         if (params->bssid) {
1095                 ndis_set_oid(drv, OID_802_11_BSSID, (char *) params->bssid,
1096                              ETH_ALEN);
1097                 drv->oid_bssid_set = 1;
1098         } else if (drv->oid_bssid_set) {
1099                 ndis_set_oid(drv, OID_802_11_BSSID, "\xff\xff\xff\xff\xff\xff",
1100                              ETH_ALEN);
1101                 drv->oid_bssid_set = 0;
1102         }
1103
1104         return wpa_driver_ndis_set_ssid(drv, params->ssid, params->ssid_len);
1105 }
1106
1107
1108 static int wpa_driver_ndis_set_pmkid(struct wpa_driver_ndis_data *drv)
1109 {
1110         int len, count, i, ret;
1111         struct ndis_pmkid_entry *entry;
1112         NDIS_802_11_PMKID *p;
1113
1114         count = 0;
1115         entry = drv->pmkid;
1116         while (entry) {
1117                 count++;
1118                 if (count >= drv->no_of_pmkid)
1119                         break;
1120                 entry = entry->next;
1121         }
1122         len = 8 + count * sizeof(BSSID_INFO);
1123         p = os_zalloc(len);
1124         if (p == NULL)
1125                 return -1;
1126
1127         p->Length = len;
1128         p->BSSIDInfoCount = count;
1129         entry = drv->pmkid;
1130         for (i = 0; i < count; i++) {
1131                 os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
1132                 os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
1133                 entry = entry->next;
1134         }
1135         wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", (u8 *) p, len);
1136         ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
1137         os_free(p);
1138         return ret;
1139 }
1140
1141
1142 static int wpa_driver_ndis_add_pmkid(void *priv, const u8 *bssid,
1143                                      const u8 *pmkid)
1144 {
1145         struct wpa_driver_ndis_data *drv = priv;
1146         struct ndis_pmkid_entry *entry, *prev;
1147
1148         if (drv->no_of_pmkid == 0)
1149                 return 0;
1150
1151         prev = NULL;
1152         entry = drv->pmkid;
1153         while (entry) {
1154                 if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
1155                         break;
1156                 prev = entry;
1157                 entry = entry->next;
1158         }
1159
1160         if (entry) {
1161                 /* Replace existing entry for this BSSID and move it into the
1162                  * beginning of the list. */
1163                 os_memcpy(entry->pmkid, pmkid, 16);
1164                 if (prev) {
1165                         prev->next = entry->next;
1166                         entry->next = drv->pmkid;
1167                         drv->pmkid = entry;
1168                 }
1169         } else {
1170                 entry = os_malloc(sizeof(*entry));
1171                 if (entry) {
1172                         os_memcpy(entry->bssid, bssid, ETH_ALEN);
1173                         os_memcpy(entry->pmkid, pmkid, 16);
1174                         entry->next = drv->pmkid;
1175                         drv->pmkid = entry;
1176                 }
1177         }
1178
1179         return wpa_driver_ndis_set_pmkid(drv);
1180 }
1181
1182
1183 static int wpa_driver_ndis_remove_pmkid(void *priv, const u8 *bssid,
1184                                         const u8 *pmkid)
1185 {
1186         struct wpa_driver_ndis_data *drv = priv;
1187         struct ndis_pmkid_entry *entry, *prev;
1188
1189         if (drv->no_of_pmkid == 0)
1190                 return 0;
1191
1192         entry = drv->pmkid;
1193         prev = NULL;
1194         while (entry) {
1195                 if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
1196                     os_memcmp(entry->pmkid, pmkid, 16) == 0) {
1197                         if (prev)
1198                                 prev->next = entry->next;
1199                         else
1200                                 drv->pmkid = entry->next;
1201                         os_free(entry);
1202                         break;
1203                 }
1204                 prev = entry;
1205                 entry = entry->next;
1206         }
1207         return wpa_driver_ndis_set_pmkid(drv);
1208 }
1209
1210
1211 static int wpa_driver_ndis_flush_pmkid(void *priv)
1212 {
1213         struct wpa_driver_ndis_data *drv = priv;
1214         NDIS_802_11_PMKID p;
1215         struct ndis_pmkid_entry *pmkid, *prev;
1216         int prev_authmode, ret;
1217
1218         if (drv->no_of_pmkid == 0)
1219                 return 0;
1220
1221         pmkid = drv->pmkid;
1222         drv->pmkid = NULL;
1223         while (pmkid) {
1224                 prev = pmkid;
1225                 pmkid = pmkid->next;
1226                 os_free(prev);
1227         }
1228
1229         /*
1230          * Some drivers may refuse OID_802_11_PMKID if authMode is not set to
1231          * WPA2, so change authMode temporarily, if needed.
1232          */
1233         prev_authmode = ndis_get_auth_mode(drv);
1234         if (prev_authmode != Ndis802_11AuthModeWPA2)
1235                 ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA2);
1236
1237         os_memset(&p, 0, sizeof(p));
1238         p.Length = 8;
1239         p.BSSIDInfoCount = 0;
1240         wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
1241                     (u8 *) &p, 8);
1242         ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
1243
1244         if (prev_authmode != Ndis802_11AuthModeWPA2)
1245                 ndis_set_auth_mode(drv, prev_authmode);
1246
1247         return ret;
1248 }
1249
1250
1251 static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
1252 {
1253         char buf[512], *pos;
1254         NDIS_802_11_ASSOCIATION_INFORMATION *ai;
1255         int len;
1256         union wpa_event_data data;
1257         NDIS_802_11_BSSID_LIST_EX *b;
1258         size_t blen, i;
1259
1260         len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, buf,
1261                            sizeof(buf));
1262         if (len < 0) {
1263                 wpa_printf(MSG_DEBUG, "NDIS: failed to get association "
1264                            "information");
1265                 return -1;
1266         }
1267         if (len > sizeof(buf)) {
1268                 /* Some drivers seem to be producing incorrect length for this
1269                  * data. Limit the length to the current buffer size to avoid
1270                  * crashing in hexdump. The data seems to be otherwise valid,
1271                  * so better try to use it. */
1272                 wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association "
1273                            "information length %d", len);
1274                 len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION,
1275                                    buf, sizeof(buf));
1276                 if (len < -1) {
1277                         wpa_printf(MSG_DEBUG, "NDIS: re-reading association "
1278                                    "information failed");
1279                         return -1;
1280                 }
1281                 if (len > sizeof(buf)) {
1282                         wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association"
1283                                    " information length %d (re-read)", len);
1284                         len = sizeof(buf);
1285                 }
1286         }
1287         wpa_hexdump(MSG_MSGDUMP, "NDIS: association information",
1288                     (u8 *) buf, len);
1289         if (len < sizeof(*ai)) {
1290                 wpa_printf(MSG_DEBUG, "NDIS: too short association "
1291                            "information");
1292                 return -1;
1293         }
1294         ai = (NDIS_802_11_ASSOCIATION_INFORMATION *) buf;
1295         wpa_printf(MSG_DEBUG, "NDIS: ReqFixed=0x%x RespFixed=0x%x off_req=%d "
1296                    "off_resp=%d len_req=%d len_resp=%d",
1297                    ai->AvailableRequestFixedIEs, ai->AvailableResponseFixedIEs,
1298                    (int) ai->OffsetRequestIEs, (int) ai->OffsetResponseIEs,
1299                    (int) ai->RequestIELength, (int) ai->ResponseIELength);
1300
1301         if (ai->OffsetRequestIEs + ai->RequestIELength > (unsigned) len ||
1302             ai->OffsetResponseIEs + ai->ResponseIELength > (unsigned) len) {
1303                 wpa_printf(MSG_DEBUG, "NDIS: association information - "
1304                            "IE overflow");
1305                 return -1;
1306         }
1307
1308         wpa_hexdump(MSG_MSGDUMP, "NDIS: Request IEs",
1309                     (u8 *) buf + ai->OffsetRequestIEs, ai->RequestIELength);
1310         wpa_hexdump(MSG_MSGDUMP, "NDIS: Response IEs",
1311                     (u8 *) buf + ai->OffsetResponseIEs, ai->ResponseIELength);
1312
1313         os_memset(&data, 0, sizeof(data));
1314         data.assoc_info.req_ies = (u8 *) buf + ai->OffsetRequestIEs;
1315         data.assoc_info.req_ies_len = ai->RequestIELength;
1316         data.assoc_info.resp_ies = (u8 *) buf + ai->OffsetResponseIEs;
1317         data.assoc_info.resp_ies_len = ai->ResponseIELength;
1318
1319         blen = 65535;
1320         b = os_zalloc(blen);
1321         if (b == NULL)
1322                 goto skip_scan_results;
1323         len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
1324         if (len < 0) {
1325                 wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
1326                 os_free(b);
1327                 b = NULL;
1328                 goto skip_scan_results;
1329         }
1330         wpa_printf(MSG_DEBUG, "NDIS: %d BSSID items to process for AssocInfo",
1331                    (unsigned int) b->NumberOfItems);
1332
1333         pos = (char *) &b->Bssid[0];
1334         for (i = 0; i < b->NumberOfItems; i++) {
1335                 NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
1336                 if (os_memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 &&
1337                     bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) {
1338                         data.assoc_info.beacon_ies =
1339                                 ((u8 *) bss->IEs) +
1340                                 sizeof(NDIS_802_11_FIXED_IEs);
1341                         data.assoc_info.beacon_ies_len =
1342                                 bss->IELength - sizeof(NDIS_802_11_FIXED_IEs);
1343                         wpa_hexdump(MSG_MSGDUMP, "NDIS: Beacon IEs",
1344                                     data.assoc_info.beacon_ies,
1345                                     data.assoc_info.beacon_ies_len);
1346                         break;
1347                 }
1348                 pos += bss->Length;
1349                 if (pos > (char *) b + blen)
1350                         break;
1351         }
1352
1353 skip_scan_results:
1354         wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
1355
1356         os_free(b);
1357
1358         return 0;
1359 }
1360
1361
1362 static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx)
1363 {
1364         struct wpa_driver_ndis_data *drv = eloop_ctx;
1365         u8 bssid[ETH_ALEN];
1366         int poll;
1367
1368         if (drv->wired)
1369                 return;
1370
1371         if (wpa_driver_ndis_get_bssid(drv, bssid)) {
1372                 /* Disconnected */
1373                 if (!is_zero_ether_addr(drv->bssid)) {
1374                         os_memset(drv->bssid, 0, ETH_ALEN);
1375                         wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
1376                 }
1377         } else {
1378                 /* Connected */
1379                 if (os_memcmp(drv->bssid, bssid, ETH_ALEN) != 0) {
1380                         os_memcpy(drv->bssid, bssid, ETH_ALEN);
1381                         wpa_driver_ndis_get_associnfo(drv);
1382                         wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
1383                 }
1384         }
1385
1386         /* When using integrated NDIS event receiver, we can skip BSSID
1387          * polling when using infrastructure network. However, when using
1388          * IBSS mode, many driver do not seem to generate connection event,
1389          * so we need to enable BSSID polling to figure out when IBSS network
1390          * has been formed.
1391          */
1392         poll = drv->mode == IEEE80211_MODE_IBSS;
1393 #ifndef CONFIG_NDIS_EVENTS_INTEGRATED
1394 #ifndef _WIN32_WCE
1395         poll = 1;
1396 #endif /* _WIN32_WCE */
1397 #endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
1398
1399         if (poll) {
1400                 eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout,
1401                                         drv, NULL);
1402         }
1403 }
1404
1405
1406 static void wpa_driver_ndis_poll(void *priv)
1407 {
1408         struct wpa_driver_ndis_data *drv = priv;
1409         eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
1410         wpa_driver_ndis_poll_timeout(drv, NULL);
1411 }
1412
1413
1414 /* Called when driver generates Media Connect Event by calling
1415  * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_CONNECT */
1416 void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv)
1417 {
1418         wpa_printf(MSG_DEBUG, "NDIS: Media Connect Event");
1419         if (wpa_driver_ndis_get_bssid(drv, drv->bssid) == 0) {
1420                 wpa_driver_ndis_get_associnfo(drv);
1421                 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
1422         }
1423 }
1424
1425
1426 /* Called when driver generates Media Disconnect Event by calling
1427  * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_DISCONNECT */
1428 void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv)
1429 {
1430         wpa_printf(MSG_DEBUG, "NDIS: Media Disconnect Event");
1431         os_memset(drv->bssid, 0, ETH_ALEN);
1432         wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
1433 }
1434
1435
1436 static void wpa_driver_ndis_event_auth(struct wpa_driver_ndis_data *drv,
1437                                        const u8 *data, size_t data_len)
1438 {
1439         NDIS_802_11_AUTHENTICATION_REQUEST *req;
1440         int pairwise = 0, group = 0;
1441         union wpa_event_data event;
1442
1443         if (data_len < sizeof(*req)) {
1444                 wpa_printf(MSG_DEBUG, "NDIS: Too short Authentication Request "
1445                            "Event (len=%d)", data_len);
1446                 return;
1447         }
1448         req = (NDIS_802_11_AUTHENTICATION_REQUEST *) data;
1449
1450         wpa_printf(MSG_DEBUG, "NDIS: Authentication Request Event: "
1451                    "Bssid " MACSTR " Flags 0x%x",
1452                    MAC2STR(req->Bssid), (int) req->Flags);
1453
1454         if ((req->Flags & NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR) ==
1455             NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR)
1456                 pairwise = 1;
1457         else if ((req->Flags & NDIS_802_11_AUTH_REQUEST_GROUP_ERROR) ==
1458             NDIS_802_11_AUTH_REQUEST_GROUP_ERROR)
1459                 group = 1;
1460
1461         if (pairwise || group) {
1462                 os_memset(&event, 0, sizeof(event));
1463                 event.michael_mic_failure.unicast = pairwise;
1464                 wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE,
1465                                      &event);
1466         }
1467 }
1468
1469
1470 static void wpa_driver_ndis_event_pmkid(struct wpa_driver_ndis_data *drv,
1471                                         const u8 *data, size_t data_len)
1472 {
1473         NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
1474         size_t i;
1475         union wpa_event_data event;
1476
1477         if (data_len < 8) {
1478                 wpa_printf(MSG_DEBUG, "NDIS: Too short PMKID Candidate List "
1479                            "Event (len=%d)", data_len);
1480                 return;
1481         }
1482         pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
1483         wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List Event - Version %d "
1484                    "NumCandidates %d",
1485                    (int) pmkid->Version, (int) pmkid->NumCandidates);
1486
1487         if (pmkid->Version != 1) {
1488                 wpa_printf(MSG_DEBUG, "NDIS: Unsupported PMKID Candidate List "
1489                            "Version %d", (int) pmkid->Version);
1490                 return;
1491         }
1492
1493         if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
1494                 wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List underflow");
1495                 return;
1496         }
1497
1498         os_memset(&event, 0, sizeof(event));
1499         for (i = 0; i < pmkid->NumCandidates; i++) {
1500                 PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
1501                 wpa_printf(MSG_DEBUG, "NDIS: %d: " MACSTR " Flags 0x%x",
1502                            i, MAC2STR(p->BSSID), (int) p->Flags);
1503                 os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
1504                 event.pmkid_candidate.index = i;
1505                 event.pmkid_candidate.preauth =
1506                         p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
1507                 wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
1508                                      &event);
1509         }
1510 }
1511
1512
1513 /* Called when driver calls NdisMIndicateStatus() with
1514  * NDIS_STATUS_MEDIA_SPECIFIC_INDICATION */
1515 void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv,
1516                                           const u8 *data, size_t data_len)
1517 {
1518         NDIS_802_11_STATUS_INDICATION *status;
1519
1520         if (data == NULL || data_len < sizeof(*status))
1521                 return;
1522
1523         wpa_hexdump(MSG_DEBUG, "NDIS: Media Specific Indication",
1524                     data, data_len);
1525
1526         status = (NDIS_802_11_STATUS_INDICATION *) data;
1527         data += sizeof(status);
1528         data_len -= sizeof(status);
1529
1530         switch (status->StatusType) {
1531         case Ndis802_11StatusType_Authentication:
1532                 wpa_driver_ndis_event_auth(drv, data, data_len);
1533                 break;
1534         case Ndis802_11StatusType_PMKID_CandidateList:
1535                 wpa_driver_ndis_event_pmkid(drv, data, data_len);
1536                 break;
1537         default:
1538                 wpa_printf(MSG_DEBUG, "NDIS: Unknown StatusType %d",
1539                            (int) status->StatusType);
1540                 break;
1541         }
1542 }
1543
1544
1545 /* Called when an adapter is added */
1546 void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv)
1547 {
1548         union wpa_event_data event;
1549         int i;
1550
1551         wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Arrival");
1552
1553         for (i = 0; i < 30; i++) {
1554                 /* Re-open Packet32/NDISUIO connection */
1555                 wpa_driver_ndis_adapter_close(drv);
1556                 if (wpa_driver_ndis_adapter_init(drv) < 0 ||
1557                     wpa_driver_ndis_adapter_open(drv) < 0) {
1558                         wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialization "
1559                                    "(%d) failed", i);
1560                         os_sleep(1, 0);
1561                 } else {
1562                         wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialized");
1563                         break;
1564                 }
1565         }
1566
1567         os_memset(&event, 0, sizeof(event));
1568         os_strlcpy(event.interface_status.ifname, drv->ifname,
1569                    sizeof(event.interface_status.ifname));
1570         event.interface_status.ievent = EVENT_INTERFACE_ADDED;
1571         wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1572 }
1573
1574
1575 /* Called when an adapter is removed */
1576 void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv)
1577 {
1578         union wpa_event_data event;
1579
1580         wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Removal");
1581         os_memset(&event, 0, sizeof(event));
1582         os_strlcpy(event.interface_status.ifname, drv->ifname,
1583                    sizeof(event.interface_status.ifname));
1584         event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
1585         wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1586 }
1587
1588
1589 static void
1590 wpa_driver_ndis_get_wpa_capability(struct wpa_driver_ndis_data *drv)
1591 {
1592         wpa_printf(MSG_DEBUG, "NDIS: verifying driver WPA capability");
1593
1594         if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA) == 0 &&
1595             ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPA) {
1596                 wpa_printf(MSG_DEBUG, "NDIS: WPA key management supported");
1597                 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA;
1598         }
1599
1600         if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPAPSK) == 0 &&
1601             ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPAPSK) {
1602                 wpa_printf(MSG_DEBUG, "NDIS: WPA-PSK key management "
1603                            "supported");
1604                 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
1605         }
1606
1607         if (ndis_set_encr_status(drv, Ndis802_11Encryption3Enabled) == 0 &&
1608             ndis_get_encr_status(drv) == Ndis802_11Encryption3KeyAbsent) {
1609                 wpa_printf(MSG_DEBUG, "NDIS: CCMP encryption supported");
1610                 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
1611         }
1612
1613         if (ndis_set_encr_status(drv, Ndis802_11Encryption2Enabled) == 0 &&
1614             ndis_get_encr_status(drv) == Ndis802_11Encryption2KeyAbsent) {
1615                 wpa_printf(MSG_DEBUG, "NDIS: TKIP encryption supported");
1616                 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
1617         }
1618
1619         if (ndis_set_encr_status(drv, Ndis802_11Encryption1Enabled) == 0 &&
1620             ndis_get_encr_status(drv) == Ndis802_11Encryption1KeyAbsent) {
1621                 wpa_printf(MSG_DEBUG, "NDIS: WEP encryption supported");
1622                 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
1623                         WPA_DRIVER_CAPA_ENC_WEP104;
1624         }
1625
1626         if (ndis_set_auth_mode(drv, Ndis802_11AuthModeShared) == 0 &&
1627             ndis_get_auth_mode(drv) == Ndis802_11AuthModeShared) {
1628                 drv->capa.auth |= WPA_DRIVER_AUTH_SHARED;
1629         }
1630
1631         if (ndis_set_auth_mode(drv, Ndis802_11AuthModeOpen) == 0 &&
1632             ndis_get_auth_mode(drv) == Ndis802_11AuthModeOpen) {
1633                 drv->capa.auth |= WPA_DRIVER_AUTH_OPEN;
1634         }
1635
1636         ndis_set_encr_status(drv, Ndis802_11EncryptionDisabled);
1637
1638         /* Could also verify OID_802_11_ADD_KEY error reporting and
1639          * support for OID_802_11_ASSOCIATION_INFORMATION. */
1640
1641         if (drv->capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA &&
1642             drv->capa.enc & (WPA_DRIVER_CAPA_ENC_TKIP |
1643                              WPA_DRIVER_CAPA_ENC_CCMP)) {
1644                 wpa_printf(MSG_DEBUG, "NDIS: driver supports WPA");
1645                 drv->has_capability = 1;
1646         } else {
1647                 wpa_printf(MSG_DEBUG, "NDIS: no WPA support found");
1648         }
1649
1650         wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x "
1651                    "enc 0x%x auth 0x%x",
1652                    drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth);
1653 }
1654
1655
1656 static void wpa_driver_ndis_get_capability(struct wpa_driver_ndis_data *drv)
1657 {
1658         char buf[512];
1659         int len;
1660         size_t i;
1661         NDIS_802_11_CAPABILITY *c;
1662
1663         drv->capa.flags = WPA_DRIVER_FLAGS_DRIVER_IE;
1664
1665         len = ndis_get_oid(drv, OID_802_11_CAPABILITY, buf, sizeof(buf));
1666         if (len < 0) {
1667                 wpa_driver_ndis_get_wpa_capability(drv);
1668                 return;
1669         }
1670
1671         wpa_hexdump(MSG_MSGDUMP, "OID_802_11_CAPABILITY", (u8 *) buf, len);
1672         c = (NDIS_802_11_CAPABILITY *) buf;
1673         if (len < sizeof(*c) || c->Version != 2) {
1674                 wpa_printf(MSG_DEBUG, "NDIS: unsupported "
1675                            "OID_802_11_CAPABILITY data");
1676                 return;
1677         }
1678         wpa_printf(MSG_DEBUG, "NDIS: Driver supports OID_802_11_CAPABILITY - "
1679                    "NoOfPMKIDs %d NoOfAuthEncrPairs %d",
1680                    (int) c->NoOfPMKIDs,
1681                    (int) c->NoOfAuthEncryptPairsSupported);
1682         drv->has_capability = 1;
1683         drv->no_of_pmkid = c->NoOfPMKIDs;
1684         for (i = 0; i < c->NoOfAuthEncryptPairsSupported; i++) {
1685                 NDIS_802_11_AUTHENTICATION_ENCRYPTION *ae;
1686                 ae = &c->AuthenticationEncryptionSupported[i];
1687                 if ((char *) (ae + 1) > buf + len) {
1688                         wpa_printf(MSG_DEBUG, "NDIS: auth/encr pair list "
1689                                    "overflow");
1690                         break;
1691                 }
1692                 wpa_printf(MSG_MSGDUMP, "NDIS: %d - auth %d encr %d",
1693                            i, (int) ae->AuthModeSupported,
1694                            (int) ae->EncryptStatusSupported);
1695                 switch (ae->AuthModeSupported) {
1696                 case Ndis802_11AuthModeOpen:
1697                         drv->capa.auth |= WPA_DRIVER_AUTH_OPEN;
1698                         break;
1699                 case Ndis802_11AuthModeShared:
1700                         drv->capa.auth |= WPA_DRIVER_AUTH_SHARED;
1701                         break;
1702                 case Ndis802_11AuthModeWPA:
1703                         drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA;
1704                         break;
1705                 case Ndis802_11AuthModeWPAPSK:
1706                         drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
1707                         break;
1708                 case Ndis802_11AuthModeWPA2:
1709                         drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2;
1710                         break;
1711                 case Ndis802_11AuthModeWPA2PSK:
1712                         drv->capa.key_mgmt |=
1713                                 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
1714                         break;
1715                 case Ndis802_11AuthModeWPANone:
1716                         drv->capa.key_mgmt |=
1717                                 WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE;
1718                         break;
1719                 default:
1720                         break;
1721                 }
1722                 switch (ae->EncryptStatusSupported) {
1723                 case Ndis802_11Encryption1Enabled:
1724                         drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40;
1725                         drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP104;
1726                         break;
1727                 case Ndis802_11Encryption2Enabled:
1728                         drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
1729                         break;
1730                 case Ndis802_11Encryption3Enabled:
1731                         drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
1732                         break;
1733                 default:
1734                         break;
1735                 }
1736         }
1737
1738         wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x "
1739                    "enc 0x%x auth 0x%x",
1740                    drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth);
1741 }
1742
1743
1744 static int wpa_driver_ndis_get_capa(void *priv, struct wpa_driver_capa *capa)
1745 {
1746         struct wpa_driver_ndis_data *drv = priv;
1747         if (!drv->has_capability)
1748                 return -1;
1749         os_memcpy(capa, &drv->capa, sizeof(*capa));
1750         return 0;
1751 }
1752
1753
1754 static const char * wpa_driver_ndis_get_ifname(void *priv)
1755 {
1756         struct wpa_driver_ndis_data *drv = priv;
1757         return drv->ifname;
1758 }
1759
1760
1761 static const u8 * wpa_driver_ndis_get_mac_addr(void *priv)
1762 {
1763         struct wpa_driver_ndis_data *drv = priv;
1764         return drv->own_addr;
1765 }
1766
1767
1768 #ifdef _WIN32_WCE
1769
1770 #define NDISUIO_MSG_SIZE (sizeof(NDISUIO_DEVICE_NOTIFICATION) + 512)
1771
1772 static void ndisuio_notification_receive(void *eloop_data, void *user_ctx)
1773 {
1774         struct wpa_driver_ndis_data *drv = eloop_data;
1775         NDISUIO_DEVICE_NOTIFICATION *hdr;
1776         u8 buf[NDISUIO_MSG_SIZE];
1777         DWORD len, flags;
1778
1779         if (!ReadMsgQueue(drv->event_queue, buf, NDISUIO_MSG_SIZE, &len, 0,
1780                           &flags)) {
1781                 wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: "
1782                            "ReadMsgQueue failed: %d", (int) GetLastError());
1783                 return;
1784         }
1785
1786         if (len < sizeof(NDISUIO_DEVICE_NOTIFICATION)) {
1787                 wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: "
1788                            "Too short message (len=%d)", (int) len);
1789                 return;
1790         }
1791
1792         hdr = (NDISUIO_DEVICE_NOTIFICATION *) buf;
1793         wpa_printf(MSG_DEBUG, "NDIS: Notification received: len=%d type=0x%x",
1794                    (int) len, hdr->dwNotificationType);
1795
1796         switch (hdr->dwNotificationType) {
1797 #ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL
1798         case NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL:
1799                 wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_ARRIVAL");
1800                 wpa_driver_ndis_event_adapter_arrival(drv);
1801                 break;
1802 #endif
1803 #ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL
1804         case NDISUIO_NOTIFICATION_ADAPTER_REMOVAL:
1805                 wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_REMOVAL");
1806                 wpa_driver_ndis_event_adapter_removal(drv);
1807                 break;
1808 #endif
1809         case NDISUIO_NOTIFICATION_MEDIA_CONNECT:
1810                 wpa_printf(MSG_DEBUG, "NDIS: MEDIA_CONNECT");
1811                 SetEvent(drv->connected_event);
1812                 wpa_driver_ndis_event_connect(drv);
1813                 break;
1814         case NDISUIO_NOTIFICATION_MEDIA_DISCONNECT:
1815                 ResetEvent(drv->connected_event);
1816                 wpa_printf(MSG_DEBUG, "NDIS: MEDIA_DISCONNECT");
1817                 wpa_driver_ndis_event_disconnect(drv);
1818                 break;
1819         case NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION:
1820                 wpa_printf(MSG_DEBUG, "NDIS: MEDIA_SPECIFIC_NOTIFICATION");
1821 #if _WIN32_WCE == 420 || _WIN32_WCE == 0x420
1822                 wpa_driver_ndis_event_media_specific(
1823                         drv, hdr->pvStatusBuffer, hdr->uiStatusBufferSize);
1824 #else
1825                 wpa_driver_ndis_event_media_specific(
1826                         drv, ((const u8 *) hdr) + hdr->uiOffsetToStatusBuffer,
1827                         (size_t) hdr->uiStatusBufferSize);
1828 #endif
1829                 break;
1830         default:
1831                 wpa_printf(MSG_DEBUG, "NDIS: Unknown notification type 0x%x",
1832                            hdr->dwNotificationType);
1833                 break;
1834         }
1835 }
1836
1837
1838 static void ndisuio_notification_deinit(struct wpa_driver_ndis_data *drv)
1839 {
1840         NDISUIO_REQUEST_NOTIFICATION req;
1841
1842         memset(&req, 0, sizeof(req));
1843         req.hMsgQueue = drv->event_queue;
1844         req.dwNotificationTypes = 0;
1845
1846         if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION,
1847                              &req, sizeof(req), NULL, 0, NULL, NULL)) {
1848                 wpa_printf(MSG_INFO, "ndisuio_notification_deinit: "
1849                            "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d",
1850                            (int) GetLastError());
1851         }
1852
1853         if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_CANCEL_NOTIFICATION,
1854                              NULL, 0, NULL, 0, NULL, NULL)) {
1855                 wpa_printf(MSG_INFO, "ndisuio_notification_deinit: "
1856                            "IOCTL_NDISUIO_CANCEL_NOTIFICATION failed: %d",
1857                            (int) GetLastError());
1858         }
1859
1860         if (drv->event_queue) {
1861                 eloop_unregister_event(drv->event_queue,
1862                                        sizeof(drv->event_queue));
1863                 CloseHandle(drv->event_queue);
1864                 drv->event_queue = NULL;
1865         }
1866
1867         if (drv->connected_event) {
1868                 CloseHandle(drv->connected_event);
1869                 drv->connected_event = NULL;
1870         }
1871 }
1872
1873
1874 static int ndisuio_notification_init(struct wpa_driver_ndis_data *drv)
1875 {
1876         MSGQUEUEOPTIONS opt;
1877         NDISUIO_REQUEST_NOTIFICATION req;
1878
1879         drv->connected_event =
1880                 CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));
1881         if (drv->connected_event == NULL) {
1882                 wpa_printf(MSG_INFO, "ndisuio_notification_init: "
1883                            "CreateEvent failed: %d",
1884                            (int) GetLastError());
1885                 return -1;
1886         }
1887
1888         memset(&opt, 0, sizeof(opt));
1889         opt.dwSize = sizeof(opt);
1890         opt.dwMaxMessages = 5;
1891         opt.cbMaxMessage = NDISUIO_MSG_SIZE;
1892         opt.bReadAccess = TRUE;
1893
1894         drv->event_queue = CreateMsgQueue(NULL, &opt);
1895         if (drv->event_queue == NULL) {
1896                 wpa_printf(MSG_INFO, "ndisuio_notification_init: "
1897                            "CreateMsgQueue failed: %d",
1898                            (int) GetLastError());
1899                 ndisuio_notification_deinit(drv);
1900                 return -1;
1901         }
1902
1903         memset(&req, 0, sizeof(req));
1904         req.hMsgQueue = drv->event_queue;
1905         req.dwNotificationTypes =
1906 #ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL
1907                 NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL |
1908 #endif
1909 #ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL
1910                 NDISUIO_NOTIFICATION_ADAPTER_REMOVAL |
1911 #endif
1912                 NDISUIO_NOTIFICATION_MEDIA_CONNECT |
1913                 NDISUIO_NOTIFICATION_MEDIA_DISCONNECT |
1914                 NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION;
1915
1916         if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION,
1917                              &req, sizeof(req), NULL, 0, NULL, NULL)) {
1918                 wpa_printf(MSG_INFO, "ndisuio_notification_init: "
1919                            "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d",
1920                            (int) GetLastError());
1921                 ndisuio_notification_deinit(drv);
1922                 return -1;
1923         }
1924
1925         eloop_register_event(drv->event_queue, sizeof(drv->event_queue),
1926                              ndisuio_notification_receive, drv, NULL);
1927
1928         return 0;
1929 }
1930 #endif /* _WIN32_WCE */
1931
1932
1933 static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
1934 {
1935 #ifdef CONFIG_USE_NDISUIO
1936         NDISUIO_QUERY_BINDING *b;
1937         size_t blen = sizeof(*b) + 1024;
1938         int i, error, found = 0;
1939         DWORD written;
1940         char name[256], desc[256], *dpos;
1941         WCHAR *pos;
1942         size_t j, len, dlen;
1943
1944         b = os_malloc(blen);
1945         if (b == NULL)
1946                 return -1;
1947
1948         for (i = 0; ; i++) {
1949                 os_memset(b, 0, blen);
1950                 b->BindingIndex = i;
1951                 if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
1952                                      b, sizeof(NDISUIO_QUERY_BINDING), b, blen,
1953                                      &written, NULL)) {
1954                         error = (int) GetLastError();
1955                         if (error == ERROR_NO_MORE_ITEMS)
1956                                 break;
1957                         wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING "
1958                                    "failed: %d", error);
1959                         break;
1960                 }
1961
1962                 pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
1963                 len = b->DeviceNameLength;
1964                 if (len >= sizeof(name))
1965                         len = sizeof(name) - 1;
1966                 for (j = 0; j < len; j++)
1967                         name[j] = (char) pos[j];
1968                 name[len] = '\0';
1969
1970                 pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
1971                 len = b->DeviceDescrLength;
1972                 if (len >= sizeof(desc))
1973                         len = sizeof(desc) - 1;
1974                 for (j = 0; j < len; j++)
1975                         desc[j] = (char) pos[j];
1976                 desc[len] = '\0';
1977
1978                 wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc);
1979
1980                 if (os_strstr(name, drv->ifname)) {
1981                         wpa_printf(MSG_DEBUG, "NDIS: Interface name match");
1982                         found = 1;
1983                         break;
1984                 }
1985
1986                 if (os_strncmp(desc, drv->ifname, os_strlen(drv->ifname)) == 0)
1987                 {
1988                         wpa_printf(MSG_DEBUG, "NDIS: Interface description "
1989                                    "match");
1990                         found = 1;
1991                         break;
1992                 }
1993         }
1994
1995         if (!found) {
1996                 wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'",
1997                            drv->ifname);
1998                 os_free(b);
1999                 return -1;
2000         }
2001
2002         os_strlcpy(drv->ifname,
2003                    os_strncmp(name, "\\DEVICE\\", 8) == 0 ? name + 8 : name,
2004                    sizeof(drv->ifname));
2005 #ifdef _WIN32_WCE
2006         drv->adapter_name = wpa_strdup_tchar(drv->ifname);
2007         if (drv->adapter_name == NULL) {
2008                 wpa_printf(MSG_ERROR, "NDIS: Failed to allocate memory for "
2009                            "adapter name");
2010                 os_free(b);
2011                 return -1;
2012         }
2013 #endif /* _WIN32_WCE */
2014
2015         dpos = os_strstr(desc, " - ");
2016         if (dpos)
2017                 dlen = dpos - desc;
2018         else
2019                 dlen = os_strlen(desc);
2020         drv->adapter_desc = os_malloc(dlen + 1);
2021         if (drv->adapter_desc) {
2022                 os_memcpy(drv->adapter_desc, desc, dlen);
2023                 drv->adapter_desc[dlen] = '\0';
2024         }
2025
2026         os_free(b);
2027
2028         if (drv->adapter_desc == NULL)
2029                 return -1;
2030
2031         wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'",
2032                    drv->adapter_desc);
2033
2034         return 0;
2035 #else /* CONFIG_USE_NDISUIO */
2036         PTSTR _names;
2037         char *names, *pos, *pos2;
2038         ULONG len;
2039         BOOLEAN res;
2040 #define MAX_ADAPTERS 32
2041         char *name[MAX_ADAPTERS];
2042         char *desc[MAX_ADAPTERS];
2043         int num_name, num_desc, i, found_name, found_desc;
2044         size_t dlen;
2045
2046         wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
2047                    PacketGetVersion());
2048
2049         len = 8192;
2050         _names = os_zalloc(len);
2051         if (_names == NULL)
2052                 return -1;
2053
2054         res = PacketGetAdapterNames(_names, &len);
2055         if (!res && len > 8192) {
2056                 os_free(_names);
2057                 _names = os_zalloc(len);
2058                 if (_names == NULL)
2059                         return -1;
2060                 res = PacketGetAdapterNames(_names, &len);
2061         }
2062
2063         if (!res) {
2064                 wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
2065                            "(PacketGetAdapterNames)");
2066                 os_free(_names);
2067                 return -1;
2068         }
2069
2070         names = (char *) _names;
2071         if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
2072                 wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
2073                            "UNICODE");
2074                 /* Convert to ASCII */
2075                 pos2 = pos = names;
2076                 while (pos2 < names + len) {
2077                         if (pos2[0] == '\0' && pos2[1] == '\0' &&
2078                             pos2[2] == '\0' && pos2[3] == '\0') {
2079                                 pos2 += 4;
2080                                 break;
2081                         }
2082                         *pos++ = pos2[0];
2083                         pos2 += 2;
2084                 }
2085                 os_memcpy(pos + 2, names, pos - names);
2086                 pos += 2;
2087         } else
2088                 pos = names;
2089
2090         num_name = 0;
2091         while (pos < names + len) {
2092                 name[num_name] = pos;
2093                 while (*pos && pos < names + len)
2094                         pos++;
2095                 if (pos + 1 >= names + len) {
2096                         os_free(names);
2097                         return -1;
2098                 }
2099                 pos++;
2100                 num_name++;
2101                 if (num_name >= MAX_ADAPTERS) {
2102                         wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
2103                         os_free(names);
2104                         return -1;
2105                 }
2106                 if (*pos == '\0') {
2107                         wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found",
2108                                    num_name);
2109                         pos++;
2110                         break;
2111                 }
2112         }
2113
2114         num_desc = 0;
2115         while (pos < names + len) {
2116                 desc[num_desc] = pos;
2117                 while (*pos && pos < names + len)
2118                         pos++;
2119                 if (pos + 1 >= names + len) {
2120                         os_free(names);
2121                         return -1;
2122                 }
2123                 pos++;
2124                 num_desc++;
2125                 if (num_desc >= MAX_ADAPTERS) {
2126                         wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
2127                                    "descriptions");
2128                         os_free(names);
2129                         return -1;
2130                 }
2131                 if (*pos == '\0') {
2132                         wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions "
2133                                    "found", num_name);
2134                         pos++;
2135                         break;
2136                 }
2137         }
2138
2139         /*
2140          * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
2141          * descriptions. Fill in dummy descriptors to work around this.
2142          */
2143         while (num_desc < num_name)
2144                 desc[num_desc++] = "dummy description";
2145
2146         if (num_name != num_desc) {
2147                 wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
2148                            "description counts (%d != %d)",
2149                            num_name, num_desc);
2150                 os_free(names);
2151                 return -1;
2152         }
2153
2154         found_name = found_desc = -1;
2155         for (i = 0; i < num_name; i++) {
2156                 wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s",
2157                            i, name[i], desc[i]);
2158                 if (found_name == -1 && os_strstr(name[i], drv->ifname))
2159                         found_name = i;
2160                 if (found_desc == -1 &&
2161                     os_strncmp(desc[i], drv->ifname, os_strlen(drv->ifname)) ==
2162                     0)
2163                         found_desc = i;
2164         }
2165
2166         if (found_name < 0 && found_desc >= 0) {
2167                 wpa_printf(MSG_DEBUG, "NDIS: Matched interface '%s' based on "
2168                            "description '%s'",
2169                            name[found_desc], desc[found_desc]);
2170                 found_name = found_desc;
2171                 os_strlcpy(drv->ifname,
2172                            os_strncmp(name[found_desc], "\\Device\\NPF_", 12)
2173                            == 0 ? name[found_desc] + 12 : name[found_desc],
2174                            sizeof(drv->ifname));
2175         }
2176
2177         if (found_name < 0) {
2178                 wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'",
2179                            drv->ifname);
2180                 os_free(names);
2181                 return -1;
2182         }
2183
2184         i = found_name;
2185         pos = os_strrchr(desc[i], '(');
2186         if (pos) {
2187                 dlen = pos - desc[i];
2188                 pos--;
2189                 if (pos > desc[i] && *pos == ' ')
2190                         dlen--;
2191         } else {
2192                 dlen = os_strlen(desc[i]);
2193         }
2194         drv->adapter_desc = os_malloc(dlen + 1);
2195         if (drv->adapter_desc) {
2196                 os_memcpy(drv->adapter_desc, desc[i], dlen);
2197                 drv->adapter_desc[dlen] = '\0';
2198         }
2199
2200         os_free(names);
2201
2202         if (drv->adapter_desc == NULL)
2203                 return -1;
2204
2205         wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'",
2206                    drv->adapter_desc);
2207
2208         return 0;
2209 #endif /* CONFIG_USE_NDISUIO */
2210 }
2211
2212
2213 #if defined(CONFIG_NATIVE_WINDOWS) || defined(__CYGWIN__)
2214 #ifndef _WIN32_WCE
2215 /*
2216  * These structures are undocumented for WinXP; only WinCE version is
2217  * documented. These would be included wzcsapi.h if it were available. Some
2218  * changes here have been needed to make the structures match with WinXP SP2.
2219  * It is unclear whether these work with any other version.
2220  */
2221
2222 typedef struct {
2223         LPWSTR wszGuid;
2224 } INTF_KEY_ENTRY, *PINTF_KEY_ENTRY;
2225
2226 typedef struct {
2227         DWORD dwNumIntfs;
2228         PINTF_KEY_ENTRY pIntfs;
2229 } INTFS_KEY_TABLE, *PINTFS_KEY_TABLE;
2230
2231 typedef struct {
2232         DWORD dwDataLen;
2233         LPBYTE pData;
2234 } RAW_DATA, *PRAW_DATA;
2235
2236 typedef struct {
2237         LPWSTR wszGuid;
2238         LPWSTR wszDescr;
2239         ULONG ulMediaState;
2240         ULONG ulMediaType;
2241         ULONG ulPhysicalMediaType;
2242         INT nInfraMode;
2243         INT nAuthMode;
2244         INT nWepStatus;
2245 #ifndef _WIN32_WCE
2246         u8 pad[2]; /* why is this needed? */
2247 #endif /* _WIN32_WCE */
2248         DWORD dwCtlFlags;
2249         DWORD dwCapabilities; /* something added for WinXP SP2(?) */
2250         RAW_DATA rdSSID;
2251         RAW_DATA rdBSSID;
2252         RAW_DATA rdBSSIDList;
2253         RAW_DATA rdStSSIDList;
2254         RAW_DATA rdCtrlData;
2255 #ifdef UNDER_CE
2256         BOOL bInitialized;
2257 #endif
2258         DWORD nWPAMCastCipher;
2259         /* add some extra buffer for later additions since this interface is
2260          * far from stable */
2261         u8 later_additions[100];
2262 } INTF_ENTRY, *PINTF_ENTRY;
2263
2264 #define INTF_ALL 0xffffffff
2265 #define INTF_ALL_FLAGS 0x0000ffff
2266 #define INTF_CTLFLAGS 0x00000010
2267 #define INTFCTL_ENABLED 0x8000
2268 #endif /* _WIN32_WCE */
2269
2270
2271 #ifdef _WIN32_WCE
2272 static int wpa_driver_ndis_rebind_adapter(struct wpa_driver_ndis_data *drv)
2273 {
2274         HANDLE ndis;
2275         TCHAR multi[100];
2276         int len;
2277
2278         len = _tcslen(drv->adapter_name);
2279         if (len > 80)
2280                 return -1;
2281
2282         ndis = CreateFile(DD_NDIS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
2283                           0, NULL, OPEN_EXISTING, 0, NULL);
2284         if (ndis == INVALID_HANDLE_VALUE) {
2285                 wpa_printf(MSG_DEBUG, "NDIS: Failed to open file to NDIS "
2286                            "device: %d", (int) GetLastError());
2287                 return -1;
2288         }
2289
2290         len++;
2291         memcpy(multi, drv->adapter_name, len * sizeof(TCHAR));
2292         memcpy(&multi[len], TEXT("NDISUIO\0"), 9 * sizeof(TCHAR));
2293         len += 9;
2294
2295         if (!DeviceIoControl(ndis, IOCTL_NDIS_REBIND_ADAPTER,
2296                              multi, len * sizeof(TCHAR), NULL, 0, NULL, NULL))
2297         {
2298                 wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDIS_REBIND_ADAPTER "
2299                            "failed: 0x%x", (int) GetLastError());
2300                 wpa_hexdump_ascii(MSG_DEBUG, "NDIS: rebind multi_sz",
2301                                   (u8 *) multi, len * sizeof(TCHAR));
2302                 CloseHandle(ndis);
2303                 return -1;
2304         }
2305
2306         CloseHandle(ndis);
2307
2308         wpa_printf(MSG_DEBUG, "NDIS: Requested NDIS rebind of NDISUIO "
2309                    "protocol");
2310
2311         return 0;
2312 }
2313 #endif /* _WIN32_WCE */
2314
2315
2316 static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv,
2317                                    int enable)
2318 {
2319 #ifdef _WIN32_WCE
2320         HKEY hk, hk2;
2321         LONG ret;
2322         DWORD i, hnd, len;
2323         TCHAR keyname[256], devname[256];
2324
2325 #define WZC_DRIVER TEXT("Drivers\\BuiltIn\\ZeroConfig")
2326
2327         if (enable) {
2328                 HANDLE h;
2329                 h = ActivateDeviceEx(WZC_DRIVER, NULL, 0, NULL);
2330                 if (h == INVALID_HANDLE_VALUE || h == 0) {
2331                         wpa_printf(MSG_DEBUG, "NDIS: Failed to re-enable WZC "
2332                                    "- ActivateDeviceEx failed: %d",
2333                                    (int) GetLastError());
2334                         return -1;
2335                 }
2336
2337                 wpa_printf(MSG_DEBUG, "NDIS: WZC re-enabled");
2338                 return wpa_driver_ndis_rebind_adapter(drv);
2339         }
2340
2341         /*
2342          * Unfortunately, just disabling the WZC for an interface is not enough
2343          * to free NDISUIO for us, so need to disable and unload WZC completely
2344          * for now when using WinCE with NDISUIO. In addition, must request
2345          * NDISUIO protocol to be rebound to the adapter in order to free the
2346          * NDISUIO binding that WZC hold before us.
2347          */
2348
2349         /* Enumerate HKLM\Drivers\Active\* to find a handle to WZC. */
2350         ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, DEVLOAD_ACTIVE_KEY, 0, 0, &hk);
2351         if (ret != ERROR_SUCCESS) {
2352                 wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(DEVLOAD_ACTIVE_KEY) "
2353                            "failed: %d %d", (int) ret, (int) GetLastError());
2354                 return -1;
2355         }
2356
2357         for (i = 0; ; i++) {
2358                 len = sizeof(keyname);
2359                 ret = RegEnumKeyEx(hk, i, keyname, &len, NULL, NULL, NULL,
2360                                    NULL);
2361                 if (ret != ERROR_SUCCESS) {
2362                         wpa_printf(MSG_DEBUG, "NDIS: Could not find active "
2363                                    "WZC - assuming it is not running.");
2364                         RegCloseKey(hk);
2365                         return -1;
2366                 }
2367
2368                 ret = RegOpenKeyEx(hk, keyname, 0, 0, &hk2);
2369                 if (ret != ERROR_SUCCESS) {
2370                         wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(active dev) "
2371                                    "failed: %d %d",
2372                                    (int) ret, (int) GetLastError());
2373                         continue;
2374                 }
2375
2376                 len = sizeof(devname);
2377                 ret = RegQueryValueEx(hk2, DEVLOAD_DEVKEY_VALNAME, NULL, NULL,
2378                                       (LPBYTE) devname, &len);
2379                 if (ret != ERROR_SUCCESS) {
2380                         wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx("
2381                                    "DEVKEY_VALNAME) failed: %d %d",
2382                                    (int) ret, (int) GetLastError());
2383                         RegCloseKey(hk2);
2384                         continue;
2385                 }
2386
2387                 if (_tcscmp(devname, WZC_DRIVER) == 0)
2388                         break;
2389
2390                 RegCloseKey(hk2);
2391         }
2392
2393         RegCloseKey(hk);
2394
2395         /* Found WZC - get handle to it. */
2396         len = sizeof(hnd);
2397         ret = RegQueryValueEx(hk2, DEVLOAD_HANDLE_VALNAME, NULL, NULL,
2398                               (PUCHAR) &hnd, &len);
2399         if (ret != ERROR_SUCCESS) {
2400                 wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx(HANDLE_VALNAME) "
2401                            "failed: %d %d", (int) ret, (int) GetLastError());
2402                 RegCloseKey(hk2);
2403                 return -1;
2404         }
2405
2406         RegCloseKey(hk2);
2407
2408         /* Deactivate WZC */
2409         if (!DeactivateDevice((HANDLE) hnd)) {
2410                 wpa_printf(MSG_DEBUG, "NDIS: DeactivateDevice failed: %d",
2411                            (int) GetLastError());
2412                 return -1;
2413         }
2414
2415         wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily");
2416         drv->wzc_disabled = 1;
2417         return wpa_driver_ndis_rebind_adapter(drv);
2418
2419 #else /* _WIN32_WCE */
2420
2421         HMODULE hm;
2422         DWORD (WINAPI *wzc_enum_interf)(LPWSTR pSrvAddr,
2423                                         PINTFS_KEY_TABLE pIntfs);
2424         DWORD (WINAPI *wzc_query_interf)(LPWSTR pSrvAddr, DWORD dwInFlags,
2425                                          PINTF_ENTRY pIntf,
2426                                          LPDWORD pdwOutFlags);
2427         DWORD (WINAPI *wzc_set_interf)(LPWSTR pSrvAddr, DWORD dwInFlags,
2428                                        PINTF_ENTRY pIntf, LPDWORD pdwOutFlags);
2429         int ret = -1, j;
2430         DWORD res;
2431         INTFS_KEY_TABLE guids;
2432         INTF_ENTRY intf;
2433         char guid[128];
2434         WCHAR *pos;
2435         DWORD flags, i;
2436
2437         hm = LoadLibrary(TEXT("wzcsapi.dll"));
2438         if (hm == NULL) {
2439                 wpa_printf(MSG_DEBUG, "NDIS: Failed to load wzcsapi.dll (%u) "
2440                            "- WZC probably not running",
2441                            (unsigned int) GetLastError());
2442                 return -1;
2443         }
2444
2445 #ifdef _WIN32_WCE
2446         wzc_enum_interf = (void *) GetProcAddressA(hm, "WZCEnumInterfaces");
2447         wzc_query_interf = (void *) GetProcAddressA(hm, "WZCQueryInterface");
2448         wzc_set_interf = (void *) GetProcAddressA(hm, "WZCSetInterface");
2449 #else /* _WIN32_WCE */
2450         wzc_enum_interf = (void *) GetProcAddress(hm, "WZCEnumInterfaces");
2451         wzc_query_interf = (void *) GetProcAddress(hm, "WZCQueryInterface");
2452         wzc_set_interf = (void *) GetProcAddress(hm, "WZCSetInterface");
2453 #endif /* _WIN32_WCE */
2454
2455         if (wzc_enum_interf == NULL || wzc_query_interf == NULL ||
2456             wzc_set_interf == NULL) {
2457                 wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces, "
2458                            "WZCQueryInterface, or WZCSetInterface not found "
2459                            "in wzcsapi.dll");
2460                 goto fail;
2461         }
2462
2463         os_memset(&guids, 0, sizeof(guids));
2464         res = wzc_enum_interf(NULL, &guids);
2465         if (res != 0) {
2466                 wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces failed: %d; "
2467                            "WZC service is apparently not running",
2468                            (int) res);
2469                 goto fail;
2470         }
2471
2472         wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces: %d interfaces",
2473                    (int) guids.dwNumIntfs);
2474
2475         for (i = 0; i < guids.dwNumIntfs; i++) {
2476                 pos = guids.pIntfs[i].wszGuid;
2477                 for (j = 0; j < sizeof(guid); j++) {
2478                         guid[j] = (char) *pos;
2479                         if (*pos == 0)
2480                                 break;
2481                         pos++;
2482                 }
2483                 guid[sizeof(guid) - 1] = '\0';
2484                 wpa_printf(MSG_DEBUG, "NDIS: intfs %d GUID '%s'",
2485                            (int) i, guid);
2486                 if (os_strstr(drv->ifname, guid) == NULL)
2487                         continue;
2488
2489                 wpa_printf(MSG_DEBUG, "NDIS: Current interface found from "
2490                            "WZC");
2491                 break;
2492         }
2493
2494         if (i >= guids.dwNumIntfs) {
2495                 wpa_printf(MSG_DEBUG, "NDIS: Current interface not found from "
2496                            "WZC");
2497                 goto fail;
2498         }
2499
2500         os_memset(&intf, 0, sizeof(intf));
2501         intf.wszGuid = guids.pIntfs[i].wszGuid;
2502         /* Set flags to verify that the structure has not changed. */
2503         intf.dwCtlFlags = -1;
2504         flags = 0;
2505         res = wzc_query_interf(NULL, INTFCTL_ENABLED, &intf, &flags);
2506         if (res != 0) {
2507                 wpa_printf(MSG_DEBUG, "NDIS: Could not query flags for the "
2508                            "WZC interface: %d (0x%x)",
2509                            (int) res, (int) res);
2510                 wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
2511                            (unsigned int) GetLastError());
2512                 goto fail;
2513         }
2514
2515         wpa_printf(MSG_DEBUG, "NDIS: WZC interface flags 0x%x dwCtlFlags 0x%x",
2516                    (int) flags, (int) intf.dwCtlFlags);
2517
2518         if (intf.dwCtlFlags == -1) {
2519                 wpa_printf(MSG_DEBUG, "NDIS: Looks like wzcsapi has changed "
2520                            "again - could not disable WZC");
2521                 wpa_hexdump(MSG_MSGDUMP, "NDIS: intf",
2522                             (u8 *) &intf, sizeof(intf));
2523                 goto fail;
2524         }
2525
2526         if (enable) {
2527                 if (!(intf.dwCtlFlags & INTFCTL_ENABLED)) {
2528                         wpa_printf(MSG_DEBUG, "NDIS: Enabling WZC for this "
2529                                    "interface");
2530                         intf.dwCtlFlags |= INTFCTL_ENABLED;
2531                         res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf,
2532                                              &flags);
2533                         if (res != 0) {
2534                                 wpa_printf(MSG_DEBUG, "NDIS: Failed to enable "
2535                                            "WZC: %d (0x%x)",
2536                                            (int) res, (int) res);
2537                                 wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
2538                                            (unsigned int) GetLastError());
2539                                 goto fail;
2540                         }
2541                         wpa_printf(MSG_DEBUG, "NDIS: Re-enabled WZC for this "
2542                                    "interface");
2543                         drv->wzc_disabled = 0;
2544                 }
2545         } else {
2546                 if (intf.dwCtlFlags & INTFCTL_ENABLED) {
2547                         wpa_printf(MSG_DEBUG, "NDIS: Disabling WZC for this "
2548                                    "interface");
2549                         intf.dwCtlFlags &= ~INTFCTL_ENABLED;
2550                         res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf,
2551                                              &flags);
2552                         if (res != 0) {
2553                                 wpa_printf(MSG_DEBUG, "NDIS: Failed to "
2554                                            "disable WZC: %d (0x%x)",
2555                                            (int) res, (int) res);
2556                                 wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
2557                                            (unsigned int) GetLastError());
2558                                 goto fail;
2559                         }
2560                         wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily "
2561                                    "for this interface");
2562                         drv->wzc_disabled = 1;
2563                 } else {
2564                         wpa_printf(MSG_DEBUG, "NDIS: WZC was not enabled for "
2565                                    "this interface");
2566                 }
2567         }
2568
2569         ret = 0;
2570
2571 fail:
2572         FreeLibrary(hm);
2573
2574         return ret;
2575 #endif /* _WIN32_WCE */
2576 }
2577
2578 #else /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */
2579
2580 static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv,
2581                                    int enable)
2582 {
2583         return 0;
2584 }
2585
2586 #endif /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */
2587
2588
2589 #ifdef CONFIG_USE_NDISUIO
2590 /*
2591  * l2_packet_ndis.c is sharing the same handle to NDISUIO, so we must be able
2592  * to export this handle. This is somewhat ugly, but there is no better
2593  * mechanism available to pass data from driver interface to l2_packet wrapper.
2594  */
2595 static HANDLE driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE;
2596
2597 HANDLE driver_ndis_get_ndisuio_handle(void)
2598 {
2599         return driver_ndis_ndisuio_handle;
2600 }
2601 #endif /* CONFIG_USE_NDISUIO */
2602
2603
2604 static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv)
2605 {
2606 #ifdef CONFIG_USE_NDISUIO
2607 #ifndef _WIN32_WCE
2608 #define NDISUIO_DEVICE_NAME TEXT("\\\\.\\\\Ndisuio")
2609         DWORD written;
2610 #endif /* _WIN32_WCE */
2611         drv->ndisuio = CreateFile(NDISUIO_DEVICE_NAME,
2612                                   GENERIC_READ | GENERIC_WRITE, 0, NULL,
2613                                   OPEN_EXISTING,
2614                                   FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
2615                                   INVALID_HANDLE_VALUE);
2616         if (drv->ndisuio == INVALID_HANDLE_VALUE) {
2617                 wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to "
2618                            "NDISUIO: %d", (int) GetLastError());
2619                 return -1;
2620         }
2621         driver_ndis_ndisuio_handle = drv->ndisuio;
2622
2623 #ifndef _WIN32_WCE
2624         if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0,
2625                              NULL, 0, &written, NULL)) {
2626                 wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: "
2627                            "%d", (int) GetLastError());
2628                 CloseHandle(drv->ndisuio);
2629                 drv->ndisuio = INVALID_HANDLE_VALUE;
2630                 return -1;
2631         }
2632 #endif /* _WIN32_WCE */
2633
2634         return 0;
2635 #else /* CONFIG_USE_NDISUIO */
2636         return 0;
2637 #endif /* CONFIG_USE_NDISUIO */
2638 }
2639
2640
2641 static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv)
2642 {
2643 #ifdef CONFIG_USE_NDISUIO
2644         DWORD written;
2645 #define MAX_NDIS_DEVICE_NAME_LEN 256
2646         WCHAR ifname[MAX_NDIS_DEVICE_NAME_LEN];
2647         size_t len, i, pos;
2648         const char *prefix = "\\DEVICE\\";
2649
2650 #ifdef _WIN32_WCE
2651         pos = 0;
2652 #else /* _WIN32_WCE */
2653         pos = 8;
2654 #endif /* _WIN32_WCE */
2655         len = pos + os_strlen(drv->ifname);
2656         if (len >= MAX_NDIS_DEVICE_NAME_LEN)
2657                 return -1;
2658         for (i = 0; i < pos; i++)
2659                 ifname[i] = (WCHAR) prefix[i];
2660         for (i = pos; i < len; i++)
2661                 ifname[i] = (WCHAR) drv->ifname[i - pos];
2662         ifname[i] = L'\0';
2663
2664         if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_OPEN_DEVICE,
2665                              ifname, len * sizeof(WCHAR), NULL, 0, &written,
2666                              NULL)) {
2667                 wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_OPEN_DEVICE "
2668                            "failed: %d", (int) GetLastError());
2669                 wpa_hexdump_ascii(MSG_DEBUG, "NDIS: ifname",
2670                                   (const u8 *) ifname, len * sizeof(WCHAR));
2671                 CloseHandle(drv->ndisuio);
2672                 drv->ndisuio = INVALID_HANDLE_VALUE;
2673                 return -1;
2674         }
2675
2676         wpa_printf(MSG_DEBUG, "NDIS: Opened NDISUIO device successfully");
2677
2678         return 0;
2679 #else /* CONFIG_USE_NDISUIO */
2680         char ifname[128];
2681         os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", drv->ifname);
2682         drv->adapter = PacketOpenAdapter(ifname);
2683         if (drv->adapter == NULL) {
2684                 wpa_printf(MSG_DEBUG, "NDIS: PacketOpenAdapter failed for "
2685                            "'%s'", ifname);
2686                 return -1;
2687         }
2688         return 0;
2689 #endif /* CONFIG_USE_NDISUIO */
2690 }
2691
2692
2693 static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv)
2694 {
2695 #ifdef CONFIG_USE_NDISUIO
2696         driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE;
2697         if (drv->ndisuio != INVALID_HANDLE_VALUE)
2698                 CloseHandle(drv->ndisuio);
2699 #else /* CONFIG_USE_NDISUIO */
2700         if (drv->adapter)
2701                 PacketCloseAdapter(drv->adapter);
2702 #endif /* CONFIG_USE_NDISUIO */
2703 }
2704
2705
2706 static int ndis_add_multicast(struct wpa_driver_ndis_data *drv)
2707 {
2708         if (ndis_set_oid(drv, OID_802_3_MULTICAST_LIST,
2709                          (const char *) pae_group_addr, ETH_ALEN) < 0) {
2710                 wpa_printf(MSG_DEBUG, "NDIS: Failed to add PAE group address "
2711                            "to the multicast list");
2712                 return -1;
2713         }
2714
2715         return 0;
2716 }
2717
2718
2719 static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
2720 {
2721         struct wpa_driver_ndis_data *drv;
2722         u32 mode;
2723
2724         drv = os_zalloc(sizeof(*drv));
2725         if (drv == NULL)
2726                 return NULL;
2727         drv->ctx = ctx;
2728         /*
2729          * Compatibility code to strip possible prefix from the GUID. Previous
2730          * versions include \Device\NPF_ prefix for all names, but the internal
2731          * interface name is now only the GUI. Both Packet32 and NDISUIO
2732          * prefixes are supported.
2733          */
2734         if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0)
2735                 ifname += 12;
2736         else if (os_strncmp(ifname, "\\DEVICE\\", 8) == 0)
2737                 ifname += 8;
2738         os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
2739
2740         if (wpa_driver_ndis_adapter_init(drv) < 0) {
2741                 os_free(drv);
2742                 return NULL;
2743         }
2744
2745         if (wpa_driver_ndis_get_names(drv) < 0) {
2746                 wpa_driver_ndis_adapter_close(drv);
2747                 os_free(drv);
2748                 return NULL;
2749         }
2750
2751         wpa_driver_ndis_set_wzc(drv, 0);
2752
2753         if (wpa_driver_ndis_adapter_open(drv) < 0) {
2754                 wpa_driver_ndis_adapter_close(drv);
2755                 os_free(drv);
2756                 return NULL;
2757         }
2758
2759         if (ndis_get_oid(drv, OID_802_3_CURRENT_ADDRESS,
2760                          (char *) drv->own_addr, ETH_ALEN) < 0) {
2761                 wpa_printf(MSG_DEBUG, "NDIS: Get OID_802_3_CURRENT_ADDRESS "
2762                            "failed");
2763                 wpa_driver_ndis_adapter_close(drv);
2764                 os_free(drv);
2765                 return NULL;
2766         }
2767         wpa_driver_ndis_get_capability(drv);
2768
2769         /* Make sure that the driver does not have any obsolete PMKID entries.
2770          */
2771         wpa_driver_ndis_flush_pmkid(drv);
2772
2773         /*
2774          * Disconnect to make sure that driver re-associates if it was
2775          * connected.
2776          */
2777         wpa_driver_ndis_disconnect(drv);
2778
2779         eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, drv, NULL);
2780
2781 #ifdef CONFIG_NDIS_EVENTS_INTEGRATED
2782         drv->events = ndis_events_init(&drv->events_pipe, &drv->event_avail,
2783                                        drv->ifname, drv->adapter_desc);
2784         if (drv->events == NULL) {
2785                 wpa_driver_ndis_deinit(drv);
2786                 return NULL;
2787         }
2788         eloop_register_event(drv->event_avail, sizeof(drv->event_avail),
2789                              wpa_driver_ndis_event_pipe_cb, drv, NULL);
2790 #endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
2791
2792 #ifdef _WIN32_WCE
2793         if (ndisuio_notification_init(drv) < 0) {
2794                 wpa_driver_ndis_deinit(drv);
2795                 return NULL;
2796         }
2797 #endif /* _WIN32_WCE */
2798
2799         /* Set mode here in case card was configured for ad-hoc mode
2800          * previously. */
2801         mode = Ndis802_11Infrastructure;
2802         if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
2803                          (char *) &mode, sizeof(mode)) < 0) {
2804                 wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
2805                            "OID_802_11_INFRASTRUCTURE_MODE (%d)",
2806                            (int) mode);
2807                 /* Try to continue anyway */
2808
2809                 if (!drv->has_capability && drv->capa.enc == 0) {
2810                         wpa_printf(MSG_DEBUG, "NDIS: Driver did not provide "
2811                                    "any wireless capabilities - assume it is "
2812                                    "a wired interface");
2813                         drv->wired = 1;
2814                         ndis_add_multicast(drv);
2815                 }
2816         }
2817
2818         return drv;
2819 }
2820
2821
2822 static void wpa_driver_ndis_deinit(void *priv)
2823 {
2824         struct wpa_driver_ndis_data *drv = priv;
2825
2826 #ifdef CONFIG_NDIS_EVENTS_INTEGRATED
2827         if (drv->events) {
2828                 eloop_unregister_event(drv->event_avail,
2829                                        sizeof(drv->event_avail));
2830                 ndis_events_deinit(drv->events);
2831         }
2832 #endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
2833
2834 #ifdef _WIN32_WCE
2835         ndisuio_notification_deinit(drv);
2836 #endif /* _WIN32_WCE */
2837
2838         eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
2839         eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
2840         wpa_driver_ndis_flush_pmkid(drv);
2841         wpa_driver_ndis_disconnect(drv);
2842         if (wpa_driver_ndis_radio_off(drv) < 0) {
2843                 wpa_printf(MSG_DEBUG, "NDIS: failed to disassociate and turn "
2844                            "radio off");
2845         }
2846
2847         wpa_driver_ndis_adapter_close(drv);
2848
2849         if (drv->wzc_disabled)
2850                 wpa_driver_ndis_set_wzc(drv, 1);
2851
2852 #ifdef _WIN32_WCE
2853         os_free(drv->adapter_name);
2854 #endif /* _WIN32_WCE */
2855         os_free(drv->adapter_desc);
2856         os_free(drv);
2857 }
2858
2859
2860 static struct wpa_interface_info *
2861 wpa_driver_ndis_get_interfaces(void *global_priv)
2862 {
2863         struct wpa_interface_info *iface = NULL, *niface;
2864
2865 #ifdef CONFIG_USE_NDISUIO
2866         NDISUIO_QUERY_BINDING *b;
2867         size_t blen = sizeof(*b) + 1024;
2868         int i, error;
2869         DWORD written;
2870         char name[256], desc[256];
2871         WCHAR *pos;
2872         size_t j, len;
2873         HANDLE ndisuio;
2874
2875         ndisuio = CreateFile(NDISUIO_DEVICE_NAME,
2876                              GENERIC_READ | GENERIC_WRITE, 0, NULL,
2877                              OPEN_EXISTING,
2878                              FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
2879                              INVALID_HANDLE_VALUE);
2880         if (ndisuio == INVALID_HANDLE_VALUE) {
2881                 wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to "
2882                            "NDISUIO: %d", (int) GetLastError());
2883                 return NULL;
2884         }
2885
2886 #ifndef _WIN32_WCE
2887         if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0,
2888                              NULL, 0, &written, NULL)) {
2889                 wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: "
2890                            "%d", (int) GetLastError());
2891                 CloseHandle(ndisuio);
2892                 return NULL;
2893         }
2894 #endif /* _WIN32_WCE */
2895
2896         b = os_malloc(blen);
2897         if (b == NULL) {
2898                 CloseHandle(ndisuio);
2899                 return NULL;
2900         }
2901
2902         for (i = 0; ; i++) {
2903                 os_memset(b, 0, blen);
2904                 b->BindingIndex = i;
2905                 if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
2906                                      b, sizeof(NDISUIO_QUERY_BINDING), b, blen,
2907                                      &written, NULL)) {
2908                         error = (int) GetLastError();
2909                         if (error == ERROR_NO_MORE_ITEMS)
2910                                 break;
2911                         wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING "
2912                                    "failed: %d", error);
2913                         break;
2914                 }
2915
2916                 pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
2917                 len = b->DeviceNameLength;
2918                 if (len >= sizeof(name))
2919                         len = sizeof(name) - 1;
2920                 for (j = 0; j < len; j++)
2921                         name[j] = (char) pos[j];
2922                 name[len] = '\0';
2923
2924                 pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
2925                 len = b->DeviceDescrLength;
2926                 if (len >= sizeof(desc))
2927                         len = sizeof(desc) - 1;
2928                 for (j = 0; j < len; j++)
2929                         desc[j] = (char) pos[j];
2930                 desc[len] = '\0';
2931
2932                 wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc);
2933
2934                 niface = os_zalloc(sizeof(*niface));
2935                 if (niface == NULL)
2936                         break;
2937                 niface->drv_name = "ndis";
2938                 if (os_strncmp(name, "\\DEVICE\\", 8) == 0)
2939                         niface->ifname = os_strdup(name + 8);
2940                 else
2941                         niface->ifname = os_strdup(name);
2942                 if (niface->ifname == NULL) {
2943                         os_free(niface);
2944                         break;
2945                 }
2946                 niface->desc = os_strdup(desc);
2947                 niface->next = iface;
2948                 iface = niface;
2949         }
2950
2951         os_free(b);
2952         CloseHandle(ndisuio);
2953 #else /* CONFIG_USE_NDISUIO */
2954         PTSTR _names;
2955         char *names, *pos, *pos2;
2956         ULONG len;
2957         BOOLEAN res;
2958         char *name[MAX_ADAPTERS];
2959         char *desc[MAX_ADAPTERS];
2960         int num_name, num_desc, i;
2961
2962         wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
2963                    PacketGetVersion());
2964
2965         len = 8192;
2966         _names = os_zalloc(len);
2967         if (_names == NULL)
2968                 return NULL;
2969
2970         res = PacketGetAdapterNames(_names, &len);
2971         if (!res && len > 8192) {
2972                 os_free(_names);
2973                 _names = os_zalloc(len);
2974                 if (_names == NULL)
2975                         return NULL;
2976                 res = PacketGetAdapterNames(_names, &len);
2977         }
2978
2979         if (!res) {
2980                 wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
2981                            "(PacketGetAdapterNames)");
2982                 os_free(_names);
2983                 return NULL;
2984         }
2985
2986         names = (char *) _names;
2987         if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
2988                 wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
2989                            "UNICODE");
2990                 /* Convert to ASCII */
2991                 pos2 = pos = names;
2992                 while (pos2 < names + len) {
2993                         if (pos2[0] == '\0' && pos2[1] == '\0' &&
2994                             pos2[2] == '\0' && pos2[3] == '\0') {
2995                                 pos2 += 4;
2996                                 break;
2997                         }
2998                         *pos++ = pos2[0];
2999                         pos2 += 2;
3000                 }
3001                 os_memcpy(pos + 2, names, pos - names);
3002                 pos += 2;
3003         } else
3004                 pos = names;
3005
3006         num_name = 0;
3007         while (pos < names + len) {
3008                 name[num_name] = pos;
3009                 while (*pos && pos < names + len)
3010                         pos++;
3011                 if (pos + 1 >= names + len) {
3012                         os_free(names);
3013                         return NULL;
3014                 }
3015                 pos++;
3016                 num_name++;
3017                 if (num_name >= MAX_ADAPTERS) {
3018                         wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
3019                         os_free(names);
3020                         return NULL;
3021                 }
3022                 if (*pos == '\0') {
3023                         wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found",
3024                                    num_name);
3025                         pos++;
3026                         break;
3027                 }
3028         }
3029
3030         num_desc = 0;
3031         while (pos < names + len) {
3032                 desc[num_desc] = pos;
3033                 while (*pos && pos < names + len)
3034                         pos++;
3035                 if (pos + 1 >= names + len) {
3036                         os_free(names);
3037                         return NULL;
3038                 }
3039                 pos++;
3040                 num_desc++;
3041                 if (num_desc >= MAX_ADAPTERS) {
3042                         wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
3043                                    "descriptions");
3044                         os_free(names);
3045                         return NULL;
3046                 }
3047                 if (*pos == '\0') {
3048                         wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions "
3049                                    "found", num_name);
3050                         pos++;
3051                         break;
3052                 }
3053         }
3054
3055         /*
3056          * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
3057          * descriptions. Fill in dummy descriptors to work around this.
3058          */
3059         while (num_desc < num_name)
3060                 desc[num_desc++] = "dummy description";
3061
3062         if (num_name != num_desc) {
3063                 wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
3064                            "description counts (%d != %d)",
3065                            num_name, num_desc);
3066                 os_free(names);
3067                 return NULL;
3068         }
3069
3070         for (i = 0; i < num_name; i++) {
3071                 niface = os_zalloc(sizeof(*niface));
3072                 if (niface == NULL)
3073                         break;
3074                 niface->drv_name = "ndis";
3075                 if (os_strncmp(name[i], "\\Device\\NPF_", 12) == 0)
3076                         niface->ifname = os_strdup(name[i] + 12);
3077                 else
3078                         niface->ifname = os_strdup(name[i]);
3079                 if (niface->ifname == NULL) {
3080                         os_free(niface);
3081                         break;
3082                 }
3083                 niface->desc = os_strdup(desc[i]);
3084                 niface->next = iface;
3085                 iface = niface;
3086         }
3087
3088 #endif /* CONFIG_USE_NDISUIO */
3089
3090         return iface;
3091 }
3092
3093
3094 const struct wpa_driver_ops wpa_driver_ndis_ops = {
3095         "ndis",
3096         "Windows NDIS driver",
3097         wpa_driver_ndis_get_bssid,
3098         wpa_driver_ndis_get_ssid,
3099         wpa_driver_ndis_set_wpa,
3100         wpa_driver_ndis_set_key,
3101         wpa_driver_ndis_init,
3102         wpa_driver_ndis_deinit,
3103         NULL /* set_param */,
3104         NULL /* set_countermeasures */,
3105         NULL /* set_drop_unencrypted */,
3106         wpa_driver_ndis_scan,
3107         NULL /* get_scan_results */,
3108         wpa_driver_ndis_deauthenticate,
3109         wpa_driver_ndis_disassociate,
3110         wpa_driver_ndis_associate,
3111         NULL /* set_auth_alg */,
3112         wpa_driver_ndis_add_pmkid,
3113         wpa_driver_ndis_remove_pmkid,
3114         wpa_driver_ndis_flush_pmkid,
3115         wpa_driver_ndis_get_capa,
3116         wpa_driver_ndis_poll,
3117         wpa_driver_ndis_get_ifname,
3118         wpa_driver_ndis_get_mac_addr,
3119         NULL /* send_eapol */,
3120         NULL /* set_operstate */,
3121         NULL /* mlme_setprotection */,
3122         NULL /* get_hw_feature_data */,
3123         NULL /* set_channel */,
3124         NULL /* set_ssid */,
3125         NULL /* set_bssid */,
3126         NULL /* send_mlme */,
3127         NULL /* mlme_add_sta */,
3128         NULL /* mlme_remove_sta */,
3129         NULL /* update_ft_ies */,
3130         NULL /* send_ft_action */,
3131         wpa_driver_ndis_get_scan_results,
3132         NULL /* set_probe_req_ie */,
3133         NULL /* set_mode */,
3134         NULL /* set_country */,
3135         NULL /* global_init */,
3136         NULL /* global_deinit */,
3137         NULL /* init2 */,
3138         wpa_driver_ndis_get_interfaces
3139 };