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