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