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