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