1189251Ssam/*
2189251Ssam * WPA Supplicant - Windows/NDIS driver interface
3189251Ssam * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#ifdef __CYGWIN__
10189251Ssam/* Avoid some header file conflicts by not including standard headers for
11189251Ssam * cygwin builds when Packet32.h is included. */
12189251Ssam#include "build_config.h"
13189251Ssamint close(int fd);
14189251Ssam#else /* __CYGWIN__ */
15189251Ssam#include "includes.h"
16189251Ssam#endif /* __CYGWIN__ */
17189251Ssam#ifdef CONFIG_USE_NDISUIO
18189251Ssam#include <winsock2.h>
19189251Ssam#else /* CONFIG_USE_NDISUIO */
20189251Ssam#include <Packet32.h>
21189251Ssam#endif /* CONFIG_USE_NDISUIO */
22189251Ssam#ifdef __MINGW32_VERSION
23189251Ssam#include <ddk/ntddndis.h>
24189251Ssam#else /* __MINGW32_VERSION */
25189251Ssam#include <ntddndis.h>
26189251Ssam#endif /* __MINGW32_VERSION */
27189251Ssam
28189251Ssam#ifdef _WIN32_WCE
29189251Ssam#include <winioctl.h>
30189251Ssam#include <nuiouser.h>
31189251Ssam#include <devload.h>
32189251Ssam#endif /* _WIN32_WCE */
33189251Ssam
34189251Ssam#include "common.h"
35189251Ssam#include "driver.h"
36189251Ssam#include "eloop.h"
37214734Srpaulo#include "common/ieee802_11_defs.h"
38189251Ssam#include "driver_ndis.h"
39189251Ssam
40189251Ssamint wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv);
41189251Ssam#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
42189251Ssamvoid wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data);
43189251Ssam#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
44189251Ssam
45189251Ssamstatic void wpa_driver_ndis_deinit(void *priv);
46189251Ssamstatic void wpa_driver_ndis_poll(void *drv);
47189251Ssamstatic void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx);
48189251Ssamstatic int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv);
49189251Ssamstatic int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv);
50189251Ssamstatic void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv);
51189251Ssam
52189251Ssam
53209158Srpaulostatic const u8 pae_group_addr[ETH_ALEN] =
54209158Srpaulo{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
55209158Srpaulo
56209158Srpaulo
57189251Ssam/* FIX: to be removed once this can be compiled with the complete NDIS
58189251Ssam * header files */
59189251Ssam#ifndef OID_802_11_BSSID
60209158Srpaulo#define OID_802_3_MULTICAST_LIST                0x01010103
61189251Ssam#define OID_802_11_BSSID 			0x0d010101
62189251Ssam#define OID_802_11_SSID 			0x0d010102
63189251Ssam#define OID_802_11_INFRASTRUCTURE_MODE		0x0d010108
64189251Ssam#define OID_802_11_ADD_WEP			0x0D010113
65189251Ssam#define OID_802_11_REMOVE_WEP			0x0D010114
66189251Ssam#define OID_802_11_DISASSOCIATE			0x0D010115
67189251Ssam#define OID_802_11_BSSID_LIST 			0x0d010217
68189251Ssam#define OID_802_11_AUTHENTICATION_MODE		0x0d010118
69189251Ssam#define OID_802_11_PRIVACY_FILTER		0x0d010119
70189251Ssam#define OID_802_11_BSSID_LIST_SCAN 		0x0d01011A
71189251Ssam#define OID_802_11_WEP_STATUS	 		0x0d01011B
72189251Ssam#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS
73189251Ssam#define OID_802_11_ADD_KEY 			0x0d01011D
74189251Ssam#define OID_802_11_REMOVE_KEY 			0x0d01011E
75189251Ssam#define OID_802_11_ASSOCIATION_INFORMATION	0x0d01011F
76189251Ssam#define OID_802_11_TEST 			0x0d010120
77189251Ssam#define OID_802_11_CAPABILITY 			0x0d010122
78189251Ssam#define OID_802_11_PMKID 			0x0d010123
79189251Ssam
80189251Ssam#define NDIS_802_11_LENGTH_SSID 32
81189251Ssam#define NDIS_802_11_LENGTH_RATES 8
82189251Ssam#define NDIS_802_11_LENGTH_RATES_EX 16
83189251Ssam
84189251Ssamtypedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
85189251Ssam
86189251Ssamtypedef struct NDIS_802_11_SSID {
87189251Ssam	ULONG SsidLength;
88189251Ssam	UCHAR Ssid[NDIS_802_11_LENGTH_SSID];
89189251Ssam} NDIS_802_11_SSID;
90189251Ssam
91189251Ssamtypedef LONG NDIS_802_11_RSSI;
92189251Ssam
93189251Ssamtypedef enum NDIS_802_11_NETWORK_TYPE {
94189251Ssam	Ndis802_11FH,
95189251Ssam	Ndis802_11DS,
96189251Ssam	Ndis802_11OFDM5,
97189251Ssam	Ndis802_11OFDM24,
98189251Ssam	Ndis802_11NetworkTypeMax
99189251Ssam} NDIS_802_11_NETWORK_TYPE;
100189251Ssam
101189251Ssamtypedef struct NDIS_802_11_CONFIGURATION_FH {
102189251Ssam	ULONG Length;
103189251Ssam	ULONG HopPattern;
104189251Ssam	ULONG HopSet;
105189251Ssam	ULONG DwellTime;
106189251Ssam} NDIS_802_11_CONFIGURATION_FH;
107189251Ssam
108189251Ssamtypedef struct NDIS_802_11_CONFIGURATION {
109189251Ssam	ULONG Length;
110189251Ssam	ULONG BeaconPeriod;
111189251Ssam	ULONG ATIMWindow;
112189251Ssam	ULONG DSConfig;
113189251Ssam	NDIS_802_11_CONFIGURATION_FH FHConfig;
114189251Ssam} NDIS_802_11_CONFIGURATION;
115189251Ssam
116189251Ssamtypedef enum NDIS_802_11_NETWORK_INFRASTRUCTURE {
117189251Ssam	Ndis802_11IBSS,
118189251Ssam	Ndis802_11Infrastructure,
119189251Ssam	Ndis802_11AutoUnknown,
120189251Ssam	Ndis802_11InfrastructureMax
121189251Ssam} NDIS_802_11_NETWORK_INFRASTRUCTURE;
122189251Ssam
123189251Ssamtypedef enum NDIS_802_11_AUTHENTICATION_MODE {
124189251Ssam	Ndis802_11AuthModeOpen,
125189251Ssam	Ndis802_11AuthModeShared,
126189251Ssam	Ndis802_11AuthModeAutoSwitch,
127189251Ssam	Ndis802_11AuthModeWPA,
128189251Ssam	Ndis802_11AuthModeWPAPSK,
129189251Ssam	Ndis802_11AuthModeWPANone,
130189251Ssam	Ndis802_11AuthModeWPA2,
131189251Ssam	Ndis802_11AuthModeWPA2PSK,
132189251Ssam	Ndis802_11AuthModeMax
133189251Ssam} NDIS_802_11_AUTHENTICATION_MODE;
134189251Ssam
135189251Ssamtypedef enum NDIS_802_11_WEP_STATUS {
136189251Ssam	Ndis802_11WEPEnabled,
137189251Ssam	Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
138189251Ssam	Ndis802_11WEPDisabled,
139189251Ssam	Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
140189251Ssam	Ndis802_11WEPKeyAbsent,
141189251Ssam	Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
142189251Ssam	Ndis802_11WEPNotSupported,
143189251Ssam	Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
144189251Ssam	Ndis802_11Encryption2Enabled,
145189251Ssam	Ndis802_11Encryption2KeyAbsent,
146189251Ssam	Ndis802_11Encryption3Enabled,
147189251Ssam	Ndis802_11Encryption3KeyAbsent
148189251Ssam} NDIS_802_11_WEP_STATUS, NDIS_802_11_ENCRYPTION_STATUS;
149189251Ssam
150189251Ssamtypedef enum NDIS_802_11_PRIVACY_FILTER {
151189251Ssam	Ndis802_11PrivFilterAcceptAll,
152189251Ssam	Ndis802_11PrivFilter8021xWEP
153189251Ssam} NDIS_802_11_PRIVACY_FILTER;
154189251Ssam
155189251Ssamtypedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES];
156189251Ssamtypedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX];
157189251Ssam
158189251Ssamtypedef struct NDIS_WLAN_BSSID_EX {
159189251Ssam	ULONG Length;
160189251Ssam	NDIS_802_11_MAC_ADDRESS MacAddress; /* BSSID */
161189251Ssam	UCHAR Reserved[2];
162189251Ssam	NDIS_802_11_SSID Ssid;
163189251Ssam	ULONG Privacy;
164189251Ssam	NDIS_802_11_RSSI Rssi;
165189251Ssam	NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
166189251Ssam	NDIS_802_11_CONFIGURATION Configuration;
167189251Ssam	NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
168189251Ssam	NDIS_802_11_RATES_EX SupportedRates;
169189251Ssam	ULONG IELength;
170189251Ssam	UCHAR IEs[1];
171189251Ssam} NDIS_WLAN_BSSID_EX;
172189251Ssam
173189251Ssamtypedef struct NDIS_802_11_BSSID_LIST_EX {
174189251Ssam	ULONG NumberOfItems;
175189251Ssam	NDIS_WLAN_BSSID_EX Bssid[1];
176189251Ssam} NDIS_802_11_BSSID_LIST_EX;
177189251Ssam
178189251Ssamtypedef struct NDIS_802_11_FIXED_IEs {
179189251Ssam	UCHAR Timestamp[8];
180189251Ssam	USHORT BeaconInterval;
181189251Ssam	USHORT Capabilities;
182189251Ssam} NDIS_802_11_FIXED_IEs;
183189251Ssam
184189251Ssamtypedef struct NDIS_802_11_WEP {
185189251Ssam	ULONG Length;
186189251Ssam	ULONG KeyIndex;
187189251Ssam	ULONG KeyLength;
188189251Ssam	UCHAR KeyMaterial[1];
189189251Ssam} NDIS_802_11_WEP;
190189251Ssam
191189251Ssamtypedef ULONG NDIS_802_11_KEY_INDEX;
192189251Ssamtypedef ULONGLONG NDIS_802_11_KEY_RSC;
193189251Ssam
194189251Ssamtypedef struct NDIS_802_11_KEY {
195189251Ssam	ULONG Length;
196189251Ssam	ULONG KeyIndex;
197189251Ssam	ULONG KeyLength;
198189251Ssam	NDIS_802_11_MAC_ADDRESS BSSID;
199189251Ssam	NDIS_802_11_KEY_RSC KeyRSC;
200189251Ssam	UCHAR KeyMaterial[1];
201189251Ssam} NDIS_802_11_KEY;
202189251Ssam
203189251Ssamtypedef struct NDIS_802_11_REMOVE_KEY {
204189251Ssam	ULONG Length;
205189251Ssam	ULONG KeyIndex;
206189251Ssam	NDIS_802_11_MAC_ADDRESS BSSID;
207189251Ssam} NDIS_802_11_REMOVE_KEY;
208189251Ssam
209189251Ssamtypedef struct NDIS_802_11_AI_REQFI {
210189251Ssam	USHORT Capabilities;
211189251Ssam	USHORT ListenInterval;
212189251Ssam	NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
213189251Ssam} NDIS_802_11_AI_REQFI;
214189251Ssam
215189251Ssamtypedef struct NDIS_802_11_AI_RESFI {
216189251Ssam	USHORT Capabilities;
217189251Ssam	USHORT StatusCode;
218189251Ssam	USHORT AssociationId;
219189251Ssam} NDIS_802_11_AI_RESFI;
220189251Ssam
221189251Ssamtypedef struct NDIS_802_11_ASSOCIATION_INFORMATION {
222189251Ssam	ULONG Length;
223189251Ssam	USHORT AvailableRequestFixedIEs;
224189251Ssam	NDIS_802_11_AI_REQFI RequestFixedIEs;
225189251Ssam	ULONG RequestIELength;
226189251Ssam	ULONG OffsetRequestIEs;
227189251Ssam	USHORT AvailableResponseFixedIEs;
228189251Ssam	NDIS_802_11_AI_RESFI ResponseFixedIEs;
229189251Ssam	ULONG ResponseIELength;
230189251Ssam	ULONG OffsetResponseIEs;
231189251Ssam} NDIS_802_11_ASSOCIATION_INFORMATION;
232189251Ssam
233189251Ssamtypedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION {
234189251Ssam	NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported;
235189251Ssam	NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported;
236189251Ssam} NDIS_802_11_AUTHENTICATION_ENCRYPTION;
237189251Ssam
238189251Ssamtypedef struct NDIS_802_11_CAPABILITY {
239189251Ssam	ULONG Length;
240189251Ssam	ULONG Version;
241189251Ssam	ULONG NoOfPMKIDs;
242189251Ssam	ULONG NoOfAuthEncryptPairsSupported;
243189251Ssam	NDIS_802_11_AUTHENTICATION_ENCRYPTION
244189251Ssam		AuthenticationEncryptionSupported[1];
245189251Ssam} NDIS_802_11_CAPABILITY;
246189251Ssam
247189251Ssamtypedef UCHAR NDIS_802_11_PMKID_VALUE[16];
248189251Ssam
249189251Ssamtypedef struct BSSID_INFO {
250189251Ssam	NDIS_802_11_MAC_ADDRESS BSSID;
251189251Ssam	NDIS_802_11_PMKID_VALUE PMKID;
252189251Ssam} BSSID_INFO;
253189251Ssam
254189251Ssamtypedef struct NDIS_802_11_PMKID {
255189251Ssam	ULONG Length;
256189251Ssam	ULONG BSSIDInfoCount;
257189251Ssam	BSSID_INFO BSSIDInfo[1];
258189251Ssam} NDIS_802_11_PMKID;
259189251Ssam
260189251Ssamtypedef enum NDIS_802_11_STATUS_TYPE {
261189251Ssam	Ndis802_11StatusType_Authentication,
262189251Ssam	Ndis802_11StatusType_PMKID_CandidateList = 2,
263189251Ssam	Ndis802_11StatusTypeMax
264189251Ssam} NDIS_802_11_STATUS_TYPE;
265189251Ssam
266189251Ssamtypedef struct NDIS_802_11_STATUS_INDICATION {
267189251Ssam	NDIS_802_11_STATUS_TYPE StatusType;
268189251Ssam} NDIS_802_11_STATUS_INDICATION;
269189251Ssam
270189251Ssamtypedef struct PMKID_CANDIDATE {
271189251Ssam	NDIS_802_11_MAC_ADDRESS BSSID;
272189251Ssam	ULONG Flags;
273189251Ssam} PMKID_CANDIDATE;
274189251Ssam
275189251Ssam#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
276189251Ssam
277189251Ssamtypedef struct NDIS_802_11_PMKID_CANDIDATE_LIST {
278189251Ssam	ULONG Version;
279189251Ssam	ULONG NumCandidates;
280189251Ssam	PMKID_CANDIDATE CandidateList[1];
281189251Ssam} NDIS_802_11_PMKID_CANDIDATE_LIST;
282189251Ssam
283189251Ssamtypedef struct NDIS_802_11_AUTHENTICATION_REQUEST {
284189251Ssam	ULONG Length;
285189251Ssam	NDIS_802_11_MAC_ADDRESS Bssid;
286189251Ssam	ULONG Flags;
287189251Ssam} NDIS_802_11_AUTHENTICATION_REQUEST;
288189251Ssam
289189251Ssam#define NDIS_802_11_AUTH_REQUEST_REAUTH			0x01
290189251Ssam#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE		0x02
291189251Ssam#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR		0x06
292189251Ssam#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR		0x0E
293189251Ssam
294189251Ssam#endif /* OID_802_11_BSSID */
295189251Ssam
296189251Ssam
297189251Ssam#ifndef OID_802_11_PMKID
298189251Ssam/* Platform SDK for XP did not include WPA2, so add needed definitions */
299189251Ssam
300189251Ssam#define OID_802_11_CAPABILITY 			0x0d010122
301189251Ssam#define OID_802_11_PMKID 			0x0d010123
302189251Ssam
303189251Ssam#define Ndis802_11AuthModeWPA2 6
304189251Ssam#define Ndis802_11AuthModeWPA2PSK 7
305189251Ssam
306189251Ssam#define Ndis802_11StatusType_PMKID_CandidateList 2
307189251Ssam
308189251Ssamtypedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION {
309189251Ssam	NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported;
310189251Ssam	NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported;
311189251Ssam} NDIS_802_11_AUTHENTICATION_ENCRYPTION;
312189251Ssam
313189251Ssamtypedef struct NDIS_802_11_CAPABILITY {
314189251Ssam	ULONG Length;
315189251Ssam	ULONG Version;
316189251Ssam	ULONG NoOfPMKIDs;
317189251Ssam	ULONG NoOfAuthEncryptPairsSupported;
318189251Ssam	NDIS_802_11_AUTHENTICATION_ENCRYPTION
319189251Ssam		AuthenticationEncryptionSupported[1];
320189251Ssam} NDIS_802_11_CAPABILITY;
321189251Ssam
322189251Ssamtypedef UCHAR NDIS_802_11_PMKID_VALUE[16];
323189251Ssam
324189251Ssamtypedef struct BSSID_INFO {
325189251Ssam	NDIS_802_11_MAC_ADDRESS BSSID;
326189251Ssam	NDIS_802_11_PMKID_VALUE PMKID;
327189251Ssam} BSSID_INFO;
328189251Ssam
329189251Ssamtypedef struct NDIS_802_11_PMKID {
330189251Ssam	ULONG Length;
331189251Ssam	ULONG BSSIDInfoCount;
332189251Ssam	BSSID_INFO BSSIDInfo[1];
333189251Ssam} NDIS_802_11_PMKID;
334189251Ssam
335189251Ssamtypedef struct PMKID_CANDIDATE {
336189251Ssam	NDIS_802_11_MAC_ADDRESS BSSID;
337189251Ssam	ULONG Flags;
338189251Ssam} PMKID_CANDIDATE;
339189251Ssam
340189251Ssam#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
341189251Ssam
342189251Ssamtypedef struct NDIS_802_11_PMKID_CANDIDATE_LIST {
343189251Ssam	ULONG Version;
344189251Ssam	ULONG NumCandidates;
345189251Ssam	PMKID_CANDIDATE CandidateList[1];
346189251Ssam} NDIS_802_11_PMKID_CANDIDATE_LIST;
347189251Ssam
348189251Ssam#endif /* OID_802_11_CAPABILITY */
349189251Ssam
350189251Ssam
351214734Srpaulo#ifndef OID_DOT11_CURRENT_OPERATION_MODE
352214734Srpaulo/* Native 802.11 OIDs */
353214734Srpaulo#define OID_DOT11_NDIS_START 0x0D010300
354214734Srpaulo#define OID_DOT11_CURRENT_OPERATION_MODE (OID_DOT11_NDIS_START + 8)
355214734Srpaulo#define OID_DOT11_SCAN_REQUEST (OID_DOT11_NDIS_START + 11)
356214734Srpaulo
357214734Srpaulotypedef enum _DOT11_BSS_TYPE {
358214734Srpaulo	dot11_BSS_type_infrastructure = 1,
359214734Srpaulo	dot11_BSS_type_independent = 2,
360214734Srpaulo	dot11_BSS_type_any = 3
361214734Srpaulo} DOT11_BSS_TYPE, * PDOT11_BSS_TYPE;
362214734Srpaulo
363214734Srpaulotypedef UCHAR DOT11_MAC_ADDRESS[6];
364214734Srpaulotypedef DOT11_MAC_ADDRESS * PDOT11_MAC_ADDRESS;
365214734Srpaulo
366214734Srpaulotypedef enum _DOT11_SCAN_TYPE {
367214734Srpaulo	dot11_scan_type_active = 1,
368214734Srpaulo	dot11_scan_type_passive = 2,
369214734Srpaulo	dot11_scan_type_auto = 3,
370214734Srpaulo	dot11_scan_type_forced = 0x80000000
371214734Srpaulo} DOT11_SCAN_TYPE, * PDOT11_SCAN_TYPE;
372214734Srpaulo
373214734Srpaulotypedef struct _DOT11_SCAN_REQUEST_V2 {
374214734Srpaulo	DOT11_BSS_TYPE dot11BSSType;
375214734Srpaulo	DOT11_MAC_ADDRESS dot11BSSID;
376214734Srpaulo	DOT11_SCAN_TYPE dot11ScanType;
377214734Srpaulo	BOOLEAN bRestrictedScan;
378214734Srpaulo	ULONG udot11SSIDsOffset;
379214734Srpaulo	ULONG uNumOfdot11SSIDs;
380214734Srpaulo	BOOLEAN bUseRequestIE;
381214734Srpaulo	ULONG uRequestIDsOffset;
382214734Srpaulo	ULONG uNumOfRequestIDs;
383214734Srpaulo	ULONG uPhyTypeInfosOffset;
384214734Srpaulo	ULONG uNumOfPhyTypeInfos;
385214734Srpaulo	ULONG uIEsOffset;
386214734Srpaulo	ULONG uIEsLength;
387214734Srpaulo	UCHAR ucBuffer[1];
388214734Srpaulo} DOT11_SCAN_REQUEST_V2, * PDOT11_SCAN_REQUEST_V2;
389214734Srpaulo
390214734Srpaulo#endif /* OID_DOT11_CURRENT_OPERATION_MODE */
391214734Srpaulo
392189251Ssam#ifdef CONFIG_USE_NDISUIO
393189251Ssam#ifndef _WIN32_WCE
394189251Ssam#ifdef __MINGW32_VERSION
395189251Ssamtypedef ULONG NDIS_OID;
396189251Ssam#endif /* __MINGW32_VERSION */
397189251Ssam/* from nuiouser.h */
398189251Ssam#define FSCTL_NDISUIO_BASE      FILE_DEVICE_NETWORK
399189251Ssam
400189251Ssam#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
401189251Ssam	CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
402189251Ssam
403189251Ssam#define IOCTL_NDISUIO_OPEN_DEVICE \
404189251Ssam	_NDISUIO_CTL_CODE(0x200, METHOD_BUFFERED, \
405189251Ssam			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
406189251Ssam
407189251Ssam#define IOCTL_NDISUIO_QUERY_OID_VALUE \
408189251Ssam	_NDISUIO_CTL_CODE(0x201, METHOD_BUFFERED, \
409189251Ssam			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
410189251Ssam
411189251Ssam#define IOCTL_NDISUIO_SET_OID_VALUE \
412189251Ssam	_NDISUIO_CTL_CODE(0x205, METHOD_BUFFERED, \
413189251Ssam			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
414189251Ssam
415189251Ssam#define IOCTL_NDISUIO_SET_ETHER_TYPE \
416189251Ssam	_NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \
417189251Ssam			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
418189251Ssam
419189251Ssam#define IOCTL_NDISUIO_QUERY_BINDING \
420189251Ssam	_NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \
421189251Ssam			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
422189251Ssam
423189251Ssam#define IOCTL_NDISUIO_BIND_WAIT \
424189251Ssam	_NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \
425189251Ssam			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
426189251Ssam
427189251Ssamtypedef struct _NDISUIO_QUERY_OID
428189251Ssam{
429189251Ssam    NDIS_OID Oid;
430189251Ssam    UCHAR Data[sizeof(ULONG)];
431189251Ssam} NDISUIO_QUERY_OID, *PNDISUIO_QUERY_OID;
432189251Ssam
433189251Ssamtypedef struct _NDISUIO_SET_OID
434189251Ssam{
435189251Ssam    NDIS_OID Oid;
436189251Ssam    UCHAR Data[sizeof(ULONG)];
437189251Ssam} NDISUIO_SET_OID, *PNDISUIO_SET_OID;
438189251Ssam
439189251Ssamtypedef struct _NDISUIO_QUERY_BINDING
440189251Ssam{
441189251Ssam	ULONG BindingIndex;
442189251Ssam	ULONG DeviceNameOffset;
443189251Ssam	ULONG DeviceNameLength;
444189251Ssam	ULONG DeviceDescrOffset;
445189251Ssam	ULONG DeviceDescrLength;
446189251Ssam} NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING;
447189251Ssam#endif /* _WIN32_WCE */
448189251Ssam#endif /* CONFIG_USE_NDISUIO */
449189251Ssam
450189251Ssam
451189251Ssamstatic int ndis_get_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
452189251Ssam			char *data, size_t len)
453189251Ssam{
454189251Ssam#ifdef CONFIG_USE_NDISUIO
455189251Ssam	NDISUIO_QUERY_OID *o;
456189251Ssam	size_t buflen = sizeof(*o) + len;
457189251Ssam	DWORD written;
458189251Ssam	int ret;
459189251Ssam	size_t hdrlen;
460189251Ssam
461189251Ssam	o = os_zalloc(buflen);
462189251Ssam	if (o == NULL)
463189251Ssam		return -1;
464189251Ssam	o->Oid = oid;
465189251Ssam#ifdef _WIN32_WCE
466189251Ssam	o->ptcDeviceName = drv->adapter_name;
467189251Ssam#endif /* _WIN32_WCE */
468189251Ssam	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_OID_VALUE,
469189251Ssam			     o, sizeof(NDISUIO_QUERY_OID), o, buflen, &written,
470189251Ssam			     NULL)) {
471189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_QUERY_OID_VALUE "
472189251Ssam			   "failed (oid=%08x): %d", oid, (int) GetLastError());
473189251Ssam		os_free(o);
474189251Ssam		return -1;
475189251Ssam	}
476189251Ssam	hdrlen = sizeof(NDISUIO_QUERY_OID) - sizeof(o->Data);
477189251Ssam	if (written < hdrlen) {
478189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d); "
479189251Ssam			   "too short", oid, (unsigned int) written);
480189251Ssam		os_free(o);
481189251Ssam		return -1;
482189251Ssam	}
483189251Ssam	written -= hdrlen;
484189251Ssam	if (written > len) {
485189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d) > "
486189251Ssam			   "len (%d)",oid, (unsigned int) written, len);
487189251Ssam		os_free(o);
488189251Ssam		return -1;
489189251Ssam	}
490189251Ssam	os_memcpy(data, o->Data, written);
491189251Ssam	ret = written;
492189251Ssam	os_free(o);
493189251Ssam	return ret;
494189251Ssam#else /* CONFIG_USE_NDISUIO */
495189251Ssam	char *buf;
496189251Ssam	PACKET_OID_DATA *o;
497189251Ssam	int ret;
498189251Ssam
499189251Ssam	buf = os_zalloc(sizeof(*o) + len);
500189251Ssam	if (buf == NULL)
501189251Ssam		return -1;
502189251Ssam	o = (PACKET_OID_DATA *) buf;
503189251Ssam	o->Oid = oid;
504189251Ssam	o->Length = len;
505189251Ssam
506189251Ssam	if (!PacketRequest(drv->adapter, FALSE, o)) {
507189251Ssam		wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
508189251Ssam			   __func__, oid, len);
509189251Ssam		os_free(buf);
510189251Ssam		return -1;
511189251Ssam	}
512189251Ssam	if (o->Length > len) {
513189251Ssam		wpa_printf(MSG_DEBUG, "%s: oid=0x%x Length (%d) > len (%d)",
514189251Ssam			   __func__, oid, (unsigned int) o->Length, len);
515189251Ssam		os_free(buf);
516189251Ssam		return -1;
517189251Ssam	}
518189251Ssam	os_memcpy(data, o->Data, o->Length);
519189251Ssam	ret = o->Length;
520189251Ssam	os_free(buf);
521189251Ssam	return ret;
522189251Ssam#endif /* CONFIG_USE_NDISUIO */
523189251Ssam}
524189251Ssam
525189251Ssam
526189251Ssamstatic int ndis_set_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
527189251Ssam			const char *data, size_t len)
528189251Ssam{
529189251Ssam#ifdef CONFIG_USE_NDISUIO
530189251Ssam	NDISUIO_SET_OID *o;
531189251Ssam	size_t buflen, reallen;
532189251Ssam	DWORD written;
533189251Ssam	char txt[50];
534189251Ssam
535189251Ssam	os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
536189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len);
537189251Ssam
538189251Ssam	buflen = sizeof(*o) + len;
539189251Ssam	reallen = buflen - sizeof(o->Data);
540189251Ssam	o = os_zalloc(buflen);
541189251Ssam	if (o == NULL)
542189251Ssam		return -1;
543189251Ssam	o->Oid = oid;
544189251Ssam#ifdef _WIN32_WCE
545189251Ssam	o->ptcDeviceName = drv->adapter_name;
546189251Ssam#endif /* _WIN32_WCE */
547189251Ssam	if (data)
548189251Ssam		os_memcpy(o->Data, data, len);
549189251Ssam	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_SET_OID_VALUE,
550189251Ssam			     o, reallen, NULL, 0, &written, NULL)) {
551189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_SET_OID_VALUE "
552189251Ssam			   "(oid=%08x) failed: %d", oid, (int) GetLastError());
553189251Ssam		os_free(o);
554189251Ssam		return -1;
555189251Ssam	}
556189251Ssam	os_free(o);
557189251Ssam	return 0;
558189251Ssam#else /* CONFIG_USE_NDISUIO */
559189251Ssam	char *buf;
560189251Ssam	PACKET_OID_DATA *o;
561189251Ssam	char txt[50];
562189251Ssam
563189251Ssam	os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
564189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len);
565189251Ssam
566189251Ssam	buf = os_zalloc(sizeof(*o) + len);
567189251Ssam	if (buf == NULL)
568189251Ssam		return -1;
569189251Ssam	o = (PACKET_OID_DATA *) buf;
570189251Ssam	o->Oid = oid;
571189251Ssam	o->Length = len;
572189251Ssam	if (data)
573189251Ssam		os_memcpy(o->Data, data, len);
574189251Ssam
575189251Ssam	if (!PacketRequest(drv->adapter, TRUE, o)) {
576189251Ssam		wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
577189251Ssam			   __func__, oid, len);
578189251Ssam		os_free(buf);
579189251Ssam		return -1;
580189251Ssam	}
581189251Ssam	os_free(buf);
582189251Ssam	return 0;
583189251Ssam#endif /* CONFIG_USE_NDISUIO */
584189251Ssam}
585189251Ssam
586189251Ssam
587189251Ssamstatic int ndis_set_auth_mode(struct wpa_driver_ndis_data *drv, int mode)
588189251Ssam{
589189251Ssam	u32 auth_mode = mode;
590189251Ssam	if (ndis_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
591189251Ssam			 (char *) &auth_mode, sizeof(auth_mode)) < 0) {
592189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
593189251Ssam			   "OID_802_11_AUTHENTICATION_MODE (%d)",
594189251Ssam			   (int) auth_mode);
595189251Ssam		return -1;
596189251Ssam	}
597189251Ssam	return 0;
598189251Ssam}
599189251Ssam
600189251Ssam
601189251Ssamstatic int ndis_get_auth_mode(struct wpa_driver_ndis_data *drv)
602189251Ssam{
603189251Ssam	u32 auth_mode;
604189251Ssam	int res;
605189251Ssam	res = ndis_get_oid(drv, OID_802_11_AUTHENTICATION_MODE,
606189251Ssam			   (char *) &auth_mode, sizeof(auth_mode));
607189251Ssam	if (res != sizeof(auth_mode)) {
608189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Failed to get "
609189251Ssam			   "OID_802_11_AUTHENTICATION_MODE");
610189251Ssam		return -1;
611189251Ssam	}
612189251Ssam	return auth_mode;
613189251Ssam}
614189251Ssam
615189251Ssam
616189251Ssamstatic int ndis_set_encr_status(struct wpa_driver_ndis_data *drv, int encr)
617189251Ssam{
618189251Ssam	u32 encr_status = encr;
619189251Ssam	if (ndis_set_oid(drv, OID_802_11_ENCRYPTION_STATUS,
620189251Ssam			 (char *) &encr_status, sizeof(encr_status)) < 0) {
621189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
622189251Ssam			   "OID_802_11_ENCRYPTION_STATUS (%d)", encr);
623189251Ssam		return -1;
624189251Ssam	}
625189251Ssam	return 0;
626189251Ssam}
627189251Ssam
628189251Ssam
629189251Ssamstatic int ndis_get_encr_status(struct wpa_driver_ndis_data *drv)
630189251Ssam{
631189251Ssam	u32 encr;
632189251Ssam	int res;
633189251Ssam	res = ndis_get_oid(drv, OID_802_11_ENCRYPTION_STATUS,
634189251Ssam			   (char *) &encr, sizeof(encr));
635189251Ssam	if (res != sizeof(encr)) {
636189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Failed to get "
637189251Ssam			   "OID_802_11_ENCRYPTION_STATUS");
638189251Ssam		return -1;
639189251Ssam	}
640189251Ssam	return encr;
641189251Ssam}
642189251Ssam
643189251Ssam
644189251Ssamstatic int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid)
645189251Ssam{
646189251Ssam	struct wpa_driver_ndis_data *drv = priv;
647189251Ssam
648189251Ssam	if (drv->wired) {
649189251Ssam		/*
650189251Ssam		 * Report PAE group address as the "BSSID" for wired
651189251Ssam		 * connection.
652189251Ssam		 */
653209158Srpaulo		os_memcpy(bssid, pae_group_addr, ETH_ALEN);
654189251Ssam		return 0;
655189251Ssam	}
656189251Ssam
657189251Ssam	return ndis_get_oid(drv, OID_802_11_BSSID, (char *) bssid, ETH_ALEN) <
658189251Ssam		0 ? -1 : 0;
659189251Ssam}
660189251Ssam
661189251Ssam
662189251Ssamstatic int wpa_driver_ndis_get_ssid(void *priv, u8 *ssid)
663189251Ssam{
664189251Ssam	struct wpa_driver_ndis_data *drv = priv;
665189251Ssam	NDIS_802_11_SSID buf;
666189251Ssam	int res;
667189251Ssam
668189251Ssam	res = ndis_get_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
669189251Ssam	if (res < 4) {
670189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Failed to get SSID");
671189251Ssam		if (drv->wired) {
672189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Allow get_ssid failure "
673189251Ssam				   "with a wired interface");
674189251Ssam			return 0;
675189251Ssam		}
676189251Ssam		return -1;
677189251Ssam	}
678189251Ssam	os_memcpy(ssid, buf.Ssid, buf.SsidLength);
679189251Ssam	return buf.SsidLength;
680189251Ssam}
681189251Ssam
682189251Ssam
683189251Ssamstatic int wpa_driver_ndis_set_ssid(struct wpa_driver_ndis_data *drv,
684189251Ssam				    const u8 *ssid, size_t ssid_len)
685189251Ssam{
686189251Ssam	NDIS_802_11_SSID buf;
687189251Ssam
688189251Ssam	os_memset(&buf, 0, sizeof(buf));
689189251Ssam	buf.SsidLength = ssid_len;
690189251Ssam	os_memcpy(buf.Ssid, ssid, ssid_len);
691189251Ssam	/*
692189251Ssam	 * Make sure radio is marked enabled here so that scan request will not
693189251Ssam	 * force SSID to be changed to a random one in order to enable radio at
694189251Ssam	 * that point.
695189251Ssam	 */
696189251Ssam	drv->radio_enabled = 1;
697189251Ssam	return ndis_set_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
698189251Ssam}
699189251Ssam
700189251Ssam
701189251Ssam/* Disconnect using OID_802_11_DISASSOCIATE. This will also turn the radio off.
702189251Ssam */
703189251Ssamstatic int wpa_driver_ndis_radio_off(struct wpa_driver_ndis_data *drv)
704189251Ssam{
705189251Ssam	drv->radio_enabled = 0;
706189251Ssam	return ndis_set_oid(drv, OID_802_11_DISASSOCIATE, "    ", 4);
707189251Ssam}
708189251Ssam
709189251Ssam
710189251Ssam/* Disconnect by setting SSID to random (i.e., likely not used). */
711189251Ssamstatic int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv)
712189251Ssam{
713189251Ssam	char ssid[32];
714189251Ssam	int i;
715189251Ssam	for (i = 0; i < 32; i++)
716189251Ssam		ssid[i] = rand() & 0xff;
717189251Ssam	return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32);
718189251Ssam}
719189251Ssam
720189251Ssam
721189251Ssamstatic int wpa_driver_ndis_deauthenticate(void *priv, const u8 *addr,
722189251Ssam					  int reason_code)
723189251Ssam{
724189251Ssam	struct wpa_driver_ndis_data *drv = priv;
725189251Ssam	return wpa_driver_ndis_disconnect(drv);
726189251Ssam}
727189251Ssam
728189251Ssam
729214734Srpaulostatic void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx)
730189251Ssam{
731214734Srpaulo	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
732214734Srpaulo	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
733189251Ssam}
734189251Ssam
735189251Ssam
736214734Srpaulostatic int wpa_driver_ndis_scan_native80211(
737214734Srpaulo	struct wpa_driver_ndis_data *drv,
738214734Srpaulo	struct wpa_driver_scan_params *params)
739189251Ssam{
740214734Srpaulo	DOT11_SCAN_REQUEST_V2 req;
741214734Srpaulo	int res;
742214734Srpaulo
743214734Srpaulo	os_memset(&req, 0, sizeof(req));
744214734Srpaulo	req.dot11BSSType = dot11_BSS_type_any;
745214734Srpaulo	os_memset(req.dot11BSSID, 0xff, ETH_ALEN);
746214734Srpaulo	req.dot11ScanType = dot11_scan_type_auto;
747214734Srpaulo	res = ndis_set_oid(drv, OID_DOT11_SCAN_REQUEST, (char *) &req,
748214734Srpaulo			   sizeof(req));
749214734Srpaulo	eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
750214734Srpaulo	eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv,
751214734Srpaulo			       drv->ctx);
752214734Srpaulo	return res;
753189251Ssam}
754189251Ssam
755189251Ssam
756214734Srpaulostatic int wpa_driver_ndis_scan(void *priv,
757214734Srpaulo				struct wpa_driver_scan_params *params)
758189251Ssam{
759189251Ssam	struct wpa_driver_ndis_data *drv = priv;
760189251Ssam	int res;
761189251Ssam
762214734Srpaulo	if (drv->native80211)
763214734Srpaulo		return wpa_driver_ndis_scan_native80211(drv, params);
764214734Srpaulo
765189251Ssam	if (!drv->radio_enabled) {
766189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: turning radio on before the first"
767189251Ssam			   " scan");
768189251Ssam		if (wpa_driver_ndis_disconnect(drv) < 0) {
769189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: failed to enable radio");
770189251Ssam		}
771189251Ssam		drv->radio_enabled = 1;
772189251Ssam	}
773189251Ssam
774189251Ssam	res = ndis_set_oid(drv, OID_802_11_BSSID_LIST_SCAN, "    ", 4);
775189251Ssam	eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
776189251Ssam	eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv,
777189251Ssam			       drv->ctx);
778189251Ssam	return res;
779189251Ssam}
780189251Ssam
781189251Ssam
782214734Srpaulostatic const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
783214734Srpaulo{
784214734Srpaulo	const u8 *end, *pos;
785214734Srpaulo
786214734Srpaulo	pos = (const u8 *) (res + 1);
787214734Srpaulo	end = pos + res->ie_len;
788214734Srpaulo
789214734Srpaulo	while (pos + 1 < end) {
790214734Srpaulo		if (pos + 2 + pos[1] > end)
791214734Srpaulo			break;
792214734Srpaulo		if (pos[0] == ie)
793214734Srpaulo			return pos;
794214734Srpaulo		pos += 2 + pos[1];
795214734Srpaulo	}
796214734Srpaulo
797214734Srpaulo	return NULL;
798214734Srpaulo}
799214734Srpaulo
800214734Srpaulo
801189251Ssamstatic struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid(
802189251Ssam	struct wpa_scan_res *r, NDIS_802_11_SSID *ssid)
803189251Ssam{
804189251Ssam	struct wpa_scan_res *nr;
805189251Ssam	u8 *pos;
806189251Ssam
807189251Ssam	if (wpa_scan_get_ie(r, WLAN_EID_SSID))
808189251Ssam		return r; /* SSID IE already present */
809189251Ssam
810189251Ssam	if (ssid->SsidLength == 0 || ssid->SsidLength > 32)
811189251Ssam		return r; /* No valid SSID inside scan data */
812189251Ssam
813189251Ssam	nr = os_realloc(r, sizeof(*r) + r->ie_len + 2 + ssid->SsidLength);
814189251Ssam	if (nr == NULL)
815189251Ssam		return r;
816189251Ssam
817189251Ssam	pos = ((u8 *) (nr + 1)) + nr->ie_len;
818189251Ssam	*pos++ = WLAN_EID_SSID;
819189251Ssam	*pos++ = ssid->SsidLength;
820189251Ssam	os_memcpy(pos, ssid->Ssid, ssid->SsidLength);
821189251Ssam	nr->ie_len += 2 + ssid->SsidLength;
822189251Ssam
823189251Ssam	return nr;
824189251Ssam}
825189251Ssam
826189251Ssam
827189251Ssamstatic struct wpa_scan_results * wpa_driver_ndis_get_scan_results(void *priv)
828189251Ssam{
829189251Ssam	struct wpa_driver_ndis_data *drv = priv;
830189251Ssam	NDIS_802_11_BSSID_LIST_EX *b;
831189251Ssam	size_t blen, count, i;
832189251Ssam	int len;
833189251Ssam	char *pos;
834189251Ssam	struct wpa_scan_results *results;
835189251Ssam	struct wpa_scan_res *r;
836189251Ssam
837189251Ssam	blen = 65535;
838189251Ssam	b = os_zalloc(blen);
839189251Ssam	if (b == NULL)
840189251Ssam		return NULL;
841189251Ssam	len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
842189251Ssam	if (len < 0) {
843189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
844189251Ssam		os_free(b);
845189251Ssam		return NULL;
846189251Ssam	}
847189251Ssam	count = b->NumberOfItems;
848189251Ssam
849189251Ssam	results = os_zalloc(sizeof(*results));
850189251Ssam	if (results == NULL) {
851189251Ssam		os_free(b);
852189251Ssam		return NULL;
853189251Ssam	}
854252726Srpaulo	results->res = os_calloc(count, sizeof(struct wpa_scan_res *));
855189251Ssam	if (results->res == NULL) {
856189251Ssam		os_free(results);
857189251Ssam		os_free(b);
858189251Ssam		return NULL;
859189251Ssam	}
860189251Ssam
861189251Ssam	pos = (char *) &b->Bssid[0];
862189251Ssam	for (i = 0; i < count; i++) {
863189251Ssam		NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
864189251Ssam		NDIS_802_11_FIXED_IEs *fixed;
865189251Ssam
866189251Ssam		if (bss->IELength < sizeof(NDIS_802_11_FIXED_IEs)) {
867189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: too small IELength=%d",
868189251Ssam				   (int) bss->IELength);
869189251Ssam			break;
870189251Ssam		}
871189251Ssam		if (((char *) bss->IEs) + bss->IELength  > (char *) b + blen) {
872189251Ssam			/*
873189251Ssam			 * Some NDIS drivers have been reported to include an
874189251Ssam			 * entry with an invalid IELength in scan results and
875189251Ssam			 * this has crashed wpa_supplicant, so validate the
876189251Ssam			 * returned value before using it.
877189251Ssam			 */
878189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: skipped invalid scan "
879189251Ssam				   "result IE (BSSID=" MACSTR ") IELength=%d",
880189251Ssam				   MAC2STR(bss->MacAddress),
881189251Ssam				   (int) bss->IELength);
882189251Ssam			break;
883189251Ssam		}
884189251Ssam
885189251Ssam		r = os_zalloc(sizeof(*r) + bss->IELength -
886189251Ssam			      sizeof(NDIS_802_11_FIXED_IEs));
887189251Ssam		if (r == NULL)
888189251Ssam			break;
889189251Ssam
890189251Ssam		os_memcpy(r->bssid, bss->MacAddress, ETH_ALEN);
891189251Ssam		r->level = (int) bss->Rssi;
892189251Ssam		r->freq = bss->Configuration.DSConfig / 1000;
893189251Ssam		fixed = (NDIS_802_11_FIXED_IEs *) bss->IEs;
894189251Ssam		r->beacon_int = WPA_GET_LE16((u8 *) &fixed->BeaconInterval);
895189251Ssam		r->caps = WPA_GET_LE16((u8 *) &fixed->Capabilities);
896189251Ssam		r->tsf = WPA_GET_LE64(fixed->Timestamp);
897189251Ssam		os_memcpy(r + 1, bss->IEs + sizeof(NDIS_802_11_FIXED_IEs),
898189251Ssam			  bss->IELength - sizeof(NDIS_802_11_FIXED_IEs));
899189251Ssam		r->ie_len = bss->IELength - sizeof(NDIS_802_11_FIXED_IEs);
900189251Ssam		r = wpa_driver_ndis_add_scan_ssid(r, &bss->Ssid);
901189251Ssam
902189251Ssam		results->res[results->num++] = r;
903189251Ssam
904189251Ssam		pos += bss->Length;
905189251Ssam		if (pos > (char *) b + blen)
906189251Ssam			break;
907189251Ssam	}
908189251Ssam
909189251Ssam	os_free(b);
910189251Ssam
911189251Ssam	return results;
912189251Ssam}
913189251Ssam
914189251Ssam
915189251Ssamstatic int wpa_driver_ndis_remove_key(struct wpa_driver_ndis_data *drv,
916189251Ssam				      int key_idx, const u8 *addr,
917189251Ssam				      const u8 *bssid, int pairwise)
918189251Ssam{
919189251Ssam	NDIS_802_11_REMOVE_KEY rkey;
920189251Ssam	NDIS_802_11_KEY_INDEX index;
921189251Ssam	int res, res2;
922189251Ssam
923189251Ssam	os_memset(&rkey, 0, sizeof(rkey));
924189251Ssam
925189251Ssam	rkey.Length = sizeof(rkey);
926189251Ssam	rkey.KeyIndex = key_idx;
927189251Ssam	if (pairwise)
928189251Ssam		rkey.KeyIndex |= 1 << 30;
929189251Ssam	os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
930189251Ssam
931189251Ssam	res = ndis_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
932189251Ssam			   sizeof(rkey));
933189251Ssam	if (!pairwise) {
934189251Ssam		index = key_idx;
935189251Ssam		res2 = ndis_set_oid(drv, OID_802_11_REMOVE_WEP,
936189251Ssam				    (char *) &index, sizeof(index));
937189251Ssam	} else
938189251Ssam		res2 = 0;
939189251Ssam
940189251Ssam	if (res < 0 && res2 < 0)
941189251Ssam		return -1;
942189251Ssam	return 0;
943189251Ssam}
944189251Ssam
945189251Ssam
946189251Ssamstatic int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv,
947189251Ssam				   int pairwise, int key_idx, int set_tx,
948189251Ssam				   const u8 *key, size_t key_len)
949189251Ssam{
950189251Ssam	NDIS_802_11_WEP *wep;
951189251Ssam	size_t len;
952189251Ssam	int res;
953189251Ssam
954189251Ssam	len = 12 + key_len;
955189251Ssam	wep = os_zalloc(len);
956189251Ssam	if (wep == NULL)
957189251Ssam		return -1;
958189251Ssam	wep->Length = len;
959189251Ssam	wep->KeyIndex = key_idx;
960189251Ssam	if (set_tx)
961189251Ssam		wep->KeyIndex |= 1 << 31;
962189251Ssam#if 0 /* Setting bit30 does not seem to work with some NDIS drivers */
963189251Ssam	if (pairwise)
964189251Ssam		wep->KeyIndex |= 1 << 30;
965189251Ssam#endif
966189251Ssam	wep->KeyLength = key_len;
967189251Ssam	os_memcpy(wep->KeyMaterial, key, key_len);
968189251Ssam
969189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_WEP",
970189251Ssam			(u8 *) wep, len);
971189251Ssam	res = ndis_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
972189251Ssam
973189251Ssam	os_free(wep);
974189251Ssam
975189251Ssam	return res;
976189251Ssam}
977189251Ssam
978189251Ssam
979214734Srpaulostatic int wpa_driver_ndis_set_key(const char *ifname, void *priv,
980214734Srpaulo				   enum wpa_alg alg, const u8 *addr,
981189251Ssam				   int key_idx, int set_tx,
982189251Ssam				   const u8 *seq, size_t seq_len,
983189251Ssam				   const u8 *key, size_t key_len)
984189251Ssam{
985189251Ssam	struct wpa_driver_ndis_data *drv = priv;
986189251Ssam	size_t len, i;
987189251Ssam	NDIS_802_11_KEY *nkey;
988189251Ssam	int res, pairwise;
989189251Ssam	u8 bssid[ETH_ALEN];
990189251Ssam
991252726Srpaulo	if (addr == NULL || is_broadcast_ether_addr(addr)) {
992189251Ssam		/* Group Key */
993189251Ssam		pairwise = 0;
994189251Ssam		if (wpa_driver_ndis_get_bssid(drv, bssid) < 0)
995189251Ssam			os_memset(bssid, 0xff, ETH_ALEN);
996189251Ssam	} else {
997189251Ssam		/* Pairwise Key */
998189251Ssam		pairwise = 1;
999189251Ssam		os_memcpy(bssid, addr, ETH_ALEN);
1000189251Ssam	}
1001189251Ssam
1002189251Ssam	if (alg == WPA_ALG_NONE || key_len == 0) {
1003189251Ssam		return wpa_driver_ndis_remove_key(drv, key_idx, addr, bssid,
1004189251Ssam						  pairwise);
1005189251Ssam	}
1006189251Ssam
1007189251Ssam	if (alg == WPA_ALG_WEP) {
1008189251Ssam		return wpa_driver_ndis_add_wep(drv, pairwise, key_idx, set_tx,
1009189251Ssam					       key, key_len);
1010189251Ssam	}
1011189251Ssam
1012189251Ssam	len = 12 + 6 + 6 + 8 + key_len;
1013189251Ssam
1014189251Ssam	nkey = os_zalloc(len);
1015189251Ssam	if (nkey == NULL)
1016189251Ssam		return -1;
1017189251Ssam
1018189251Ssam	nkey->Length = len;
1019189251Ssam	nkey->KeyIndex = key_idx;
1020189251Ssam	if (set_tx)
1021189251Ssam		nkey->KeyIndex |= 1 << 31;
1022189251Ssam	if (pairwise)
1023189251Ssam		nkey->KeyIndex |= 1 << 30;
1024189251Ssam	if (seq && seq_len)
1025189251Ssam		nkey->KeyIndex |= 1 << 29;
1026189251Ssam	nkey->KeyLength = key_len;
1027189251Ssam	os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
1028189251Ssam	if (seq && seq_len) {
1029189251Ssam		for (i = 0; i < seq_len; i++)
1030189251Ssam			nkey->KeyRSC |= (ULONGLONG) seq[i] << (i * 8);
1031189251Ssam	}
1032189251Ssam	if (alg == WPA_ALG_TKIP && key_len == 32) {
1033189251Ssam		os_memcpy(nkey->KeyMaterial, key, 16);
1034189251Ssam		os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
1035189251Ssam		os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
1036189251Ssam	} else {
1037189251Ssam		os_memcpy(nkey->KeyMaterial, key, key_len);
1038189251Ssam	}
1039189251Ssam
1040189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_KEY",
1041189251Ssam			(u8 *) nkey, len);
1042189251Ssam	res = ndis_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
1043189251Ssam	os_free(nkey);
1044189251Ssam
1045189251Ssam	return res;
1046189251Ssam}
1047189251Ssam
1048189251Ssam
1049189251Ssamstatic int
1050189251Ssamwpa_driver_ndis_associate(void *priv,
1051189251Ssam			  struct wpa_driver_associate_params *params)
1052189251Ssam{
1053189251Ssam	struct wpa_driver_ndis_data *drv = priv;
1054189251Ssam	u32 auth_mode, encr, priv_mode, mode;
1055252726Srpaulo	u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1056189251Ssam
1057189251Ssam	drv->mode = params->mode;
1058189251Ssam
1059189251Ssam	/* Note: Setting OID_802_11_INFRASTRUCTURE_MODE clears current keys,
1060189251Ssam	 * so static WEP keys needs to be set again after this. */
1061189251Ssam	if (params->mode == IEEE80211_MODE_IBSS) {
1062189251Ssam		mode = Ndis802_11IBSS;
1063189251Ssam		/* Need to make sure that BSSID polling is enabled for
1064189251Ssam		 * IBSS mode. */
1065189251Ssam		eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
1066189251Ssam		eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout,
1067189251Ssam				       drv, NULL);
1068189251Ssam	} else
1069189251Ssam		mode = Ndis802_11Infrastructure;
1070189251Ssam	if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
1071189251Ssam			 (char *) &mode, sizeof(mode)) < 0) {
1072189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
1073189251Ssam			   "OID_802_11_INFRASTRUCTURE_MODE (%d)",
1074189251Ssam			   (int) mode);
1075189251Ssam		/* Try to continue anyway */
1076189251Ssam	}
1077189251Ssam
1078189251Ssam	if (params->key_mgmt_suite == KEY_MGMT_NONE ||
1079189251Ssam	    params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
1080189251Ssam		/* Re-set WEP keys if static WEP configuration is used. */
1081189251Ssam		int i;
1082189251Ssam		for (i = 0; i < 4; i++) {
1083189251Ssam			if (!params->wep_key[i])
1084189251Ssam				continue;
1085189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Re-setting static WEP "
1086189251Ssam				   "key %d", i);
1087214734Srpaulo			wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP,
1088214734Srpaulo						bcast, i,
1089189251Ssam						i == params->wep_tx_keyidx,
1090189251Ssam						NULL, 0, params->wep_key[i],
1091189251Ssam						params->wep_key_len[i]);
1092189251Ssam		}
1093189251Ssam	}
1094189251Ssam
1095189251Ssam	if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
1096214734Srpaulo		if (params->auth_alg & WPA_AUTH_ALG_SHARED) {
1097214734Srpaulo			if (params->auth_alg & WPA_AUTH_ALG_OPEN)
1098189251Ssam				auth_mode = Ndis802_11AuthModeAutoSwitch;
1099189251Ssam			else
1100189251Ssam				auth_mode = Ndis802_11AuthModeShared;
1101189251Ssam		} else
1102189251Ssam			auth_mode = Ndis802_11AuthModeOpen;
1103189251Ssam		priv_mode = Ndis802_11PrivFilterAcceptAll;
1104189251Ssam	} else if (params->wpa_ie[0] == WLAN_EID_RSN) {
1105189251Ssam		priv_mode = Ndis802_11PrivFilter8021xWEP;
1106189251Ssam		if (params->key_mgmt_suite == KEY_MGMT_PSK)
1107189251Ssam			auth_mode = Ndis802_11AuthModeWPA2PSK;
1108189251Ssam		else
1109189251Ssam			auth_mode = Ndis802_11AuthModeWPA2;
1110189251Ssam#ifdef CONFIG_WPS
1111189251Ssam	} else if (params->key_mgmt_suite == KEY_MGMT_WPS) {
1112189251Ssam		auth_mode = Ndis802_11AuthModeOpen;
1113189251Ssam		priv_mode = Ndis802_11PrivFilterAcceptAll;
1114252726Srpaulo		if (params->wps == WPS_MODE_PRIVACY) {
1115252726Srpaulo			u8 dummy_key[5] = { 0x11, 0x22, 0x33, 0x44, 0x55 };
1116252726Srpaulo			/*
1117252726Srpaulo			 * Some NDIS drivers refuse to associate in open mode
1118252726Srpaulo			 * configuration due to Privacy field mismatch, so use
1119252726Srpaulo			 * a workaround to make the configuration look like
1120252726Srpaulo			 * matching one for WPS provisioning.
1121252726Srpaulo			 */
1122252726Srpaulo			wpa_printf(MSG_DEBUG, "NDIS: Set dummy WEP key as a "
1123252726Srpaulo				   "workaround to allow driver to associate "
1124252726Srpaulo				   "for WPS");
1125252726Srpaulo			wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP,
1126252726Srpaulo						bcast, 0, 1,
1127252726Srpaulo						NULL, 0, dummy_key,
1128252726Srpaulo						sizeof(dummy_key));
1129252726Srpaulo		}
1130189251Ssam#endif /* CONFIG_WPS */
1131189251Ssam	} else {
1132189251Ssam		priv_mode = Ndis802_11PrivFilter8021xWEP;
1133189251Ssam		if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
1134189251Ssam			auth_mode = Ndis802_11AuthModeWPANone;
1135189251Ssam		else if (params->key_mgmt_suite == KEY_MGMT_PSK)
1136189251Ssam			auth_mode = Ndis802_11AuthModeWPAPSK;
1137189251Ssam		else
1138189251Ssam			auth_mode = Ndis802_11AuthModeWPA;
1139189251Ssam	}
1140189251Ssam
1141189251Ssam	switch (params->pairwise_suite) {
1142189251Ssam	case CIPHER_CCMP:
1143189251Ssam		encr = Ndis802_11Encryption3Enabled;
1144189251Ssam		break;
1145189251Ssam	case CIPHER_TKIP:
1146189251Ssam		encr = Ndis802_11Encryption2Enabled;
1147189251Ssam		break;
1148189251Ssam	case CIPHER_WEP40:
1149189251Ssam	case CIPHER_WEP104:
1150189251Ssam		encr = Ndis802_11Encryption1Enabled;
1151189251Ssam		break;
1152189251Ssam	case CIPHER_NONE:
1153252726Srpaulo#ifdef CONFIG_WPS
1154252726Srpaulo		if (params->wps == WPS_MODE_PRIVACY) {
1155252726Srpaulo			encr = Ndis802_11Encryption1Enabled;
1156252726Srpaulo			break;
1157252726Srpaulo		}
1158252726Srpaulo#endif /* CONFIG_WPS */
1159189251Ssam		if (params->group_suite == CIPHER_CCMP)
1160189251Ssam			encr = Ndis802_11Encryption3Enabled;
1161189251Ssam		else if (params->group_suite == CIPHER_TKIP)
1162189251Ssam			encr = Ndis802_11Encryption2Enabled;
1163189251Ssam		else
1164189251Ssam			encr = Ndis802_11EncryptionDisabled;
1165189251Ssam		break;
1166189251Ssam	default:
1167252726Srpaulo#ifdef CONFIG_WPS
1168252726Srpaulo		if (params->wps == WPS_MODE_PRIVACY) {
1169252726Srpaulo			encr = Ndis802_11Encryption1Enabled;
1170252726Srpaulo			break;
1171252726Srpaulo		}
1172252726Srpaulo#endif /* CONFIG_WPS */
1173189251Ssam		encr = Ndis802_11EncryptionDisabled;
1174252726Srpaulo		break;
1175189251Ssam	};
1176189251Ssam
1177189251Ssam	if (ndis_set_oid(drv, OID_802_11_PRIVACY_FILTER,
1178189251Ssam			 (char *) &priv_mode, sizeof(priv_mode)) < 0) {
1179189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
1180189251Ssam			   "OID_802_11_PRIVACY_FILTER (%d)",
1181189251Ssam			   (int) priv_mode);
1182189251Ssam		/* Try to continue anyway */
1183189251Ssam	}
1184189251Ssam
1185189251Ssam	ndis_set_auth_mode(drv, auth_mode);
1186189251Ssam	ndis_set_encr_status(drv, encr);
1187189251Ssam
1188189251Ssam	if (params->bssid) {
1189189251Ssam		ndis_set_oid(drv, OID_802_11_BSSID, (char *) params->bssid,
1190189251Ssam			     ETH_ALEN);
1191189251Ssam		drv->oid_bssid_set = 1;
1192189251Ssam	} else if (drv->oid_bssid_set) {
1193189251Ssam		ndis_set_oid(drv, OID_802_11_BSSID, "\xff\xff\xff\xff\xff\xff",
1194189251Ssam			     ETH_ALEN);
1195189251Ssam		drv->oid_bssid_set = 0;
1196189251Ssam	}
1197189251Ssam
1198189251Ssam	return wpa_driver_ndis_set_ssid(drv, params->ssid, params->ssid_len);
1199189251Ssam}
1200189251Ssam
1201189251Ssam
1202189251Ssamstatic int wpa_driver_ndis_set_pmkid(struct wpa_driver_ndis_data *drv)
1203189251Ssam{
1204189251Ssam	int len, count, i, ret;
1205189251Ssam	struct ndis_pmkid_entry *entry;
1206189251Ssam	NDIS_802_11_PMKID *p;
1207189251Ssam
1208189251Ssam	count = 0;
1209189251Ssam	entry = drv->pmkid;
1210189251Ssam	while (entry) {
1211189251Ssam		count++;
1212189251Ssam		if (count >= drv->no_of_pmkid)
1213189251Ssam			break;
1214189251Ssam		entry = entry->next;
1215189251Ssam	}
1216189251Ssam	len = 8 + count * sizeof(BSSID_INFO);
1217189251Ssam	p = os_zalloc(len);
1218189251Ssam	if (p == NULL)
1219189251Ssam		return -1;
1220189251Ssam
1221189251Ssam	p->Length = len;
1222189251Ssam	p->BSSIDInfoCount = count;
1223189251Ssam	entry = drv->pmkid;
1224189251Ssam	for (i = 0; i < count; i++) {
1225189251Ssam		os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
1226189251Ssam		os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
1227189251Ssam		entry = entry->next;
1228189251Ssam	}
1229189251Ssam	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", (u8 *) p, len);
1230189251Ssam	ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
1231189251Ssam	os_free(p);
1232189251Ssam	return ret;
1233189251Ssam}
1234189251Ssam
1235189251Ssam
1236189251Ssamstatic int wpa_driver_ndis_add_pmkid(void *priv, const u8 *bssid,
1237189251Ssam				     const u8 *pmkid)
1238189251Ssam{
1239189251Ssam	struct wpa_driver_ndis_data *drv = priv;
1240189251Ssam	struct ndis_pmkid_entry *entry, *prev;
1241189251Ssam
1242189251Ssam	if (drv->no_of_pmkid == 0)
1243189251Ssam		return 0;
1244189251Ssam
1245189251Ssam	prev = NULL;
1246189251Ssam	entry = drv->pmkid;
1247189251Ssam	while (entry) {
1248189251Ssam		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
1249189251Ssam			break;
1250189251Ssam		prev = entry;
1251189251Ssam		entry = entry->next;
1252189251Ssam	}
1253189251Ssam
1254189251Ssam	if (entry) {
1255189251Ssam		/* Replace existing entry for this BSSID and move it into the
1256189251Ssam		 * beginning of the list. */
1257189251Ssam		os_memcpy(entry->pmkid, pmkid, 16);
1258189251Ssam		if (prev) {
1259189251Ssam			prev->next = entry->next;
1260189251Ssam			entry->next = drv->pmkid;
1261189251Ssam			drv->pmkid = entry;
1262189251Ssam		}
1263189251Ssam	} else {
1264189251Ssam		entry = os_malloc(sizeof(*entry));
1265189251Ssam		if (entry) {
1266189251Ssam			os_memcpy(entry->bssid, bssid, ETH_ALEN);
1267189251Ssam			os_memcpy(entry->pmkid, pmkid, 16);
1268189251Ssam			entry->next = drv->pmkid;
1269189251Ssam			drv->pmkid = entry;
1270189251Ssam		}
1271189251Ssam	}
1272189251Ssam
1273189251Ssam	return wpa_driver_ndis_set_pmkid(drv);
1274189251Ssam}
1275189251Ssam
1276189251Ssam
1277189251Ssamstatic int wpa_driver_ndis_remove_pmkid(void *priv, const u8 *bssid,
1278189251Ssam		 			const u8 *pmkid)
1279189251Ssam{
1280189251Ssam	struct wpa_driver_ndis_data *drv = priv;
1281189251Ssam	struct ndis_pmkid_entry *entry, *prev;
1282189251Ssam
1283189251Ssam	if (drv->no_of_pmkid == 0)
1284189251Ssam		return 0;
1285189251Ssam
1286189251Ssam	entry = drv->pmkid;
1287189251Ssam	prev = NULL;
1288189251Ssam	while (entry) {
1289189251Ssam		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
1290189251Ssam		    os_memcmp(entry->pmkid, pmkid, 16) == 0) {
1291189251Ssam			if (prev)
1292189251Ssam				prev->next = entry->next;
1293189251Ssam			else
1294189251Ssam				drv->pmkid = entry->next;
1295189251Ssam			os_free(entry);
1296189251Ssam			break;
1297189251Ssam		}
1298189251Ssam		prev = entry;
1299189251Ssam		entry = entry->next;
1300189251Ssam	}
1301189251Ssam	return wpa_driver_ndis_set_pmkid(drv);
1302189251Ssam}
1303189251Ssam
1304189251Ssam
1305189251Ssamstatic int wpa_driver_ndis_flush_pmkid(void *priv)
1306189251Ssam{
1307189251Ssam	struct wpa_driver_ndis_data *drv = priv;
1308189251Ssam	NDIS_802_11_PMKID p;
1309189251Ssam	struct ndis_pmkid_entry *pmkid, *prev;
1310189251Ssam	int prev_authmode, ret;
1311189251Ssam
1312189251Ssam	if (drv->no_of_pmkid == 0)
1313189251Ssam		return 0;
1314189251Ssam
1315189251Ssam	pmkid = drv->pmkid;
1316189251Ssam	drv->pmkid = NULL;
1317189251Ssam	while (pmkid) {
1318189251Ssam		prev = pmkid;
1319189251Ssam		pmkid = pmkid->next;
1320189251Ssam		os_free(prev);
1321189251Ssam	}
1322189251Ssam
1323189251Ssam	/*
1324189251Ssam	 * Some drivers may refuse OID_802_11_PMKID if authMode is not set to
1325189251Ssam	 * WPA2, so change authMode temporarily, if needed.
1326189251Ssam	 */
1327189251Ssam	prev_authmode = ndis_get_auth_mode(drv);
1328189251Ssam	if (prev_authmode != Ndis802_11AuthModeWPA2)
1329189251Ssam		ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA2);
1330189251Ssam
1331189251Ssam	os_memset(&p, 0, sizeof(p));
1332189251Ssam	p.Length = 8;
1333189251Ssam	p.BSSIDInfoCount = 0;
1334189251Ssam	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
1335189251Ssam		    (u8 *) &p, 8);
1336189251Ssam	ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
1337189251Ssam
1338189251Ssam	if (prev_authmode != Ndis802_11AuthModeWPA2)
1339189251Ssam		ndis_set_auth_mode(drv, prev_authmode);
1340189251Ssam
1341189251Ssam	return ret;
1342189251Ssam}
1343189251Ssam
1344189251Ssam
1345189251Ssamstatic int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
1346189251Ssam{
1347189251Ssam	char buf[512], *pos;
1348189251Ssam	NDIS_802_11_ASSOCIATION_INFORMATION *ai;
1349189251Ssam	int len;
1350189251Ssam	union wpa_event_data data;
1351189251Ssam	NDIS_802_11_BSSID_LIST_EX *b;
1352189251Ssam	size_t blen, i;
1353189251Ssam
1354189251Ssam	len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, buf,
1355189251Ssam			   sizeof(buf));
1356189251Ssam	if (len < 0) {
1357189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: failed to get association "
1358189251Ssam			   "information");
1359189251Ssam		return -1;
1360189251Ssam	}
1361189251Ssam	if (len > sizeof(buf)) {
1362189251Ssam		/* Some drivers seem to be producing incorrect length for this
1363189251Ssam		 * data. Limit the length to the current buffer size to avoid
1364189251Ssam		 * crashing in hexdump. The data seems to be otherwise valid,
1365189251Ssam		 * so better try to use it. */
1366189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association "
1367189251Ssam			   "information length %d", len);
1368189251Ssam		len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION,
1369189251Ssam				   buf, sizeof(buf));
1370189251Ssam		if (len < -1) {
1371189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: re-reading association "
1372189251Ssam				   "information failed");
1373189251Ssam			return -1;
1374189251Ssam		}
1375189251Ssam		if (len > sizeof(buf)) {
1376189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association"
1377189251Ssam				   " information length %d (re-read)", len);
1378189251Ssam			len = sizeof(buf);
1379189251Ssam		}
1380189251Ssam	}
1381189251Ssam	wpa_hexdump(MSG_MSGDUMP, "NDIS: association information",
1382189251Ssam		    (u8 *) buf, len);
1383189251Ssam	if (len < sizeof(*ai)) {
1384189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: too short association "
1385189251Ssam			   "information");
1386189251Ssam		return -1;
1387189251Ssam	}
1388189251Ssam	ai = (NDIS_802_11_ASSOCIATION_INFORMATION *) buf;
1389189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: ReqFixed=0x%x RespFixed=0x%x off_req=%d "
1390189251Ssam		   "off_resp=%d len_req=%d len_resp=%d",
1391189251Ssam		   ai->AvailableRequestFixedIEs, ai->AvailableResponseFixedIEs,
1392189251Ssam		   (int) ai->OffsetRequestIEs, (int) ai->OffsetResponseIEs,
1393189251Ssam		   (int) ai->RequestIELength, (int) ai->ResponseIELength);
1394189251Ssam
1395189251Ssam	if (ai->OffsetRequestIEs + ai->RequestIELength > (unsigned) len ||
1396189251Ssam	    ai->OffsetResponseIEs + ai->ResponseIELength > (unsigned) len) {
1397189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: association information - "
1398189251Ssam			   "IE overflow");
1399189251Ssam		return -1;
1400189251Ssam	}
1401189251Ssam
1402189251Ssam	wpa_hexdump(MSG_MSGDUMP, "NDIS: Request IEs",
1403189251Ssam		    (u8 *) buf + ai->OffsetRequestIEs, ai->RequestIELength);
1404189251Ssam	wpa_hexdump(MSG_MSGDUMP, "NDIS: Response IEs",
1405189251Ssam		    (u8 *) buf + ai->OffsetResponseIEs, ai->ResponseIELength);
1406189251Ssam
1407189251Ssam	os_memset(&data, 0, sizeof(data));
1408189251Ssam	data.assoc_info.req_ies = (u8 *) buf + ai->OffsetRequestIEs;
1409189251Ssam	data.assoc_info.req_ies_len = ai->RequestIELength;
1410189251Ssam	data.assoc_info.resp_ies = (u8 *) buf + ai->OffsetResponseIEs;
1411189251Ssam	data.assoc_info.resp_ies_len = ai->ResponseIELength;
1412189251Ssam
1413189251Ssam	blen = 65535;
1414189251Ssam	b = os_zalloc(blen);
1415189251Ssam	if (b == NULL)
1416189251Ssam		goto skip_scan_results;
1417189251Ssam	len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
1418189251Ssam	if (len < 0) {
1419189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
1420189251Ssam		os_free(b);
1421189251Ssam		b = NULL;
1422189251Ssam		goto skip_scan_results;
1423189251Ssam	}
1424189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: %d BSSID items to process for AssocInfo",
1425189251Ssam		   (unsigned int) b->NumberOfItems);
1426189251Ssam
1427189251Ssam	pos = (char *) &b->Bssid[0];
1428189251Ssam	for (i = 0; i < b->NumberOfItems; i++) {
1429189251Ssam		NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
1430189251Ssam		if (os_memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 &&
1431189251Ssam		    bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) {
1432189251Ssam			data.assoc_info.beacon_ies =
1433189251Ssam				((u8 *) bss->IEs) +
1434189251Ssam				sizeof(NDIS_802_11_FIXED_IEs);
1435189251Ssam			data.assoc_info.beacon_ies_len =
1436189251Ssam				bss->IELength - sizeof(NDIS_802_11_FIXED_IEs);
1437189251Ssam			wpa_hexdump(MSG_MSGDUMP, "NDIS: Beacon IEs",
1438189251Ssam				    data.assoc_info.beacon_ies,
1439189251Ssam				    data.assoc_info.beacon_ies_len);
1440189251Ssam			break;
1441189251Ssam		}
1442189251Ssam		pos += bss->Length;
1443189251Ssam		if (pos > (char *) b + blen)
1444189251Ssam			break;
1445189251Ssam	}
1446189251Ssam
1447189251Ssamskip_scan_results:
1448189251Ssam	wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
1449189251Ssam
1450189251Ssam	os_free(b);
1451189251Ssam
1452189251Ssam	return 0;
1453189251Ssam}
1454189251Ssam
1455189251Ssam
1456189251Ssamstatic void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx)
1457189251Ssam{
1458189251Ssam	struct wpa_driver_ndis_data *drv = eloop_ctx;
1459189251Ssam	u8 bssid[ETH_ALEN];
1460189251Ssam	int poll;
1461189251Ssam
1462189251Ssam	if (drv->wired)
1463189251Ssam		return;
1464189251Ssam
1465189251Ssam	if (wpa_driver_ndis_get_bssid(drv, bssid)) {
1466189251Ssam		/* Disconnected */
1467189251Ssam		if (!is_zero_ether_addr(drv->bssid)) {
1468189251Ssam			os_memset(drv->bssid, 0, ETH_ALEN);
1469189251Ssam			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
1470189251Ssam		}
1471189251Ssam	} else {
1472189251Ssam		/* Connected */
1473189251Ssam		if (os_memcmp(drv->bssid, bssid, ETH_ALEN) != 0) {
1474189251Ssam			os_memcpy(drv->bssid, bssid, ETH_ALEN);
1475189251Ssam			wpa_driver_ndis_get_associnfo(drv);
1476189251Ssam			wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
1477189251Ssam		}
1478189251Ssam	}
1479189251Ssam
1480189251Ssam	/* When using integrated NDIS event receiver, we can skip BSSID
1481189251Ssam	 * polling when using infrastructure network. However, when using
1482189251Ssam	 * IBSS mode, many driver do not seem to generate connection event,
1483189251Ssam	 * so we need to enable BSSID polling to figure out when IBSS network
1484189251Ssam	 * has been formed.
1485189251Ssam	 */
1486189251Ssam	poll = drv->mode == IEEE80211_MODE_IBSS;
1487189251Ssam#ifndef CONFIG_NDIS_EVENTS_INTEGRATED
1488189251Ssam#ifndef _WIN32_WCE
1489189251Ssam	poll = 1;
1490189251Ssam#endif /* _WIN32_WCE */
1491189251Ssam#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
1492189251Ssam
1493189251Ssam	if (poll) {
1494189251Ssam		eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout,
1495189251Ssam					drv, NULL);
1496189251Ssam	}
1497189251Ssam}
1498189251Ssam
1499189251Ssam
1500189251Ssamstatic void wpa_driver_ndis_poll(void *priv)
1501189251Ssam{
1502189251Ssam	struct wpa_driver_ndis_data *drv = priv;
1503189251Ssam	eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
1504189251Ssam	wpa_driver_ndis_poll_timeout(drv, NULL);
1505189251Ssam}
1506189251Ssam
1507189251Ssam
1508189251Ssam/* Called when driver generates Media Connect Event by calling
1509189251Ssam * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_CONNECT */
1510189251Ssamvoid wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv)
1511189251Ssam{
1512189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Media Connect Event");
1513189251Ssam	if (wpa_driver_ndis_get_bssid(drv, drv->bssid) == 0) {
1514189251Ssam		wpa_driver_ndis_get_associnfo(drv);
1515189251Ssam		wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
1516189251Ssam	}
1517189251Ssam}
1518189251Ssam
1519189251Ssam
1520189251Ssam/* Called when driver generates Media Disconnect Event by calling
1521189251Ssam * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_DISCONNECT */
1522189251Ssamvoid wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv)
1523189251Ssam{
1524189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Media Disconnect Event");
1525189251Ssam	os_memset(drv->bssid, 0, ETH_ALEN);
1526189251Ssam	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
1527189251Ssam}
1528189251Ssam
1529189251Ssam
1530189251Ssamstatic void wpa_driver_ndis_event_auth(struct wpa_driver_ndis_data *drv,
1531189251Ssam				       const u8 *data, size_t data_len)
1532189251Ssam{
1533189251Ssam	NDIS_802_11_AUTHENTICATION_REQUEST *req;
1534189251Ssam	int pairwise = 0, group = 0;
1535189251Ssam	union wpa_event_data event;
1536189251Ssam
1537189251Ssam	if (data_len < sizeof(*req)) {
1538189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Too short Authentication Request "
1539189251Ssam			   "Event (len=%d)", data_len);
1540189251Ssam		return;
1541189251Ssam	}
1542189251Ssam	req = (NDIS_802_11_AUTHENTICATION_REQUEST *) data;
1543189251Ssam
1544189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Authentication Request Event: "
1545189251Ssam		   "Bssid " MACSTR " Flags 0x%x",
1546189251Ssam		   MAC2STR(req->Bssid), (int) req->Flags);
1547189251Ssam
1548189251Ssam	if ((req->Flags & NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR) ==
1549189251Ssam	    NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR)
1550189251Ssam		pairwise = 1;
1551189251Ssam	else if ((req->Flags & NDIS_802_11_AUTH_REQUEST_GROUP_ERROR) ==
1552189251Ssam	    NDIS_802_11_AUTH_REQUEST_GROUP_ERROR)
1553189251Ssam		group = 1;
1554189251Ssam
1555189251Ssam	if (pairwise || group) {
1556189251Ssam		os_memset(&event, 0, sizeof(event));
1557189251Ssam		event.michael_mic_failure.unicast = pairwise;
1558189251Ssam		wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE,
1559189251Ssam				     &event);
1560189251Ssam	}
1561189251Ssam}
1562189251Ssam
1563189251Ssam
1564189251Ssamstatic void wpa_driver_ndis_event_pmkid(struct wpa_driver_ndis_data *drv,
1565189251Ssam					const u8 *data, size_t data_len)
1566189251Ssam{
1567189251Ssam	NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
1568189251Ssam	size_t i;
1569189251Ssam	union wpa_event_data event;
1570189251Ssam
1571189251Ssam	if (data_len < 8) {
1572189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Too short PMKID Candidate List "
1573189251Ssam			   "Event (len=%d)", data_len);
1574189251Ssam		return;
1575189251Ssam	}
1576189251Ssam	pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
1577189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List Event - Version %d "
1578189251Ssam		   "NumCandidates %d",
1579189251Ssam		   (int) pmkid->Version, (int) pmkid->NumCandidates);
1580189251Ssam
1581189251Ssam	if (pmkid->Version != 1) {
1582189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Unsupported PMKID Candidate List "
1583189251Ssam			   "Version %d", (int) pmkid->Version);
1584189251Ssam		return;
1585189251Ssam	}
1586189251Ssam
1587189251Ssam	if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
1588189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List underflow");
1589189251Ssam		return;
1590189251Ssam	}
1591189251Ssam
1592189251Ssam	os_memset(&event, 0, sizeof(event));
1593189251Ssam	for (i = 0; i < pmkid->NumCandidates; i++) {
1594189251Ssam		PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
1595189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: %d: " MACSTR " Flags 0x%x",
1596189251Ssam			   i, MAC2STR(p->BSSID), (int) p->Flags);
1597189251Ssam		os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
1598189251Ssam		event.pmkid_candidate.index = i;
1599189251Ssam		event.pmkid_candidate.preauth =
1600189251Ssam			p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
1601189251Ssam		wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
1602189251Ssam				     &event);
1603189251Ssam	}
1604189251Ssam}
1605189251Ssam
1606189251Ssam
1607189251Ssam/* Called when driver calls NdisMIndicateStatus() with
1608189251Ssam * NDIS_STATUS_MEDIA_SPECIFIC_INDICATION */
1609189251Ssamvoid wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv,
1610189251Ssam					  const u8 *data, size_t data_len)
1611189251Ssam{
1612189251Ssam	NDIS_802_11_STATUS_INDICATION *status;
1613189251Ssam
1614189251Ssam	if (data == NULL || data_len < sizeof(*status))
1615189251Ssam		return;
1616189251Ssam
1617189251Ssam	wpa_hexdump(MSG_DEBUG, "NDIS: Media Specific Indication",
1618189251Ssam		    data, data_len);
1619189251Ssam
1620189251Ssam	status = (NDIS_802_11_STATUS_INDICATION *) data;
1621189251Ssam	data += sizeof(status);
1622189251Ssam	data_len -= sizeof(status);
1623189251Ssam
1624189251Ssam	switch (status->StatusType) {
1625189251Ssam	case Ndis802_11StatusType_Authentication:
1626189251Ssam		wpa_driver_ndis_event_auth(drv, data, data_len);
1627189251Ssam		break;
1628189251Ssam	case Ndis802_11StatusType_PMKID_CandidateList:
1629189251Ssam		wpa_driver_ndis_event_pmkid(drv, data, data_len);
1630189251Ssam		break;
1631189251Ssam	default:
1632189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Unknown StatusType %d",
1633189251Ssam			   (int) status->StatusType);
1634189251Ssam		break;
1635189251Ssam	}
1636189251Ssam}
1637189251Ssam
1638189251Ssam
1639189251Ssam/* Called when an adapter is added */
1640189251Ssamvoid wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv)
1641189251Ssam{
1642189251Ssam	union wpa_event_data event;
1643189251Ssam	int i;
1644189251Ssam
1645189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Arrival");
1646189251Ssam
1647189251Ssam	for (i = 0; i < 30; i++) {
1648189251Ssam		/* Re-open Packet32/NDISUIO connection */
1649189251Ssam		wpa_driver_ndis_adapter_close(drv);
1650189251Ssam		if (wpa_driver_ndis_adapter_init(drv) < 0 ||
1651189251Ssam		    wpa_driver_ndis_adapter_open(drv) < 0) {
1652189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialization "
1653189251Ssam				   "(%d) failed", i);
1654189251Ssam			os_sleep(1, 0);
1655189251Ssam		} else {
1656189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialized");
1657189251Ssam			break;
1658189251Ssam		}
1659189251Ssam	}
1660189251Ssam
1661189251Ssam	os_memset(&event, 0, sizeof(event));
1662189251Ssam	os_strlcpy(event.interface_status.ifname, drv->ifname,
1663189251Ssam		   sizeof(event.interface_status.ifname));
1664189251Ssam	event.interface_status.ievent = EVENT_INTERFACE_ADDED;
1665189251Ssam	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1666189251Ssam}
1667189251Ssam
1668189251Ssam
1669189251Ssam/* Called when an adapter is removed */
1670189251Ssamvoid wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv)
1671189251Ssam{
1672189251Ssam	union wpa_event_data event;
1673189251Ssam
1674189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Removal");
1675189251Ssam	os_memset(&event, 0, sizeof(event));
1676189251Ssam	os_strlcpy(event.interface_status.ifname, drv->ifname,
1677189251Ssam		   sizeof(event.interface_status.ifname));
1678189251Ssam	event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
1679189251Ssam	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1680189251Ssam}
1681189251Ssam
1682189251Ssam
1683189251Ssamstatic void
1684189251Ssamwpa_driver_ndis_get_wpa_capability(struct wpa_driver_ndis_data *drv)
1685189251Ssam{
1686189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: verifying driver WPA capability");
1687189251Ssam
1688189251Ssam	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA) == 0 &&
1689189251Ssam	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPA) {
1690189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: WPA key management supported");
1691189251Ssam		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA;
1692189251Ssam	}
1693189251Ssam
1694189251Ssam	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPAPSK) == 0 &&
1695189251Ssam	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPAPSK) {
1696189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: WPA-PSK key management "
1697189251Ssam			   "supported");
1698189251Ssam		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
1699189251Ssam	}
1700189251Ssam
1701189251Ssam	if (ndis_set_encr_status(drv, Ndis802_11Encryption3Enabled) == 0 &&
1702189251Ssam	    ndis_get_encr_status(drv) == Ndis802_11Encryption3KeyAbsent) {
1703189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: CCMP encryption supported");
1704189251Ssam		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
1705189251Ssam	}
1706189251Ssam
1707189251Ssam	if (ndis_set_encr_status(drv, Ndis802_11Encryption2Enabled) == 0 &&
1708189251Ssam	    ndis_get_encr_status(drv) == Ndis802_11Encryption2KeyAbsent) {
1709189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: TKIP encryption supported");
1710189251Ssam		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
1711189251Ssam	}
1712189251Ssam
1713189251Ssam	if (ndis_set_encr_status(drv, Ndis802_11Encryption1Enabled) == 0 &&
1714189251Ssam	    ndis_get_encr_status(drv) == Ndis802_11Encryption1KeyAbsent) {
1715189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: WEP encryption supported");
1716189251Ssam		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
1717189251Ssam			WPA_DRIVER_CAPA_ENC_WEP104;
1718189251Ssam	}
1719189251Ssam
1720189251Ssam	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeShared) == 0 &&
1721189251Ssam	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeShared) {
1722189251Ssam		drv->capa.auth |= WPA_DRIVER_AUTH_SHARED;
1723189251Ssam	}
1724189251Ssam
1725189251Ssam	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeOpen) == 0 &&
1726189251Ssam	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeOpen) {
1727189251Ssam		drv->capa.auth |= WPA_DRIVER_AUTH_OPEN;
1728189251Ssam	}
1729189251Ssam
1730189251Ssam	ndis_set_encr_status(drv, Ndis802_11EncryptionDisabled);
1731189251Ssam
1732189251Ssam	/* Could also verify OID_802_11_ADD_KEY error reporting and
1733189251Ssam	 * support for OID_802_11_ASSOCIATION_INFORMATION. */
1734189251Ssam
1735189251Ssam	if (drv->capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA &&
1736189251Ssam	    drv->capa.enc & (WPA_DRIVER_CAPA_ENC_TKIP |
1737189251Ssam			     WPA_DRIVER_CAPA_ENC_CCMP)) {
1738189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: driver supports WPA");
1739189251Ssam		drv->has_capability = 1;
1740189251Ssam	} else {
1741189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: no WPA support found");
1742189251Ssam	}
1743189251Ssam
1744189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x "
1745189251Ssam		   "enc 0x%x auth 0x%x",
1746189251Ssam		   drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth);
1747189251Ssam}
1748189251Ssam
1749189251Ssam
1750189251Ssamstatic void wpa_driver_ndis_get_capability(struct wpa_driver_ndis_data *drv)
1751189251Ssam{
1752189251Ssam	char buf[512];
1753189251Ssam	int len;
1754189251Ssam	size_t i;
1755189251Ssam	NDIS_802_11_CAPABILITY *c;
1756189251Ssam
1757189251Ssam	drv->capa.flags = WPA_DRIVER_FLAGS_DRIVER_IE;
1758189251Ssam
1759189251Ssam	len = ndis_get_oid(drv, OID_802_11_CAPABILITY, buf, sizeof(buf));
1760189251Ssam	if (len < 0) {
1761189251Ssam		wpa_driver_ndis_get_wpa_capability(drv);
1762189251Ssam		return;
1763189251Ssam	}
1764189251Ssam
1765189251Ssam	wpa_hexdump(MSG_MSGDUMP, "OID_802_11_CAPABILITY", (u8 *) buf, len);
1766189251Ssam	c = (NDIS_802_11_CAPABILITY *) buf;
1767189251Ssam	if (len < sizeof(*c) || c->Version != 2) {
1768189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: unsupported "
1769189251Ssam			   "OID_802_11_CAPABILITY data");
1770189251Ssam		return;
1771189251Ssam	}
1772189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Driver supports OID_802_11_CAPABILITY - "
1773189251Ssam		   "NoOfPMKIDs %d NoOfAuthEncrPairs %d",
1774189251Ssam		   (int) c->NoOfPMKIDs,
1775189251Ssam		   (int) c->NoOfAuthEncryptPairsSupported);
1776189251Ssam	drv->has_capability = 1;
1777189251Ssam	drv->no_of_pmkid = c->NoOfPMKIDs;
1778189251Ssam	for (i = 0; i < c->NoOfAuthEncryptPairsSupported; i++) {
1779189251Ssam		NDIS_802_11_AUTHENTICATION_ENCRYPTION *ae;
1780189251Ssam		ae = &c->AuthenticationEncryptionSupported[i];
1781189251Ssam		if ((char *) (ae + 1) > buf + len) {
1782189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: auth/encr pair list "
1783189251Ssam				   "overflow");
1784189251Ssam			break;
1785189251Ssam		}
1786189251Ssam		wpa_printf(MSG_MSGDUMP, "NDIS: %d - auth %d encr %d",
1787189251Ssam			   i, (int) ae->AuthModeSupported,
1788189251Ssam			   (int) ae->EncryptStatusSupported);
1789189251Ssam		switch (ae->AuthModeSupported) {
1790189251Ssam		case Ndis802_11AuthModeOpen:
1791189251Ssam			drv->capa.auth |= WPA_DRIVER_AUTH_OPEN;
1792189251Ssam			break;
1793189251Ssam		case Ndis802_11AuthModeShared:
1794189251Ssam			drv->capa.auth |= WPA_DRIVER_AUTH_SHARED;
1795189251Ssam			break;
1796189251Ssam		case Ndis802_11AuthModeWPA:
1797189251Ssam			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA;
1798189251Ssam			break;
1799189251Ssam		case Ndis802_11AuthModeWPAPSK:
1800189251Ssam			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
1801189251Ssam			break;
1802189251Ssam		case Ndis802_11AuthModeWPA2:
1803189251Ssam			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2;
1804189251Ssam			break;
1805189251Ssam		case Ndis802_11AuthModeWPA2PSK:
1806189251Ssam			drv->capa.key_mgmt |=
1807189251Ssam				WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
1808189251Ssam			break;
1809189251Ssam		case Ndis802_11AuthModeWPANone:
1810189251Ssam			drv->capa.key_mgmt |=
1811189251Ssam				WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE;
1812189251Ssam			break;
1813189251Ssam		default:
1814189251Ssam			break;
1815189251Ssam		}
1816189251Ssam		switch (ae->EncryptStatusSupported) {
1817189251Ssam		case Ndis802_11Encryption1Enabled:
1818189251Ssam			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40;
1819189251Ssam			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP104;
1820189251Ssam			break;
1821189251Ssam		case Ndis802_11Encryption2Enabled:
1822189251Ssam			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
1823189251Ssam			break;
1824189251Ssam		case Ndis802_11Encryption3Enabled:
1825189251Ssam			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
1826189251Ssam			break;
1827189251Ssam		default:
1828189251Ssam			break;
1829189251Ssam		}
1830189251Ssam	}
1831189251Ssam
1832189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x "
1833189251Ssam		   "enc 0x%x auth 0x%x",
1834189251Ssam		   drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth);
1835189251Ssam}
1836189251Ssam
1837189251Ssam
1838189251Ssamstatic int wpa_driver_ndis_get_capa(void *priv, struct wpa_driver_capa *capa)
1839189251Ssam{
1840189251Ssam	struct wpa_driver_ndis_data *drv = priv;
1841189251Ssam	if (!drv->has_capability)
1842189251Ssam		return -1;
1843189251Ssam	os_memcpy(capa, &drv->capa, sizeof(*capa));
1844189251Ssam	return 0;
1845189251Ssam}
1846189251Ssam
1847189251Ssam
1848189251Ssamstatic const char * wpa_driver_ndis_get_ifname(void *priv)
1849189251Ssam{
1850189251Ssam	struct wpa_driver_ndis_data *drv = priv;
1851189251Ssam	return drv->ifname;
1852189251Ssam}
1853189251Ssam
1854189251Ssam
1855189251Ssamstatic const u8 * wpa_driver_ndis_get_mac_addr(void *priv)
1856189251Ssam{
1857189251Ssam	struct wpa_driver_ndis_data *drv = priv;
1858189251Ssam	return drv->own_addr;
1859189251Ssam}
1860189251Ssam
1861189251Ssam
1862189251Ssam#ifdef _WIN32_WCE
1863189251Ssam
1864189251Ssam#define NDISUIO_MSG_SIZE (sizeof(NDISUIO_DEVICE_NOTIFICATION) + 512)
1865189251Ssam
1866189251Ssamstatic void ndisuio_notification_receive(void *eloop_data, void *user_ctx)
1867189251Ssam{
1868189251Ssam	struct wpa_driver_ndis_data *drv = eloop_data;
1869189251Ssam	NDISUIO_DEVICE_NOTIFICATION *hdr;
1870189251Ssam	u8 buf[NDISUIO_MSG_SIZE];
1871189251Ssam	DWORD len, flags;
1872189251Ssam
1873189251Ssam	if (!ReadMsgQueue(drv->event_queue, buf, NDISUIO_MSG_SIZE, &len, 0,
1874189251Ssam			  &flags)) {
1875189251Ssam		wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: "
1876189251Ssam			   "ReadMsgQueue failed: %d", (int) GetLastError());
1877189251Ssam		return;
1878189251Ssam	}
1879189251Ssam
1880189251Ssam	if (len < sizeof(NDISUIO_DEVICE_NOTIFICATION)) {
1881189251Ssam		wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: "
1882189251Ssam			   "Too short message (len=%d)", (int) len);
1883189251Ssam		return;
1884189251Ssam	}
1885189251Ssam
1886189251Ssam	hdr = (NDISUIO_DEVICE_NOTIFICATION *) buf;
1887189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Notification received: len=%d type=0x%x",
1888189251Ssam		   (int) len, hdr->dwNotificationType);
1889189251Ssam
1890189251Ssam	switch (hdr->dwNotificationType) {
1891189251Ssam#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL
1892189251Ssam	case NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL:
1893189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_ARRIVAL");
1894189251Ssam		wpa_driver_ndis_event_adapter_arrival(drv);
1895189251Ssam		break;
1896189251Ssam#endif
1897189251Ssam#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL
1898189251Ssam	case NDISUIO_NOTIFICATION_ADAPTER_REMOVAL:
1899189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_REMOVAL");
1900189251Ssam		wpa_driver_ndis_event_adapter_removal(drv);
1901189251Ssam		break;
1902189251Ssam#endif
1903189251Ssam	case NDISUIO_NOTIFICATION_MEDIA_CONNECT:
1904189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: MEDIA_CONNECT");
1905189251Ssam		SetEvent(drv->connected_event);
1906189251Ssam		wpa_driver_ndis_event_connect(drv);
1907189251Ssam		break;
1908189251Ssam	case NDISUIO_NOTIFICATION_MEDIA_DISCONNECT:
1909189251Ssam		ResetEvent(drv->connected_event);
1910189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: MEDIA_DISCONNECT");
1911189251Ssam		wpa_driver_ndis_event_disconnect(drv);
1912189251Ssam		break;
1913189251Ssam	case NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION:
1914189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: MEDIA_SPECIFIC_NOTIFICATION");
1915189251Ssam#if _WIN32_WCE == 420 || _WIN32_WCE == 0x420
1916189251Ssam		wpa_driver_ndis_event_media_specific(
1917189251Ssam			drv, hdr->pvStatusBuffer, hdr->uiStatusBufferSize);
1918189251Ssam#else
1919189251Ssam		wpa_driver_ndis_event_media_specific(
1920189251Ssam			drv, ((const u8 *) hdr) + hdr->uiOffsetToStatusBuffer,
1921189251Ssam			(size_t) hdr->uiStatusBufferSize);
1922189251Ssam#endif
1923189251Ssam		break;
1924189251Ssam	default:
1925189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Unknown notification type 0x%x",
1926189251Ssam			   hdr->dwNotificationType);
1927189251Ssam		break;
1928189251Ssam	}
1929189251Ssam}
1930189251Ssam
1931189251Ssam
1932189251Ssamstatic void ndisuio_notification_deinit(struct wpa_driver_ndis_data *drv)
1933189251Ssam{
1934189251Ssam	NDISUIO_REQUEST_NOTIFICATION req;
1935189251Ssam
1936189251Ssam	memset(&req, 0, sizeof(req));
1937189251Ssam	req.hMsgQueue = drv->event_queue;
1938189251Ssam	req.dwNotificationTypes = 0;
1939189251Ssam
1940189251Ssam	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION,
1941189251Ssam			     &req, sizeof(req), NULL, 0, NULL, NULL)) {
1942189251Ssam		wpa_printf(MSG_INFO, "ndisuio_notification_deinit: "
1943189251Ssam			   "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d",
1944189251Ssam			   (int) GetLastError());
1945189251Ssam	}
1946189251Ssam
1947189251Ssam	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_CANCEL_NOTIFICATION,
1948189251Ssam			     NULL, 0, NULL, 0, NULL, NULL)) {
1949189251Ssam		wpa_printf(MSG_INFO, "ndisuio_notification_deinit: "
1950189251Ssam			   "IOCTL_NDISUIO_CANCEL_NOTIFICATION failed: %d",
1951189251Ssam			   (int) GetLastError());
1952189251Ssam	}
1953189251Ssam
1954189251Ssam	if (drv->event_queue) {
1955189251Ssam		eloop_unregister_event(drv->event_queue,
1956189251Ssam				       sizeof(drv->event_queue));
1957189251Ssam		CloseHandle(drv->event_queue);
1958189251Ssam		drv->event_queue = NULL;
1959189251Ssam	}
1960189251Ssam
1961189251Ssam	if (drv->connected_event) {
1962189251Ssam		CloseHandle(drv->connected_event);
1963189251Ssam		drv->connected_event = NULL;
1964189251Ssam	}
1965189251Ssam}
1966189251Ssam
1967189251Ssam
1968189251Ssamstatic int ndisuio_notification_init(struct wpa_driver_ndis_data *drv)
1969189251Ssam{
1970189251Ssam	MSGQUEUEOPTIONS opt;
1971189251Ssam	NDISUIO_REQUEST_NOTIFICATION req;
1972189251Ssam
1973189251Ssam	drv->connected_event =
1974189251Ssam		CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));
1975189251Ssam	if (drv->connected_event == NULL) {
1976189251Ssam		wpa_printf(MSG_INFO, "ndisuio_notification_init: "
1977189251Ssam			   "CreateEvent failed: %d",
1978189251Ssam			   (int) GetLastError());
1979189251Ssam		return -1;
1980189251Ssam	}
1981189251Ssam
1982189251Ssam	memset(&opt, 0, sizeof(opt));
1983189251Ssam	opt.dwSize = sizeof(opt);
1984189251Ssam	opt.dwMaxMessages = 5;
1985189251Ssam	opt.cbMaxMessage = NDISUIO_MSG_SIZE;
1986189251Ssam	opt.bReadAccess = TRUE;
1987189251Ssam
1988189251Ssam	drv->event_queue = CreateMsgQueue(NULL, &opt);
1989189251Ssam	if (drv->event_queue == NULL) {
1990189251Ssam		wpa_printf(MSG_INFO, "ndisuio_notification_init: "
1991189251Ssam			   "CreateMsgQueue failed: %d",
1992189251Ssam			   (int) GetLastError());
1993189251Ssam		ndisuio_notification_deinit(drv);
1994189251Ssam		return -1;
1995189251Ssam	}
1996189251Ssam
1997189251Ssam	memset(&req, 0, sizeof(req));
1998189251Ssam	req.hMsgQueue = drv->event_queue;
1999189251Ssam	req.dwNotificationTypes =
2000189251Ssam#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL
2001189251Ssam		NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL |
2002189251Ssam#endif
2003189251Ssam#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL
2004189251Ssam		NDISUIO_NOTIFICATION_ADAPTER_REMOVAL |
2005189251Ssam#endif
2006189251Ssam		NDISUIO_NOTIFICATION_MEDIA_CONNECT |
2007189251Ssam		NDISUIO_NOTIFICATION_MEDIA_DISCONNECT |
2008189251Ssam		NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION;
2009189251Ssam
2010189251Ssam	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION,
2011189251Ssam			     &req, sizeof(req), NULL, 0, NULL, NULL)) {
2012189251Ssam		wpa_printf(MSG_INFO, "ndisuio_notification_init: "
2013189251Ssam			   "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d",
2014189251Ssam			   (int) GetLastError());
2015189251Ssam		ndisuio_notification_deinit(drv);
2016189251Ssam		return -1;
2017189251Ssam	}
2018189251Ssam
2019189251Ssam	eloop_register_event(drv->event_queue, sizeof(drv->event_queue),
2020189251Ssam			     ndisuio_notification_receive, drv, NULL);
2021189251Ssam
2022189251Ssam	return 0;
2023189251Ssam}
2024189251Ssam#endif /* _WIN32_WCE */
2025189251Ssam
2026189251Ssam
2027189251Ssamstatic int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
2028189251Ssam{
2029189251Ssam#ifdef CONFIG_USE_NDISUIO
2030189251Ssam	NDISUIO_QUERY_BINDING *b;
2031189251Ssam	size_t blen = sizeof(*b) + 1024;
2032189251Ssam	int i, error, found = 0;
2033189251Ssam	DWORD written;
2034189251Ssam	char name[256], desc[256], *dpos;
2035189251Ssam	WCHAR *pos;
2036189251Ssam	size_t j, len, dlen;
2037189251Ssam
2038189251Ssam	b = os_malloc(blen);
2039189251Ssam	if (b == NULL)
2040189251Ssam		return -1;
2041189251Ssam
2042189251Ssam	for (i = 0; ; i++) {
2043189251Ssam		os_memset(b, 0, blen);
2044189251Ssam		b->BindingIndex = i;
2045189251Ssam		if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
2046189251Ssam				     b, sizeof(NDISUIO_QUERY_BINDING), b, blen,
2047189251Ssam				     &written, NULL)) {
2048189251Ssam			error = (int) GetLastError();
2049189251Ssam			if (error == ERROR_NO_MORE_ITEMS)
2050189251Ssam				break;
2051189251Ssam			wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING "
2052189251Ssam				   "failed: %d", error);
2053189251Ssam			break;
2054189251Ssam		}
2055189251Ssam
2056189251Ssam		pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
2057189251Ssam		len = b->DeviceNameLength;
2058189251Ssam		if (len >= sizeof(name))
2059189251Ssam			len = sizeof(name) - 1;
2060189251Ssam		for (j = 0; j < len; j++)
2061189251Ssam			name[j] = (char) pos[j];
2062189251Ssam		name[len] = '\0';
2063189251Ssam
2064189251Ssam		pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
2065189251Ssam		len = b->DeviceDescrLength;
2066189251Ssam		if (len >= sizeof(desc))
2067189251Ssam			len = sizeof(desc) - 1;
2068189251Ssam		for (j = 0; j < len; j++)
2069189251Ssam			desc[j] = (char) pos[j];
2070189251Ssam		desc[len] = '\0';
2071189251Ssam
2072189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc);
2073189251Ssam
2074189251Ssam		if (os_strstr(name, drv->ifname)) {
2075189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Interface name match");
2076189251Ssam			found = 1;
2077189251Ssam			break;
2078189251Ssam		}
2079189251Ssam
2080189251Ssam		if (os_strncmp(desc, drv->ifname, os_strlen(drv->ifname)) == 0)
2081189251Ssam		{
2082189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Interface description "
2083189251Ssam				   "match");
2084189251Ssam			found = 1;
2085189251Ssam			break;
2086189251Ssam		}
2087189251Ssam	}
2088189251Ssam
2089189251Ssam	if (!found) {
2090189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'",
2091189251Ssam			   drv->ifname);
2092189251Ssam		os_free(b);
2093189251Ssam		return -1;
2094189251Ssam	}
2095189251Ssam
2096189251Ssam	os_strlcpy(drv->ifname,
2097189251Ssam		   os_strncmp(name, "\\DEVICE\\", 8) == 0 ? name + 8 : name,
2098189251Ssam		   sizeof(drv->ifname));
2099189251Ssam#ifdef _WIN32_WCE
2100189251Ssam	drv->adapter_name = wpa_strdup_tchar(drv->ifname);
2101189251Ssam	if (drv->adapter_name == NULL) {
2102189251Ssam		wpa_printf(MSG_ERROR, "NDIS: Failed to allocate memory for "
2103189251Ssam			   "adapter name");
2104189251Ssam		os_free(b);
2105189251Ssam		return -1;
2106189251Ssam	}
2107189251Ssam#endif /* _WIN32_WCE */
2108189251Ssam
2109189251Ssam	dpos = os_strstr(desc, " - ");
2110189251Ssam	if (dpos)
2111189251Ssam		dlen = dpos - desc;
2112189251Ssam	else
2113189251Ssam		dlen = os_strlen(desc);
2114189251Ssam	drv->adapter_desc = os_malloc(dlen + 1);
2115189251Ssam	if (drv->adapter_desc) {
2116189251Ssam		os_memcpy(drv->adapter_desc, desc, dlen);
2117189251Ssam		drv->adapter_desc[dlen] = '\0';
2118189251Ssam	}
2119189251Ssam
2120189251Ssam	os_free(b);
2121189251Ssam
2122189251Ssam	if (drv->adapter_desc == NULL)
2123189251Ssam		return -1;
2124189251Ssam
2125189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'",
2126189251Ssam		   drv->adapter_desc);
2127189251Ssam
2128189251Ssam	return 0;
2129189251Ssam#else /* CONFIG_USE_NDISUIO */
2130189251Ssam	PTSTR _names;
2131189251Ssam	char *names, *pos, *pos2;
2132189251Ssam	ULONG len;
2133189251Ssam	BOOLEAN res;
2134189251Ssam#define MAX_ADAPTERS 32
2135189251Ssam	char *name[MAX_ADAPTERS];
2136189251Ssam	char *desc[MAX_ADAPTERS];
2137189251Ssam	int num_name, num_desc, i, found_name, found_desc;
2138189251Ssam	size_t dlen;
2139189251Ssam
2140189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
2141189251Ssam		   PacketGetVersion());
2142189251Ssam
2143189251Ssam	len = 8192;
2144189251Ssam	_names = os_zalloc(len);
2145189251Ssam	if (_names == NULL)
2146189251Ssam		return -1;
2147189251Ssam
2148189251Ssam	res = PacketGetAdapterNames(_names, &len);
2149189251Ssam	if (!res && len > 8192) {
2150189251Ssam		os_free(_names);
2151189251Ssam		_names = os_zalloc(len);
2152189251Ssam		if (_names == NULL)
2153189251Ssam			return -1;
2154189251Ssam		res = PacketGetAdapterNames(_names, &len);
2155189251Ssam	}
2156189251Ssam
2157189251Ssam	if (!res) {
2158189251Ssam		wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
2159189251Ssam			   "(PacketGetAdapterNames)");
2160189251Ssam		os_free(_names);
2161189251Ssam		return -1;
2162189251Ssam	}
2163189251Ssam
2164189251Ssam	names = (char *) _names;
2165189251Ssam	if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
2166189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
2167189251Ssam			   "UNICODE");
2168189251Ssam		/* Convert to ASCII */
2169189251Ssam		pos2 = pos = names;
2170189251Ssam		while (pos2 < names + len) {
2171189251Ssam			if (pos2[0] == '\0' && pos2[1] == '\0' &&
2172189251Ssam			    pos2[2] == '\0' && pos2[3] == '\0') {
2173189251Ssam				pos2 += 4;
2174189251Ssam				break;
2175189251Ssam			}
2176189251Ssam			*pos++ = pos2[0];
2177189251Ssam			pos2 += 2;
2178189251Ssam		}
2179189251Ssam		os_memcpy(pos + 2, names, pos - names);
2180189251Ssam		pos += 2;
2181189251Ssam	} else
2182189251Ssam		pos = names;
2183189251Ssam
2184189251Ssam	num_name = 0;
2185189251Ssam	while (pos < names + len) {
2186189251Ssam		name[num_name] = pos;
2187189251Ssam		while (*pos && pos < names + len)
2188189251Ssam			pos++;
2189189251Ssam		if (pos + 1 >= names + len) {
2190189251Ssam			os_free(names);
2191189251Ssam			return -1;
2192189251Ssam		}
2193189251Ssam		pos++;
2194189251Ssam		num_name++;
2195189251Ssam		if (num_name >= MAX_ADAPTERS) {
2196189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
2197189251Ssam			os_free(names);
2198189251Ssam			return -1;
2199189251Ssam		}
2200189251Ssam		if (*pos == '\0') {
2201189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found",
2202189251Ssam				   num_name);
2203189251Ssam			pos++;
2204189251Ssam			break;
2205189251Ssam		}
2206189251Ssam	}
2207189251Ssam
2208189251Ssam	num_desc = 0;
2209189251Ssam	while (pos < names + len) {
2210189251Ssam		desc[num_desc] = pos;
2211189251Ssam		while (*pos && pos < names + len)
2212189251Ssam			pos++;
2213189251Ssam		if (pos + 1 >= names + len) {
2214189251Ssam			os_free(names);
2215189251Ssam			return -1;
2216189251Ssam		}
2217189251Ssam		pos++;
2218189251Ssam		num_desc++;
2219189251Ssam		if (num_desc >= MAX_ADAPTERS) {
2220189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
2221189251Ssam				   "descriptions");
2222189251Ssam			os_free(names);
2223189251Ssam			return -1;
2224189251Ssam		}
2225189251Ssam		if (*pos == '\0') {
2226189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions "
2227189251Ssam				   "found", num_name);
2228189251Ssam			pos++;
2229189251Ssam			break;
2230189251Ssam		}
2231189251Ssam	}
2232189251Ssam
2233189251Ssam	/*
2234189251Ssam	 * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
2235189251Ssam	 * descriptions. Fill in dummy descriptors to work around this.
2236189251Ssam	 */
2237189251Ssam	while (num_desc < num_name)
2238189251Ssam		desc[num_desc++] = "dummy description";
2239189251Ssam
2240189251Ssam	if (num_name != num_desc) {
2241189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
2242189251Ssam			   "description counts (%d != %d)",
2243189251Ssam			   num_name, num_desc);
2244189251Ssam		os_free(names);
2245189251Ssam		return -1;
2246189251Ssam	}
2247189251Ssam
2248189251Ssam	found_name = found_desc = -1;
2249189251Ssam	for (i = 0; i < num_name; i++) {
2250189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s",
2251189251Ssam			   i, name[i], desc[i]);
2252189251Ssam		if (found_name == -1 && os_strstr(name[i], drv->ifname))
2253189251Ssam			found_name = i;
2254189251Ssam		if (found_desc == -1 &&
2255189251Ssam		    os_strncmp(desc[i], drv->ifname, os_strlen(drv->ifname)) ==
2256189251Ssam		    0)
2257189251Ssam			found_desc = i;
2258189251Ssam	}
2259189251Ssam
2260189251Ssam	if (found_name < 0 && found_desc >= 0) {
2261189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Matched interface '%s' based on "
2262189251Ssam			   "description '%s'",
2263189251Ssam			   name[found_desc], desc[found_desc]);
2264189251Ssam		found_name = found_desc;
2265189251Ssam		os_strlcpy(drv->ifname,
2266189251Ssam			   os_strncmp(name[found_desc], "\\Device\\NPF_", 12)
2267189251Ssam			   == 0 ? name[found_desc] + 12 : name[found_desc],
2268189251Ssam			   sizeof(drv->ifname));
2269189251Ssam	}
2270189251Ssam
2271189251Ssam	if (found_name < 0) {
2272189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'",
2273189251Ssam			   drv->ifname);
2274189251Ssam		os_free(names);
2275189251Ssam		return -1;
2276189251Ssam	}
2277189251Ssam
2278189251Ssam	i = found_name;
2279189251Ssam	pos = os_strrchr(desc[i], '(');
2280189251Ssam	if (pos) {
2281189251Ssam		dlen = pos - desc[i];
2282189251Ssam		pos--;
2283189251Ssam		if (pos > desc[i] && *pos == ' ')
2284189251Ssam			dlen--;
2285189251Ssam	} else {
2286189251Ssam		dlen = os_strlen(desc[i]);
2287189251Ssam	}
2288189251Ssam	drv->adapter_desc = os_malloc(dlen + 1);
2289189251Ssam	if (drv->adapter_desc) {
2290189251Ssam		os_memcpy(drv->adapter_desc, desc[i], dlen);
2291189251Ssam		drv->adapter_desc[dlen] = '\0';
2292189251Ssam	}
2293189251Ssam
2294189251Ssam	os_free(names);
2295189251Ssam
2296189251Ssam	if (drv->adapter_desc == NULL)
2297189251Ssam		return -1;
2298189251Ssam
2299189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'",
2300189251Ssam		   drv->adapter_desc);
2301189251Ssam
2302189251Ssam	return 0;
2303189251Ssam#endif /* CONFIG_USE_NDISUIO */
2304189251Ssam}
2305189251Ssam
2306189251Ssam
2307189251Ssam#if defined(CONFIG_NATIVE_WINDOWS) || defined(__CYGWIN__)
2308189251Ssam#ifndef _WIN32_WCE
2309189251Ssam/*
2310189251Ssam * These structures are undocumented for WinXP; only WinCE version is
2311189251Ssam * documented. These would be included wzcsapi.h if it were available. Some
2312189251Ssam * changes here have been needed to make the structures match with WinXP SP2.
2313189251Ssam * It is unclear whether these work with any other version.
2314189251Ssam */
2315189251Ssam
2316189251Ssamtypedef struct {
2317189251Ssam	LPWSTR wszGuid;
2318189251Ssam} INTF_KEY_ENTRY, *PINTF_KEY_ENTRY;
2319189251Ssam
2320189251Ssamtypedef struct {
2321189251Ssam	DWORD dwNumIntfs;
2322189251Ssam	PINTF_KEY_ENTRY pIntfs;
2323189251Ssam} INTFS_KEY_TABLE, *PINTFS_KEY_TABLE;
2324189251Ssam
2325189251Ssamtypedef struct {
2326189251Ssam	DWORD dwDataLen;
2327189251Ssam	LPBYTE pData;
2328189251Ssam} RAW_DATA, *PRAW_DATA;
2329189251Ssam
2330189251Ssamtypedef struct {
2331189251Ssam	LPWSTR wszGuid;
2332189251Ssam	LPWSTR wszDescr;
2333189251Ssam	ULONG ulMediaState;
2334189251Ssam	ULONG ulMediaType;
2335189251Ssam	ULONG ulPhysicalMediaType;
2336189251Ssam	INT nInfraMode;
2337189251Ssam	INT nAuthMode;
2338189251Ssam	INT nWepStatus;
2339189251Ssam#ifndef _WIN32_WCE
2340189251Ssam	u8 pad[2]; /* why is this needed? */
2341189251Ssam#endif /* _WIN32_WCE */
2342189251Ssam	DWORD dwCtlFlags;
2343189251Ssam	DWORD dwCapabilities; /* something added for WinXP SP2(?) */
2344189251Ssam	RAW_DATA rdSSID;
2345189251Ssam	RAW_DATA rdBSSID;
2346189251Ssam	RAW_DATA rdBSSIDList;
2347189251Ssam	RAW_DATA rdStSSIDList;
2348189251Ssam	RAW_DATA rdCtrlData;
2349189251Ssam#ifdef UNDER_CE
2350189251Ssam	BOOL bInitialized;
2351189251Ssam#endif
2352189251Ssam	DWORD nWPAMCastCipher;
2353189251Ssam	/* add some extra buffer for later additions since this interface is
2354189251Ssam	 * far from stable */
2355189251Ssam	u8 later_additions[100];
2356189251Ssam} INTF_ENTRY, *PINTF_ENTRY;
2357189251Ssam
2358189251Ssam#define INTF_ALL 0xffffffff
2359189251Ssam#define INTF_ALL_FLAGS 0x0000ffff
2360189251Ssam#define INTF_CTLFLAGS 0x00000010
2361189251Ssam#define INTFCTL_ENABLED 0x8000
2362189251Ssam#endif /* _WIN32_WCE */
2363189251Ssam
2364189251Ssam
2365189251Ssam#ifdef _WIN32_WCE
2366189251Ssamstatic int wpa_driver_ndis_rebind_adapter(struct wpa_driver_ndis_data *drv)
2367189251Ssam{
2368189251Ssam	HANDLE ndis;
2369189251Ssam	TCHAR multi[100];
2370189251Ssam	int len;
2371189251Ssam
2372189251Ssam	len = _tcslen(drv->adapter_name);
2373189251Ssam	if (len > 80)
2374189251Ssam		return -1;
2375189251Ssam
2376189251Ssam	ndis = CreateFile(DD_NDIS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
2377189251Ssam			  0, NULL, OPEN_EXISTING, 0, NULL);
2378189251Ssam	if (ndis == INVALID_HANDLE_VALUE) {
2379189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Failed to open file to NDIS "
2380189251Ssam			   "device: %d", (int) GetLastError());
2381189251Ssam		return -1;
2382189251Ssam	}
2383189251Ssam
2384189251Ssam	len++;
2385189251Ssam	memcpy(multi, drv->adapter_name, len * sizeof(TCHAR));
2386189251Ssam	memcpy(&multi[len], TEXT("NDISUIO\0"), 9 * sizeof(TCHAR));
2387189251Ssam	len += 9;
2388189251Ssam
2389189251Ssam	if (!DeviceIoControl(ndis, IOCTL_NDIS_REBIND_ADAPTER,
2390189251Ssam			     multi, len * sizeof(TCHAR), NULL, 0, NULL, NULL))
2391189251Ssam	{
2392189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDIS_REBIND_ADAPTER "
2393189251Ssam			   "failed: 0x%x", (int) GetLastError());
2394189251Ssam		wpa_hexdump_ascii(MSG_DEBUG, "NDIS: rebind multi_sz",
2395189251Ssam				  (u8 *) multi, len * sizeof(TCHAR));
2396189251Ssam		CloseHandle(ndis);
2397189251Ssam		return -1;
2398189251Ssam	}
2399189251Ssam
2400189251Ssam	CloseHandle(ndis);
2401189251Ssam
2402189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Requested NDIS rebind of NDISUIO "
2403189251Ssam		   "protocol");
2404189251Ssam
2405189251Ssam	return 0;
2406189251Ssam}
2407189251Ssam#endif /* _WIN32_WCE */
2408189251Ssam
2409189251Ssam
2410189251Ssamstatic int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv,
2411189251Ssam				   int enable)
2412189251Ssam{
2413189251Ssam#ifdef _WIN32_WCE
2414189251Ssam	HKEY hk, hk2;
2415189251Ssam	LONG ret;
2416189251Ssam	DWORD i, hnd, len;
2417189251Ssam	TCHAR keyname[256], devname[256];
2418189251Ssam
2419189251Ssam#define WZC_DRIVER TEXT("Drivers\\BuiltIn\\ZeroConfig")
2420189251Ssam
2421189251Ssam	if (enable) {
2422189251Ssam		HANDLE h;
2423189251Ssam		h = ActivateDeviceEx(WZC_DRIVER, NULL, 0, NULL);
2424189251Ssam		if (h == INVALID_HANDLE_VALUE || h == 0) {
2425189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Failed to re-enable WZC "
2426189251Ssam				   "- ActivateDeviceEx failed: %d",
2427189251Ssam				   (int) GetLastError());
2428189251Ssam			return -1;
2429189251Ssam		}
2430189251Ssam
2431189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: WZC re-enabled");
2432189251Ssam		return wpa_driver_ndis_rebind_adapter(drv);
2433189251Ssam	}
2434189251Ssam
2435189251Ssam	/*
2436189251Ssam	 * Unfortunately, just disabling the WZC for an interface is not enough
2437189251Ssam	 * to free NDISUIO for us, so need to disable and unload WZC completely
2438189251Ssam	 * for now when using WinCE with NDISUIO. In addition, must request
2439189251Ssam	 * NDISUIO protocol to be rebound to the adapter in order to free the
2440189251Ssam	 * NDISUIO binding that WZC hold before us.
2441189251Ssam	 */
2442189251Ssam
2443189251Ssam	/* Enumerate HKLM\Drivers\Active\* to find a handle to WZC. */
2444189251Ssam	ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, DEVLOAD_ACTIVE_KEY, 0, 0, &hk);
2445189251Ssam	if (ret != ERROR_SUCCESS) {
2446189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(DEVLOAD_ACTIVE_KEY) "
2447189251Ssam			   "failed: %d %d", (int) ret, (int) GetLastError());
2448189251Ssam		return -1;
2449189251Ssam	}
2450189251Ssam
2451189251Ssam	for (i = 0; ; i++) {
2452189251Ssam		len = sizeof(keyname);
2453189251Ssam		ret = RegEnumKeyEx(hk, i, keyname, &len, NULL, NULL, NULL,
2454189251Ssam				   NULL);
2455189251Ssam		if (ret != ERROR_SUCCESS) {
2456189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Could not find active "
2457189251Ssam				   "WZC - assuming it is not running.");
2458189251Ssam			RegCloseKey(hk);
2459189251Ssam			return -1;
2460189251Ssam		}
2461189251Ssam
2462189251Ssam		ret = RegOpenKeyEx(hk, keyname, 0, 0, &hk2);
2463189251Ssam		if (ret != ERROR_SUCCESS) {
2464189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(active dev) "
2465189251Ssam				   "failed: %d %d",
2466189251Ssam				   (int) ret, (int) GetLastError());
2467189251Ssam			continue;
2468189251Ssam		}
2469189251Ssam
2470189251Ssam		len = sizeof(devname);
2471189251Ssam		ret = RegQueryValueEx(hk2, DEVLOAD_DEVKEY_VALNAME, NULL, NULL,
2472189251Ssam				      (LPBYTE) devname, &len);
2473189251Ssam		if (ret != ERROR_SUCCESS) {
2474189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx("
2475189251Ssam				   "DEVKEY_VALNAME) failed: %d %d",
2476189251Ssam				   (int) ret, (int) GetLastError());
2477189251Ssam			RegCloseKey(hk2);
2478189251Ssam			continue;
2479189251Ssam		}
2480189251Ssam
2481189251Ssam		if (_tcscmp(devname, WZC_DRIVER) == 0)
2482189251Ssam			break;
2483189251Ssam
2484189251Ssam		RegCloseKey(hk2);
2485189251Ssam	}
2486189251Ssam
2487189251Ssam	RegCloseKey(hk);
2488189251Ssam
2489189251Ssam	/* Found WZC - get handle to it. */
2490189251Ssam	len = sizeof(hnd);
2491189251Ssam	ret = RegQueryValueEx(hk2, DEVLOAD_HANDLE_VALNAME, NULL, NULL,
2492189251Ssam			      (PUCHAR) &hnd, &len);
2493189251Ssam	if (ret != ERROR_SUCCESS) {
2494189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx(HANDLE_VALNAME) "
2495189251Ssam			   "failed: %d %d", (int) ret, (int) GetLastError());
2496189251Ssam		RegCloseKey(hk2);
2497189251Ssam		return -1;
2498189251Ssam	}
2499189251Ssam
2500189251Ssam	RegCloseKey(hk2);
2501189251Ssam
2502189251Ssam	/* Deactivate WZC */
2503189251Ssam	if (!DeactivateDevice((HANDLE) hnd)) {
2504189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: DeactivateDevice failed: %d",
2505189251Ssam			   (int) GetLastError());
2506189251Ssam		return -1;
2507189251Ssam	}
2508189251Ssam
2509189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily");
2510189251Ssam	drv->wzc_disabled = 1;
2511189251Ssam	return wpa_driver_ndis_rebind_adapter(drv);
2512189251Ssam
2513189251Ssam#else /* _WIN32_WCE */
2514189251Ssam
2515189251Ssam	HMODULE hm;
2516189251Ssam	DWORD (WINAPI *wzc_enum_interf)(LPWSTR pSrvAddr,
2517189251Ssam					PINTFS_KEY_TABLE pIntfs);
2518189251Ssam	DWORD (WINAPI *wzc_query_interf)(LPWSTR pSrvAddr, DWORD dwInFlags,
2519189251Ssam					 PINTF_ENTRY pIntf,
2520189251Ssam					 LPDWORD pdwOutFlags);
2521189251Ssam	DWORD (WINAPI *wzc_set_interf)(LPWSTR pSrvAddr, DWORD dwInFlags,
2522189251Ssam				       PINTF_ENTRY pIntf, LPDWORD pdwOutFlags);
2523189251Ssam	int ret = -1, j;
2524189251Ssam	DWORD res;
2525189251Ssam	INTFS_KEY_TABLE guids;
2526189251Ssam	INTF_ENTRY intf;
2527189251Ssam	char guid[128];
2528189251Ssam	WCHAR *pos;
2529189251Ssam	DWORD flags, i;
2530189251Ssam
2531189251Ssam	hm = LoadLibrary(TEXT("wzcsapi.dll"));
2532189251Ssam	if (hm == NULL) {
2533189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Failed to load wzcsapi.dll (%u) "
2534189251Ssam			   "- WZC probably not running",
2535189251Ssam			   (unsigned int) GetLastError());
2536189251Ssam		return -1;
2537189251Ssam	}
2538189251Ssam
2539189251Ssam#ifdef _WIN32_WCE
2540189251Ssam	wzc_enum_interf = (void *) GetProcAddressA(hm, "WZCEnumInterfaces");
2541189251Ssam	wzc_query_interf = (void *) GetProcAddressA(hm, "WZCQueryInterface");
2542189251Ssam	wzc_set_interf = (void *) GetProcAddressA(hm, "WZCSetInterface");
2543189251Ssam#else /* _WIN32_WCE */
2544189251Ssam	wzc_enum_interf = (void *) GetProcAddress(hm, "WZCEnumInterfaces");
2545189251Ssam	wzc_query_interf = (void *) GetProcAddress(hm, "WZCQueryInterface");
2546189251Ssam	wzc_set_interf = (void *) GetProcAddress(hm, "WZCSetInterface");
2547189251Ssam#endif /* _WIN32_WCE */
2548189251Ssam
2549189251Ssam	if (wzc_enum_interf == NULL || wzc_query_interf == NULL ||
2550189251Ssam	    wzc_set_interf == NULL) {
2551189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces, "
2552189251Ssam			   "WZCQueryInterface, or WZCSetInterface not found "
2553189251Ssam			   "in wzcsapi.dll");
2554189251Ssam		goto fail;
2555189251Ssam	}
2556189251Ssam
2557189251Ssam	os_memset(&guids, 0, sizeof(guids));
2558189251Ssam	res = wzc_enum_interf(NULL, &guids);
2559189251Ssam	if (res != 0) {
2560189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces failed: %d; "
2561189251Ssam			   "WZC service is apparently not running",
2562189251Ssam			   (int) res);
2563189251Ssam		goto fail;
2564189251Ssam	}
2565189251Ssam
2566189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces: %d interfaces",
2567189251Ssam		   (int) guids.dwNumIntfs);
2568189251Ssam
2569189251Ssam	for (i = 0; i < guids.dwNumIntfs; i++) {
2570189251Ssam		pos = guids.pIntfs[i].wszGuid;
2571189251Ssam		for (j = 0; j < sizeof(guid); j++) {
2572189251Ssam			guid[j] = (char) *pos;
2573189251Ssam			if (*pos == 0)
2574189251Ssam				break;
2575189251Ssam			pos++;
2576189251Ssam		}
2577189251Ssam		guid[sizeof(guid) - 1] = '\0';
2578189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: intfs %d GUID '%s'",
2579189251Ssam			   (int) i, guid);
2580189251Ssam		if (os_strstr(drv->ifname, guid) == NULL)
2581189251Ssam			continue;
2582189251Ssam
2583189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Current interface found from "
2584189251Ssam			   "WZC");
2585189251Ssam		break;
2586189251Ssam	}
2587189251Ssam
2588189251Ssam	if (i >= guids.dwNumIntfs) {
2589189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Current interface not found from "
2590189251Ssam			   "WZC");
2591189251Ssam		goto fail;
2592189251Ssam	}
2593189251Ssam
2594189251Ssam	os_memset(&intf, 0, sizeof(intf));
2595189251Ssam	intf.wszGuid = guids.pIntfs[i].wszGuid;
2596189251Ssam	/* Set flags to verify that the structure has not changed. */
2597189251Ssam	intf.dwCtlFlags = -1;
2598189251Ssam	flags = 0;
2599189251Ssam	res = wzc_query_interf(NULL, INTFCTL_ENABLED, &intf, &flags);
2600189251Ssam	if (res != 0) {
2601189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Could not query flags for the "
2602189251Ssam			   "WZC interface: %d (0x%x)",
2603189251Ssam			   (int) res, (int) res);
2604189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
2605189251Ssam			   (unsigned int) GetLastError());
2606189251Ssam		goto fail;
2607189251Ssam	}
2608189251Ssam
2609189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: WZC interface flags 0x%x dwCtlFlags 0x%x",
2610189251Ssam		   (int) flags, (int) intf.dwCtlFlags);
2611189251Ssam
2612189251Ssam	if (intf.dwCtlFlags == -1) {
2613189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Looks like wzcsapi has changed "
2614189251Ssam			   "again - could not disable WZC");
2615189251Ssam		wpa_hexdump(MSG_MSGDUMP, "NDIS: intf",
2616189251Ssam			    (u8 *) &intf, sizeof(intf));
2617189251Ssam		goto fail;
2618189251Ssam	}
2619189251Ssam
2620189251Ssam	if (enable) {
2621189251Ssam		if (!(intf.dwCtlFlags & INTFCTL_ENABLED)) {
2622189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Enabling WZC for this "
2623189251Ssam				   "interface");
2624189251Ssam			intf.dwCtlFlags |= INTFCTL_ENABLED;
2625189251Ssam			res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf,
2626189251Ssam					     &flags);
2627189251Ssam			if (res != 0) {
2628189251Ssam				wpa_printf(MSG_DEBUG, "NDIS: Failed to enable "
2629189251Ssam					   "WZC: %d (0x%x)",
2630189251Ssam					   (int) res, (int) res);
2631189251Ssam				wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
2632189251Ssam					   (unsigned int) GetLastError());
2633189251Ssam				goto fail;
2634189251Ssam			}
2635189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Re-enabled WZC for this "
2636189251Ssam				   "interface");
2637189251Ssam			drv->wzc_disabled = 0;
2638189251Ssam		}
2639189251Ssam	} else {
2640189251Ssam		if (intf.dwCtlFlags & INTFCTL_ENABLED) {
2641189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Disabling WZC for this "
2642189251Ssam				   "interface");
2643189251Ssam			intf.dwCtlFlags &= ~INTFCTL_ENABLED;
2644189251Ssam			res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf,
2645189251Ssam					     &flags);
2646189251Ssam			if (res != 0) {
2647189251Ssam				wpa_printf(MSG_DEBUG, "NDIS: Failed to "
2648189251Ssam					   "disable WZC: %d (0x%x)",
2649189251Ssam					   (int) res, (int) res);
2650189251Ssam				wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
2651189251Ssam					   (unsigned int) GetLastError());
2652189251Ssam				goto fail;
2653189251Ssam			}
2654189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily "
2655189251Ssam				   "for this interface");
2656189251Ssam			drv->wzc_disabled = 1;
2657189251Ssam		} else {
2658189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: WZC was not enabled for "
2659189251Ssam				   "this interface");
2660189251Ssam		}
2661189251Ssam	}
2662189251Ssam
2663189251Ssam	ret = 0;
2664189251Ssam
2665189251Ssamfail:
2666189251Ssam	FreeLibrary(hm);
2667189251Ssam
2668189251Ssam	return ret;
2669189251Ssam#endif /* _WIN32_WCE */
2670189251Ssam}
2671189251Ssam
2672189251Ssam#else /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */
2673189251Ssam
2674189251Ssamstatic int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv,
2675189251Ssam				   int enable)
2676189251Ssam{
2677189251Ssam	return 0;
2678189251Ssam}
2679189251Ssam
2680189251Ssam#endif /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */
2681189251Ssam
2682189251Ssam
2683189251Ssam#ifdef CONFIG_USE_NDISUIO
2684189251Ssam/*
2685189251Ssam * l2_packet_ndis.c is sharing the same handle to NDISUIO, so we must be able
2686189251Ssam * to export this handle. This is somewhat ugly, but there is no better
2687189251Ssam * mechanism available to pass data from driver interface to l2_packet wrapper.
2688189251Ssam */
2689189251Ssamstatic HANDLE driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE;
2690189251Ssam
2691189251SsamHANDLE driver_ndis_get_ndisuio_handle(void)
2692189251Ssam{
2693189251Ssam	return driver_ndis_ndisuio_handle;
2694189251Ssam}
2695189251Ssam#endif /* CONFIG_USE_NDISUIO */
2696189251Ssam
2697189251Ssam
2698189251Ssamstatic int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv)
2699189251Ssam{
2700189251Ssam#ifdef CONFIG_USE_NDISUIO
2701189251Ssam#ifndef _WIN32_WCE
2702189251Ssam#define NDISUIO_DEVICE_NAME TEXT("\\\\.\\\\Ndisuio")
2703189251Ssam	DWORD written;
2704189251Ssam#endif /* _WIN32_WCE */
2705189251Ssam	drv->ndisuio = CreateFile(NDISUIO_DEVICE_NAME,
2706189251Ssam				  GENERIC_READ | GENERIC_WRITE, 0, NULL,
2707189251Ssam				  OPEN_EXISTING,
2708189251Ssam				  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
2709189251Ssam				  INVALID_HANDLE_VALUE);
2710189251Ssam	if (drv->ndisuio == INVALID_HANDLE_VALUE) {
2711189251Ssam		wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to "
2712189251Ssam			   "NDISUIO: %d", (int) GetLastError());
2713189251Ssam		return -1;
2714189251Ssam	}
2715189251Ssam	driver_ndis_ndisuio_handle = drv->ndisuio;
2716189251Ssam
2717189251Ssam#ifndef _WIN32_WCE
2718189251Ssam	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0,
2719189251Ssam			     NULL, 0, &written, NULL)) {
2720189251Ssam		wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: "
2721189251Ssam			   "%d", (int) GetLastError());
2722189251Ssam		CloseHandle(drv->ndisuio);
2723189251Ssam		drv->ndisuio = INVALID_HANDLE_VALUE;
2724189251Ssam		return -1;
2725189251Ssam	}
2726189251Ssam#endif /* _WIN32_WCE */
2727189251Ssam
2728189251Ssam	return 0;
2729189251Ssam#else /* CONFIG_USE_NDISUIO */
2730189251Ssam	return 0;
2731189251Ssam#endif /* CONFIG_USE_NDISUIO */
2732189251Ssam}
2733189251Ssam
2734189251Ssam
2735189251Ssamstatic int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv)
2736189251Ssam{
2737189251Ssam#ifdef CONFIG_USE_NDISUIO
2738189251Ssam	DWORD written;
2739189251Ssam#define MAX_NDIS_DEVICE_NAME_LEN 256
2740189251Ssam	WCHAR ifname[MAX_NDIS_DEVICE_NAME_LEN];
2741189251Ssam	size_t len, i, pos;
2742189251Ssam	const char *prefix = "\\DEVICE\\";
2743189251Ssam
2744189251Ssam#ifdef _WIN32_WCE
2745189251Ssam	pos = 0;
2746189251Ssam#else /* _WIN32_WCE */
2747189251Ssam	pos = 8;
2748189251Ssam#endif /* _WIN32_WCE */
2749189251Ssam	len = pos + os_strlen(drv->ifname);
2750189251Ssam	if (len >= MAX_NDIS_DEVICE_NAME_LEN)
2751189251Ssam		return -1;
2752189251Ssam	for (i = 0; i < pos; i++)
2753189251Ssam		ifname[i] = (WCHAR) prefix[i];
2754189251Ssam	for (i = pos; i < len; i++)
2755189251Ssam		ifname[i] = (WCHAR) drv->ifname[i - pos];
2756189251Ssam	ifname[i] = L'\0';
2757189251Ssam
2758189251Ssam	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_OPEN_DEVICE,
2759189251Ssam			     ifname, len * sizeof(WCHAR), NULL, 0, &written,
2760189251Ssam			     NULL)) {
2761189251Ssam		wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_OPEN_DEVICE "
2762189251Ssam			   "failed: %d", (int) GetLastError());
2763189251Ssam		wpa_hexdump_ascii(MSG_DEBUG, "NDIS: ifname",
2764189251Ssam				  (const u8 *) ifname, len * sizeof(WCHAR));
2765189251Ssam		CloseHandle(drv->ndisuio);
2766189251Ssam		drv->ndisuio = INVALID_HANDLE_VALUE;
2767189251Ssam		return -1;
2768189251Ssam	}
2769189251Ssam
2770189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Opened NDISUIO device successfully");
2771189251Ssam
2772189251Ssam	return 0;
2773189251Ssam#else /* CONFIG_USE_NDISUIO */
2774189251Ssam	char ifname[128];
2775189251Ssam	os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", drv->ifname);
2776189251Ssam	drv->adapter = PacketOpenAdapter(ifname);
2777189251Ssam	if (drv->adapter == NULL) {
2778189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: PacketOpenAdapter failed for "
2779189251Ssam			   "'%s'", ifname);
2780189251Ssam		return -1;
2781189251Ssam	}
2782189251Ssam	return 0;
2783189251Ssam#endif /* CONFIG_USE_NDISUIO */
2784189251Ssam}
2785189251Ssam
2786189251Ssam
2787189251Ssamstatic void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv)
2788189251Ssam{
2789189251Ssam#ifdef CONFIG_USE_NDISUIO
2790189251Ssam	driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE;
2791189251Ssam	if (drv->ndisuio != INVALID_HANDLE_VALUE)
2792189251Ssam		CloseHandle(drv->ndisuio);
2793189251Ssam#else /* CONFIG_USE_NDISUIO */
2794189251Ssam	if (drv->adapter)
2795189251Ssam		PacketCloseAdapter(drv->adapter);
2796189251Ssam#endif /* CONFIG_USE_NDISUIO */
2797189251Ssam}
2798189251Ssam
2799189251Ssam
2800209158Srpaulostatic int ndis_add_multicast(struct wpa_driver_ndis_data *drv)
2801209158Srpaulo{
2802209158Srpaulo	if (ndis_set_oid(drv, OID_802_3_MULTICAST_LIST,
2803209158Srpaulo			 (const char *) pae_group_addr, ETH_ALEN) < 0) {
2804209158Srpaulo		wpa_printf(MSG_DEBUG, "NDIS: Failed to add PAE group address "
2805209158Srpaulo			   "to the multicast list");
2806209158Srpaulo		return -1;
2807209158Srpaulo	}
2808209158Srpaulo
2809209158Srpaulo	return 0;
2810209158Srpaulo}
2811209158Srpaulo
2812209158Srpaulo
2813189251Ssamstatic void * wpa_driver_ndis_init(void *ctx, const char *ifname)
2814189251Ssam{
2815189251Ssam	struct wpa_driver_ndis_data *drv;
2816189251Ssam	u32 mode;
2817189251Ssam
2818189251Ssam	drv = os_zalloc(sizeof(*drv));
2819189251Ssam	if (drv == NULL)
2820189251Ssam		return NULL;
2821189251Ssam	drv->ctx = ctx;
2822189251Ssam	/*
2823189251Ssam	 * Compatibility code to strip possible prefix from the GUID. Previous
2824189251Ssam	 * versions include \Device\NPF_ prefix for all names, but the internal
2825189251Ssam	 * interface name is now only the GUI. Both Packet32 and NDISUIO
2826189251Ssam	 * prefixes are supported.
2827189251Ssam	 */
2828189251Ssam	if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0)
2829189251Ssam		ifname += 12;
2830189251Ssam	else if (os_strncmp(ifname, "\\DEVICE\\", 8) == 0)
2831189251Ssam		ifname += 8;
2832189251Ssam	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
2833189251Ssam
2834189251Ssam	if (wpa_driver_ndis_adapter_init(drv) < 0) {
2835189251Ssam		os_free(drv);
2836189251Ssam		return NULL;
2837189251Ssam	}
2838189251Ssam
2839189251Ssam	if (wpa_driver_ndis_get_names(drv) < 0) {
2840189251Ssam		wpa_driver_ndis_adapter_close(drv);
2841189251Ssam		os_free(drv);
2842189251Ssam		return NULL;
2843189251Ssam	}
2844189251Ssam
2845189251Ssam	wpa_driver_ndis_set_wzc(drv, 0);
2846189251Ssam
2847189251Ssam	if (wpa_driver_ndis_adapter_open(drv) < 0) {
2848189251Ssam		wpa_driver_ndis_adapter_close(drv);
2849189251Ssam		os_free(drv);
2850189251Ssam		return NULL;
2851189251Ssam	}
2852189251Ssam
2853189251Ssam	if (ndis_get_oid(drv, OID_802_3_CURRENT_ADDRESS,
2854189251Ssam			 (char *) drv->own_addr, ETH_ALEN) < 0) {
2855189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Get OID_802_3_CURRENT_ADDRESS "
2856189251Ssam			   "failed");
2857189251Ssam		wpa_driver_ndis_adapter_close(drv);
2858189251Ssam		os_free(drv);
2859189251Ssam		return NULL;
2860189251Ssam	}
2861189251Ssam	wpa_driver_ndis_get_capability(drv);
2862189251Ssam
2863189251Ssam	/* Make sure that the driver does not have any obsolete PMKID entries.
2864189251Ssam	 */
2865189251Ssam	wpa_driver_ndis_flush_pmkid(drv);
2866189251Ssam
2867189251Ssam	/*
2868189251Ssam	 * Disconnect to make sure that driver re-associates if it was
2869189251Ssam	 * connected.
2870189251Ssam	 */
2871189251Ssam	wpa_driver_ndis_disconnect(drv);
2872189251Ssam
2873189251Ssam	eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, drv, NULL);
2874189251Ssam
2875189251Ssam#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
2876189251Ssam	drv->events = ndis_events_init(&drv->events_pipe, &drv->event_avail,
2877189251Ssam				       drv->ifname, drv->adapter_desc);
2878189251Ssam	if (drv->events == NULL) {
2879189251Ssam		wpa_driver_ndis_deinit(drv);
2880189251Ssam		return NULL;
2881189251Ssam	}
2882189251Ssam	eloop_register_event(drv->event_avail, sizeof(drv->event_avail),
2883189251Ssam			     wpa_driver_ndis_event_pipe_cb, drv, NULL);
2884189251Ssam#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
2885189251Ssam
2886189251Ssam#ifdef _WIN32_WCE
2887189251Ssam	if (ndisuio_notification_init(drv) < 0) {
2888189251Ssam		wpa_driver_ndis_deinit(drv);
2889189251Ssam		return NULL;
2890189251Ssam	}
2891189251Ssam#endif /* _WIN32_WCE */
2892189251Ssam
2893189251Ssam	/* Set mode here in case card was configured for ad-hoc mode
2894189251Ssam	 * previously. */
2895189251Ssam	mode = Ndis802_11Infrastructure;
2896189251Ssam	if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
2897189251Ssam			 (char *) &mode, sizeof(mode)) < 0) {
2898214734Srpaulo		char buf[8];
2899214734Srpaulo		int res;
2900189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
2901189251Ssam			   "OID_802_11_INFRASTRUCTURE_MODE (%d)",
2902189251Ssam			   (int) mode);
2903189251Ssam		/* Try to continue anyway */
2904189251Ssam
2905214734Srpaulo		res = ndis_get_oid(drv, OID_DOT11_CURRENT_OPERATION_MODE, buf,
2906214734Srpaulo				   sizeof(buf));
2907214734Srpaulo		if (res > 0) {
2908214734Srpaulo			wpa_printf(MSG_INFO, "NDIS: The driver seems to use "
2909214734Srpaulo				   "Native 802.11 OIDs. These are not yet "
2910214734Srpaulo				   "fully supported.");
2911214734Srpaulo			drv->native80211 = 1;
2912214734Srpaulo		} else if (!drv->has_capability || drv->capa.enc == 0) {
2913214734Srpaulo			/*
2914214734Srpaulo			 * Note: This will also happen with NDIS 6 drivers with
2915214734Srpaulo			 * Vista.
2916214734Srpaulo			 */
2917189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Driver did not provide "
2918189251Ssam				   "any wireless capabilities - assume it is "
2919189251Ssam				   "a wired interface");
2920189251Ssam			drv->wired = 1;
2921214734Srpaulo			drv->capa.flags |= WPA_DRIVER_FLAGS_WIRED;
2922214734Srpaulo			drv->has_capability = 1;
2923209158Srpaulo			ndis_add_multicast(drv);
2924189251Ssam		}
2925189251Ssam	}
2926189251Ssam
2927189251Ssam	return drv;
2928189251Ssam}
2929189251Ssam
2930189251Ssam
2931189251Ssamstatic void wpa_driver_ndis_deinit(void *priv)
2932189251Ssam{
2933189251Ssam	struct wpa_driver_ndis_data *drv = priv;
2934189251Ssam
2935189251Ssam#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
2936189251Ssam	if (drv->events) {
2937189251Ssam		eloop_unregister_event(drv->event_avail,
2938189251Ssam				       sizeof(drv->event_avail));
2939189251Ssam		ndis_events_deinit(drv->events);
2940189251Ssam	}
2941189251Ssam#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
2942189251Ssam
2943189251Ssam#ifdef _WIN32_WCE
2944189251Ssam	ndisuio_notification_deinit(drv);
2945189251Ssam#endif /* _WIN32_WCE */
2946189251Ssam
2947189251Ssam	eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
2948189251Ssam	eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
2949189251Ssam	wpa_driver_ndis_flush_pmkid(drv);
2950189251Ssam	wpa_driver_ndis_disconnect(drv);
2951189251Ssam	if (wpa_driver_ndis_radio_off(drv) < 0) {
2952189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: failed to disassociate and turn "
2953189251Ssam			   "radio off");
2954189251Ssam	}
2955189251Ssam
2956189251Ssam	wpa_driver_ndis_adapter_close(drv);
2957189251Ssam
2958189251Ssam	if (drv->wzc_disabled)
2959189251Ssam		wpa_driver_ndis_set_wzc(drv, 1);
2960189251Ssam
2961189251Ssam#ifdef _WIN32_WCE
2962189251Ssam	os_free(drv->adapter_name);
2963189251Ssam#endif /* _WIN32_WCE */
2964189251Ssam	os_free(drv->adapter_desc);
2965189251Ssam	os_free(drv);
2966189251Ssam}
2967189251Ssam
2968189251Ssam
2969189251Ssamstatic struct wpa_interface_info *
2970189251Ssamwpa_driver_ndis_get_interfaces(void *global_priv)
2971189251Ssam{
2972189251Ssam	struct wpa_interface_info *iface = NULL, *niface;
2973189251Ssam
2974189251Ssam#ifdef CONFIG_USE_NDISUIO
2975189251Ssam	NDISUIO_QUERY_BINDING *b;
2976189251Ssam	size_t blen = sizeof(*b) + 1024;
2977189251Ssam	int i, error;
2978189251Ssam	DWORD written;
2979189251Ssam	char name[256], desc[256];
2980189251Ssam	WCHAR *pos;
2981189251Ssam	size_t j, len;
2982189251Ssam	HANDLE ndisuio;
2983189251Ssam
2984189251Ssam	ndisuio = CreateFile(NDISUIO_DEVICE_NAME,
2985189251Ssam			     GENERIC_READ | GENERIC_WRITE, 0, NULL,
2986189251Ssam			     OPEN_EXISTING,
2987189251Ssam			     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
2988189251Ssam			     INVALID_HANDLE_VALUE);
2989189251Ssam	if (ndisuio == INVALID_HANDLE_VALUE) {
2990189251Ssam		wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to "
2991189251Ssam			   "NDISUIO: %d", (int) GetLastError());
2992189251Ssam		return NULL;
2993189251Ssam	}
2994189251Ssam
2995189251Ssam#ifndef _WIN32_WCE
2996189251Ssam	if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0,
2997189251Ssam			     NULL, 0, &written, NULL)) {
2998189251Ssam		wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: "
2999189251Ssam			   "%d", (int) GetLastError());
3000189251Ssam		CloseHandle(ndisuio);
3001189251Ssam		return NULL;
3002189251Ssam	}
3003189251Ssam#endif /* _WIN32_WCE */
3004189251Ssam
3005189251Ssam	b = os_malloc(blen);
3006189251Ssam	if (b == NULL) {
3007189251Ssam		CloseHandle(ndisuio);
3008189251Ssam		return NULL;
3009189251Ssam	}
3010189251Ssam
3011189251Ssam	for (i = 0; ; i++) {
3012189251Ssam		os_memset(b, 0, blen);
3013189251Ssam		b->BindingIndex = i;
3014189251Ssam		if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
3015189251Ssam				     b, sizeof(NDISUIO_QUERY_BINDING), b, blen,
3016189251Ssam				     &written, NULL)) {
3017189251Ssam			error = (int) GetLastError();
3018189251Ssam			if (error == ERROR_NO_MORE_ITEMS)
3019189251Ssam				break;
3020189251Ssam			wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING "
3021189251Ssam				   "failed: %d", error);
3022189251Ssam			break;
3023189251Ssam		}
3024189251Ssam
3025189251Ssam		pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
3026189251Ssam		len = b->DeviceNameLength;
3027189251Ssam		if (len >= sizeof(name))
3028189251Ssam			len = sizeof(name) - 1;
3029189251Ssam		for (j = 0; j < len; j++)
3030189251Ssam			name[j] = (char) pos[j];
3031189251Ssam		name[len] = '\0';
3032189251Ssam
3033189251Ssam		pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
3034189251Ssam		len = b->DeviceDescrLength;
3035189251Ssam		if (len >= sizeof(desc))
3036189251Ssam			len = sizeof(desc) - 1;
3037189251Ssam		for (j = 0; j < len; j++)
3038189251Ssam			desc[j] = (char) pos[j];
3039189251Ssam		desc[len] = '\0';
3040189251Ssam
3041189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc);
3042189251Ssam
3043189251Ssam		niface = os_zalloc(sizeof(*niface));
3044189251Ssam		if (niface == NULL)
3045189251Ssam			break;
3046189251Ssam		niface->drv_name = "ndis";
3047189251Ssam		if (os_strncmp(name, "\\DEVICE\\", 8) == 0)
3048189251Ssam			niface->ifname = os_strdup(name + 8);
3049189251Ssam		else
3050189251Ssam			niface->ifname = os_strdup(name);
3051189251Ssam		if (niface->ifname == NULL) {
3052189251Ssam			os_free(niface);
3053189251Ssam			break;
3054189251Ssam		}
3055189251Ssam		niface->desc = os_strdup(desc);
3056189251Ssam		niface->next = iface;
3057189251Ssam		iface = niface;
3058189251Ssam	}
3059189251Ssam
3060189251Ssam	os_free(b);
3061189251Ssam	CloseHandle(ndisuio);
3062189251Ssam#else /* CONFIG_USE_NDISUIO */
3063189251Ssam	PTSTR _names;
3064189251Ssam	char *names, *pos, *pos2;
3065189251Ssam	ULONG len;
3066189251Ssam	BOOLEAN res;
3067189251Ssam	char *name[MAX_ADAPTERS];
3068189251Ssam	char *desc[MAX_ADAPTERS];
3069189251Ssam	int num_name, num_desc, i;
3070189251Ssam
3071189251Ssam	wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
3072189251Ssam		   PacketGetVersion());
3073189251Ssam
3074189251Ssam	len = 8192;
3075189251Ssam	_names = os_zalloc(len);
3076189251Ssam	if (_names == NULL)
3077189251Ssam		return NULL;
3078189251Ssam
3079189251Ssam	res = PacketGetAdapterNames(_names, &len);
3080189251Ssam	if (!res && len > 8192) {
3081189251Ssam		os_free(_names);
3082189251Ssam		_names = os_zalloc(len);
3083189251Ssam		if (_names == NULL)
3084189251Ssam			return NULL;
3085189251Ssam		res = PacketGetAdapterNames(_names, &len);
3086189251Ssam	}
3087189251Ssam
3088189251Ssam	if (!res) {
3089189251Ssam		wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
3090189251Ssam			   "(PacketGetAdapterNames)");
3091189251Ssam		os_free(_names);
3092189251Ssam		return NULL;
3093189251Ssam	}
3094189251Ssam
3095189251Ssam	names = (char *) _names;
3096189251Ssam	if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
3097189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
3098189251Ssam			   "UNICODE");
3099189251Ssam		/* Convert to ASCII */
3100189251Ssam		pos2 = pos = names;
3101189251Ssam		while (pos2 < names + len) {
3102189251Ssam			if (pos2[0] == '\0' && pos2[1] == '\0' &&
3103189251Ssam			    pos2[2] == '\0' && pos2[3] == '\0') {
3104189251Ssam				pos2 += 4;
3105189251Ssam				break;
3106189251Ssam			}
3107189251Ssam			*pos++ = pos2[0];
3108189251Ssam			pos2 += 2;
3109189251Ssam		}
3110189251Ssam		os_memcpy(pos + 2, names, pos - names);
3111189251Ssam		pos += 2;
3112189251Ssam	} else
3113189251Ssam		pos = names;
3114189251Ssam
3115189251Ssam	num_name = 0;
3116189251Ssam	while (pos < names + len) {
3117189251Ssam		name[num_name] = pos;
3118189251Ssam		while (*pos && pos < names + len)
3119189251Ssam			pos++;
3120189251Ssam		if (pos + 1 >= names + len) {
3121189251Ssam			os_free(names);
3122189251Ssam			return NULL;
3123189251Ssam		}
3124189251Ssam		pos++;
3125189251Ssam		num_name++;
3126189251Ssam		if (num_name >= MAX_ADAPTERS) {
3127189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
3128189251Ssam			os_free(names);
3129189251Ssam			return NULL;
3130189251Ssam		}
3131189251Ssam		if (*pos == '\0') {
3132189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found",
3133189251Ssam				   num_name);
3134189251Ssam			pos++;
3135189251Ssam			break;
3136189251Ssam		}
3137189251Ssam	}
3138189251Ssam
3139189251Ssam	num_desc = 0;
3140189251Ssam	while (pos < names + len) {
3141189251Ssam		desc[num_desc] = pos;
3142189251Ssam		while (*pos && pos < names + len)
3143189251Ssam			pos++;
3144189251Ssam		if (pos + 1 >= names + len) {
3145189251Ssam			os_free(names);
3146189251Ssam			return NULL;
3147189251Ssam		}
3148189251Ssam		pos++;
3149189251Ssam		num_desc++;
3150189251Ssam		if (num_desc >= MAX_ADAPTERS) {
3151189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
3152189251Ssam				   "descriptions");
3153189251Ssam			os_free(names);
3154189251Ssam			return NULL;
3155189251Ssam		}
3156189251Ssam		if (*pos == '\0') {
3157189251Ssam			wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions "
3158189251Ssam				   "found", num_name);
3159189251Ssam			pos++;
3160189251Ssam			break;
3161189251Ssam		}
3162189251Ssam	}
3163189251Ssam
3164189251Ssam	/*
3165189251Ssam	 * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
3166189251Ssam	 * descriptions. Fill in dummy descriptors to work around this.
3167189251Ssam	 */
3168189251Ssam	while (num_desc < num_name)
3169189251Ssam		desc[num_desc++] = "dummy description";
3170189251Ssam
3171189251Ssam	if (num_name != num_desc) {
3172189251Ssam		wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
3173189251Ssam			   "description counts (%d != %d)",
3174189251Ssam			   num_name, num_desc);
3175189251Ssam		os_free(names);
3176189251Ssam		return NULL;
3177189251Ssam	}
3178189251Ssam
3179189251Ssam	for (i = 0; i < num_name; i++) {
3180189251Ssam		niface = os_zalloc(sizeof(*niface));
3181189251Ssam		if (niface == NULL)
3182189251Ssam			break;
3183189251Ssam		niface->drv_name = "ndis";
3184189251Ssam		if (os_strncmp(name[i], "\\Device\\NPF_", 12) == 0)
3185189251Ssam			niface->ifname = os_strdup(name[i] + 12);
3186189251Ssam		else
3187189251Ssam			niface->ifname = os_strdup(name[i]);
3188189251Ssam		if (niface->ifname == NULL) {
3189189251Ssam			os_free(niface);
3190189251Ssam			break;
3191189251Ssam		}
3192189251Ssam		niface->desc = os_strdup(desc[i]);
3193189251Ssam		niface->next = iface;
3194189251Ssam		iface = niface;
3195189251Ssam	}
3196189251Ssam
3197189251Ssam#endif /* CONFIG_USE_NDISUIO */
3198189251Ssam
3199189251Ssam	return iface;
3200189251Ssam}
3201189251Ssam
3202189251Ssam
3203252726Srpaulostatic const char *ndis_drv_name = "ndis";
3204252726Srpaulostatic const char *ndis_drv_desc = "Windows NDIS driver";
3205252726Srpaulo
3206252726Srpaulostruct wpa_driver_ops wpa_driver_ndis_ops;
3207252726Srpaulo
3208252726Srpaulovoid driver_ndis_init_ops(void)
3209252726Srpaulo{
3210252726Srpaulo	os_memset(&wpa_driver_ndis_ops, 0, sizeof(wpa_driver_ndis_ops));
3211252726Srpaulo	wpa_driver_ndis_ops.name = ndis_drv_name;
3212252726Srpaulo	wpa_driver_ndis_ops.desc = ndis_drv_desc;
3213252726Srpaulo	wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid;
3214252726Srpaulo	wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid;
3215252726Srpaulo	wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key;
3216252726Srpaulo	wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
3217252726Srpaulo	wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
3218252726Srpaulo	wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
3219252726Srpaulo	wpa_driver_ndis_ops.associate = wpa_driver_ndis_associate;
3220252726Srpaulo	wpa_driver_ndis_ops.add_pmkid = wpa_driver_ndis_add_pmkid;
3221252726Srpaulo	wpa_driver_ndis_ops.remove_pmkid = wpa_driver_ndis_remove_pmkid;
3222252726Srpaulo	wpa_driver_ndis_ops.flush_pmkid = wpa_driver_ndis_flush_pmkid;
3223252726Srpaulo	wpa_driver_ndis_ops.get_capa = wpa_driver_ndis_get_capa;
3224252726Srpaulo	wpa_driver_ndis_ops.poll = wpa_driver_ndis_poll;
3225252726Srpaulo	wpa_driver_ndis_ops.get_ifname = wpa_driver_ndis_get_ifname;
3226252726Srpaulo	wpa_driver_ndis_ops.get_mac_addr = wpa_driver_ndis_get_mac_addr;
3227252726Srpaulo	wpa_driver_ndis_ops.get_scan_results2 =
3228252726Srpaulo		wpa_driver_ndis_get_scan_results;
3229252726Srpaulo	wpa_driver_ndis_ops.get_interfaces = wpa_driver_ndis_get_interfaces;
3230252726Srpaulo	wpa_driver_ndis_ops.scan2 = wpa_driver_ndis_scan;
3231252726Srpaulo}
3232