Re-enable hardware UDP/TCP checksum calculation with pseudo header on
[dragonfly/port-amd64.git] / contrib / wpa_supplicant-0.4.9 / driver_ndis.c
blobe7cb33cc3f827f47fee5cd95af72f5b7c2780777
1 /*
2 * WPA Supplicant - Windows/NDIS driver interface
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include <stdlib.h>
16 #include <Packet32.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <sys/unistd.h>
20 #include <ntddndis.h>
22 #include "common.h"
23 #include "driver.h"
24 #include "wpa_supplicant.h"
25 #include "l2_packet.h"
26 #include "eloop.h"
27 #include "wpa.h"
28 #include "driver_ndis.h"
30 int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv);
32 static void wpa_driver_ndis_poll(void *drv);
35 /* FIX: to be removed once this can be compiled with the complete NDIS
36 * header files */
37 #ifndef OID_802_11_BSSID
38 #define OID_802_11_BSSID 0x0d010101
39 #define OID_802_11_SSID 0x0d010102
40 #define OID_802_11_INFRASTRUCTURE_MODE 0x0d010108
41 #define OID_802_11_ADD_WEP 0x0D010113
42 #define OID_802_11_REMOVE_WEP 0x0D010114
43 #define OID_802_11_DISASSOCIATE 0x0D010115
44 #define OID_802_11_BSSID_LIST 0x0d010217
45 #define OID_802_11_AUTHENTICATION_MODE 0x0d010118
46 #define OID_802_11_PRIVACY_FILTER 0x0d010119
47 #define OID_802_11_BSSID_LIST_SCAN 0x0d01011A
48 #define OID_802_11_WEP_STATUS 0x0d01011B
49 #define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS
50 #define OID_802_11_ADD_KEY 0x0d01011D
51 #define OID_802_11_REMOVE_KEY 0x0d01011E
52 #define OID_802_11_ASSOCIATION_INFORMATION 0x0d01011F
53 #define OID_802_11_TEST 0x0d010120
54 #define OID_802_11_CAPABILITY 0x0d010122
55 #define OID_802_11_PMKID 0x0d010123
57 #define NDIS_802_11_LENGTH_SSID 32
58 #define NDIS_802_11_LENGTH_RATES 8
59 #define NDIS_802_11_LENGTH_RATES_EX 16
61 typedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
63 typedef struct NDIS_802_11_SSID {
64 ULONG SsidLength;
65 UCHAR Ssid[NDIS_802_11_LENGTH_SSID];
66 } NDIS_802_11_SSID;
68 typedef LONG NDIS_802_11_RSSI;
70 typedef enum NDIS_802_11_NETWORK_TYPE {
71 Ndis802_11FH,
72 Ndis802_11DS,
73 Ndis802_11OFDM5,
74 Ndis802_11OFDM24,
75 Ndis802_11NetworkTypeMax
76 } NDIS_802_11_NETWORK_TYPE;
78 typedef struct NDIS_802_11_CONFIGURATION_FH {
79 ULONG Length;
80 ULONG HopPattern;
81 ULONG HopSet;
82 ULONG DwellTime;
83 } NDIS_802_11_CONFIGURATION_FH;
85 typedef struct NDIS_802_11_CONFIGURATION {
86 ULONG Length;
87 ULONG BeaconPeriod;
88 ULONG ATIMWindow;
89 ULONG DSConfig;
90 NDIS_802_11_CONFIGURATION_FH FHConfig;
91 } NDIS_802_11_CONFIGURATION;
93 typedef enum NDIS_802_11_NETWORK_INFRASTRUCTURE {
94 Ndis802_11IBSS,
95 Ndis802_11Infrastructure,
96 Ndis802_11AutoUnknown,
97 Ndis802_11InfrastructureMax
98 } NDIS_802_11_NETWORK_INFRASTRUCTURE;
100 typedef enum NDIS_802_11_AUTHENTICATION_MODE {
101 Ndis802_11AuthModeOpen,
102 Ndis802_11AuthModeShared,
103 Ndis802_11AuthModeAutoSwitch,
104 Ndis802_11AuthModeWPA,
105 Ndis802_11AuthModeWPAPSK,
106 Ndis802_11AuthModeWPANone,
107 Ndis802_11AuthModeWPA2,
108 Ndis802_11AuthModeWPA2PSK,
109 Ndis802_11AuthModeMax
110 } NDIS_802_11_AUTHENTICATION_MODE;
112 typedef enum NDIS_802_11_WEP_STATUS {
113 Ndis802_11WEPEnabled,
114 Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
115 Ndis802_11WEPDisabled,
116 Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
117 Ndis802_11WEPKeyAbsent,
118 Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
119 Ndis802_11WEPNotSupported,
120 Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
121 Ndis802_11Encryption2Enabled,
122 Ndis802_11Encryption2KeyAbsent,
123 Ndis802_11Encryption3Enabled,
124 Ndis802_11Encryption3KeyAbsent
125 } NDIS_802_11_WEP_STATUS, NDIS_802_11_ENCRYPTION_STATUS;
127 typedef enum NDIS_802_11_PRIVACY_FILTER {
128 Ndis802_11PrivFilterAcceptAll,
129 Ndis802_11PrivFilter8021xWEP
130 } NDIS_802_11_PRIVACY_FILTER;
132 typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES];
133 typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX];
135 typedef struct NDIS_WLAN_BSSID_EX {
136 ULONG Length;
137 NDIS_802_11_MAC_ADDRESS MacAddress; /* BSSID */
138 UCHAR Reserved[2];
139 NDIS_802_11_SSID Ssid;
140 ULONG Privacy;
141 NDIS_802_11_RSSI Rssi;
142 NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
143 NDIS_802_11_CONFIGURATION Configuration;
144 NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
145 NDIS_802_11_RATES_EX SupportedRates;
146 ULONG IELength;
147 UCHAR IEs[1];
148 } NDIS_WLAN_BSSID_EX;
150 typedef struct NDIS_802_11_BSSID_LIST_EX {
151 ULONG NumberOfItems;
152 NDIS_WLAN_BSSID_EX Bssid[1];
153 } NDIS_802_11_BSSID_LIST_EX;
155 typedef struct NDIS_802_11_FIXED_IEs {
156 UCHAR Timestamp[8];
157 USHORT BeaconInterval;
158 USHORT Capabilities;
159 } NDIS_802_11_FIXED_IEs;
161 typedef struct NDIS_802_11_WEP {
162 ULONG Length;
163 ULONG KeyIndex;
164 ULONG KeyLength;
165 UCHAR KeyMaterial[1];
166 } NDIS_802_11_WEP;
168 typedef ULONG NDIS_802_11_KEY_INDEX;
169 typedef ULONGLONG NDIS_802_11_KEY_RSC;
171 typedef struct NDIS_802_11_KEY {
172 ULONG Length;
173 ULONG KeyIndex;
174 ULONG KeyLength;
175 NDIS_802_11_MAC_ADDRESS BSSID;
176 NDIS_802_11_KEY_RSC KeyRSC;
177 UCHAR KeyMaterial[1];
178 } NDIS_802_11_KEY;
180 typedef struct NDIS_802_11_REMOVE_KEY {
181 ULONG Length;
182 ULONG KeyIndex;
183 NDIS_802_11_MAC_ADDRESS BSSID;
184 } NDIS_802_11_REMOVE_KEY;
186 typedef struct NDIS_802_11_AI_REQFI {
187 USHORT Capabilities;
188 USHORT ListenInterval;
189 NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
190 } NDIS_802_11_AI_REQFI;
192 typedef struct NDIS_802_11_AI_RESFI {
193 USHORT Capabilities;
194 USHORT StatusCode;
195 USHORT AssociationId;
196 } NDIS_802_11_AI_RESFI;
198 typedef struct NDIS_802_11_ASSOCIATION_INFORMATION {
199 ULONG Length;
200 USHORT AvailableRequestFixedIEs;
201 NDIS_802_11_AI_REQFI RequestFixedIEs;
202 ULONG RequestIELength;
203 ULONG OffsetRequestIEs;
204 USHORT AvailableResponseFixedIEs;
205 NDIS_802_11_AI_RESFI ResponseFixedIEs;
206 ULONG ResponseIELength;
207 ULONG OffsetResponseIEs;
208 } NDIS_802_11_ASSOCIATION_INFORMATION;
210 typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION {
211 NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported;
212 NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported;
213 } NDIS_802_11_AUTHENTICATION_ENCRYPTION;
215 typedef struct NDIS_802_11_CAPABILITY {
216 ULONG Length;
217 ULONG Version;
218 ULONG NoOfPMKIDs;
219 ULONG NoOfAuthEncryptPairSupported;
220 NDIS_802_11_AUTHENTICATION_ENCRYPTION
221 AuthenticationEncryptionSupported[1];
222 } NDIS_802_11_CAPABILITY;
224 typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
226 typedef struct BSSID_INFO {
227 NDIS_802_11_MAC_ADDRESS BSSID;
228 NDIS_802_11_PMKID_VALUE PMKID;
229 } BSSID_INFO;
231 typedef struct NDIS_802_11_PMKID {
232 ULONG Length;
233 ULONG BSSIDInfoCount;
234 BSSID_INFO BSSIDInfo[1];
235 } NDIS_802_11_PMKID;
237 typedef enum NDIS_802_11_STATUS_TYPE {
238 Ndis802_11StatusType_Authentication,
239 Ndis802_11StatusType_PMKID_CandidateList = 2,
240 Ndis802_11StatusTypeMax
241 } NDIS_802_11_STATUS_TYPE;
243 typedef struct NDIS_802_11_STATUS_INDICATION {
244 NDIS_802_11_STATUS_TYPE StatusType;
245 } NDIS_802_11_STATUS_INDICATION;
247 typedef struct PMKID_CANDIDATE {
248 NDIS_802_11_MAC_ADDRESS BSSID;
249 ULONG Flags;
250 } PMKID_CANDIDATE;
252 #define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
254 typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST {
255 ULONG Version;
256 ULONG NumCandidates;
257 PMKID_CANDIDATE CandidateList[1];
258 } NDIS_802_11_PMKID_CANDIDATE_LIST;
260 typedef struct NDIS_802_11_AUTHENTICATION_REQUEST {
261 ULONG Length;
262 NDIS_802_11_MAC_ADDRESS Bssid;
263 ULONG Flags;
264 } NDIS_802_11_AUTHENTICATION_REQUEST;
266 #define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01
267 #define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02
268 #define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06
269 #define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E
271 #endif
274 static int ndis_get_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
275 char *data, int len)
277 char *buf;
278 PACKET_OID_DATA *o;
279 int ret;
281 buf = malloc(sizeof(*o) + len);
282 if (buf == NULL)
283 return -1;
284 memset(buf, 0, sizeof(*o) + len);
285 o = (PACKET_OID_DATA *) buf;
286 o->Oid = oid;
287 o->Length = len;
289 if (!PacketRequest(drv->adapter, FALSE, o)) {
290 wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
291 __func__, oid, len);
292 free(buf);
293 return -1;
295 if (o->Length > len) {
296 wpa_printf(MSG_DEBUG, "%s: oid=0x%x Length (%d) > len (%d)",
297 __func__, oid, (unsigned int) o->Length, len);
298 free(buf);
299 return -1;
301 memcpy(data, o->Data, o->Length);
302 ret = o->Length;
303 free(buf);
304 return ret;
308 static int ndis_set_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
309 char *data, int len)
311 char *buf;
312 PACKET_OID_DATA *o;
314 buf = malloc(sizeof(*o) + len);
315 if (buf == NULL)
316 return -1;
317 memset(buf, 0, sizeof(*o) + len);
318 o = (PACKET_OID_DATA *) buf;
319 o->Oid = oid;
320 o->Length = len;
321 if (data)
322 memcpy(o->Data, data, len);
324 if (!PacketRequest(drv->adapter, TRUE, o)) {
325 wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
326 __func__, oid, len);
327 free(buf);
328 return -1;
330 free(buf);
331 return 0;
335 static int ndis_set_auth_mode(struct wpa_driver_ndis_data *drv, int mode)
337 u32 auth_mode = mode;
338 if (ndis_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
339 (char *) &auth_mode, sizeof(auth_mode)) < 0) {
340 wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
341 "OID_802_11_AUTHENTICATION_MODE (%d)",
342 (int) auth_mode);
343 return -1;
345 return 0;
349 static int ndis_get_auth_mode(struct wpa_driver_ndis_data *drv)
351 u32 auth_mode;
352 int res;
353 res = ndis_get_oid(drv, OID_802_11_AUTHENTICATION_MODE,
354 (char *) &auth_mode, sizeof(auth_mode));
355 if (res != sizeof(auth_mode)) {
356 wpa_printf(MSG_DEBUG, "NDIS: Failed to get "
357 "OID_802_11_AUTHENTICATION_MODE");
358 return -1;
360 return auth_mode;
364 static int ndis_set_encr_status(struct wpa_driver_ndis_data *drv, int encr)
366 u32 encr_status = encr;
367 if (ndis_set_oid(drv, OID_802_11_ENCRYPTION_STATUS,
368 (char *) &encr_status, sizeof(encr_status)) < 0) {
369 wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
370 "OID_802_11_ENCRYPTION_STATUS (%d)", encr);
371 return -1;
373 return 0;
377 static int ndis_get_encr_status(struct wpa_driver_ndis_data *drv)
379 u32 encr;
380 int res;
381 res = ndis_get_oid(drv, OID_802_11_ENCRYPTION_STATUS,
382 (char *) &encr, sizeof(encr));
383 if (res != sizeof(encr)) {
384 wpa_printf(MSG_DEBUG, "NDIS: Failed to get "
385 "OID_802_11_ENCRYPTION_STATUS");
386 return -1;
388 return encr;
392 static int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid)
394 struct wpa_driver_ndis_data *drv = priv;
396 if (drv->wired) {
398 * Report PAE group address as the "BSSID" for wired
399 * connection.
401 bssid[0] = 0x01;
402 bssid[1] = 0x80;
403 bssid[2] = 0xc2;
404 bssid[3] = 0x00;
405 bssid[4] = 0x00;
406 bssid[5] = 0x03;
407 return 0;
410 return ndis_get_oid(drv, OID_802_11_BSSID, bssid, ETH_ALEN) < 0 ?
411 -1 : 0;
416 static int wpa_driver_ndis_get_ssid(void *priv, u8 *ssid)
418 struct wpa_driver_ndis_data *drv = priv;
419 NDIS_802_11_SSID buf;
420 int res;
422 res = ndis_get_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
423 if (res < 4) {
424 wpa_printf(MSG_DEBUG, "NDIS: Failed to get SSID");
425 if (drv->wired) {
426 wpa_printf(MSG_DEBUG, "NDIS: Allow get_ssid failure "
427 "with a wired interface");
428 return 0;
430 return -1;
432 memcpy(ssid, buf.Ssid, buf.SsidLength);
433 return buf.SsidLength;
437 static int wpa_driver_ndis_set_ssid(struct wpa_driver_ndis_data *drv,
438 const u8 *ssid, size_t ssid_len)
440 NDIS_802_11_SSID buf;
442 memset(&buf, 0, sizeof(buf));
443 buf.SsidLength = ssid_len;
444 memcpy(buf.Ssid, ssid, ssid_len);
446 * Make sure radio is marked enabled here so that scan request will not
447 * force SSID to be changed to a random one in order to enable radio at
448 * that point.
450 drv->radio_enabled = 1;
451 return ndis_set_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
455 /* Disconnect using OID_802_11_DISASSOCIATE. This will also turn the radio off.
457 static int wpa_driver_ndis_radio_off(struct wpa_driver_ndis_data *drv)
459 drv->radio_enabled = 0;
460 return ndis_set_oid(drv, OID_802_11_DISASSOCIATE, " ", 4);
464 /* Disconnect by setting SSID to random (i.e., likely not used). */
465 static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv)
467 char ssid[32];
468 int i;
469 for (i = 0; i < 32; i++)
470 ssid[i] = rand() & 0xff;
471 return wpa_driver_ndis_set_ssid(drv, ssid, 32);
475 static int wpa_driver_ndis_deauthenticate(void *priv, const u8 *addr,
476 int reason_code)
478 struct wpa_driver_ndis_data *drv = priv;
479 return wpa_driver_ndis_disconnect(drv);
483 static int wpa_driver_ndis_disassociate(void *priv, const u8 *addr,
484 int reason_code)
486 struct wpa_driver_ndis_data *drv = priv;
487 return wpa_driver_ndis_disconnect(drv);
491 static int wpa_driver_ndis_set_wpa(void *priv, int enabled)
493 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
494 return 0;
498 static void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx)
500 wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
501 wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
505 static int wpa_driver_ndis_scan(void *priv, const u8 *ssid, size_t ssid_len)
507 struct wpa_driver_ndis_data *drv = priv;
508 int res;
510 if (!drv->radio_enabled) {
511 wpa_printf(MSG_DEBUG, "NDIS: turning radio on before the first"
512 " scan");
513 if (wpa_driver_ndis_disconnect(drv) < 0) {
514 wpa_printf(MSG_DEBUG, "NDIS: failed to enable radio");
516 drv->radio_enabled = 1;
519 res = ndis_set_oid(drv, OID_802_11_BSSID_LIST_SCAN, " ", 4);
520 eloop_register_timeout(3, 0, wpa_driver_ndis_scan_timeout, drv,
521 drv->ctx);
522 return res;
526 static void wpa_driver_ndis_get_ies(struct wpa_scan_result *res, u8 *ie,
527 size_t ie_len)
529 u8 *pos = ie;
530 u8 *end = ie + ie_len;
532 if (ie_len < sizeof(NDIS_802_11_FIXED_IEs))
533 return;
535 pos += sizeof(NDIS_802_11_FIXED_IEs);
536 /* wpa_hexdump(MSG_MSGDUMP, "IEs", pos, end - pos); */
537 while (pos + 1 < end && pos + 2 + pos[1] <= end) {
538 u8 ielen = 2 + pos[1];
539 if (ielen > SSID_MAX_WPA_IE_LEN) {
540 pos += ielen;
541 continue;
543 if (pos[0] == GENERIC_INFO_ELEM && pos[1] >= 4 &&
544 memcmp(pos + 2, "\x00\x50\xf2\x01", 4) == 0) {
545 memcpy(res->wpa_ie, pos, ielen);
546 res->wpa_ie_len = ielen;
547 } else if (pos[0] == RSN_INFO_ELEM) {
548 memcpy(res->rsn_ie, pos, ielen);
549 res->rsn_ie_len = ielen;
551 pos += ielen;
556 static int wpa_driver_ndis_get_scan_results(void *priv,
557 struct wpa_scan_result *results,
558 size_t max_size)
560 struct wpa_driver_ndis_data *drv = priv;
561 NDIS_802_11_BSSID_LIST_EX *b;
562 size_t blen;
563 int len, count, i, j;
564 char *pos;
566 blen = 65535;
567 b = malloc(blen);
568 if (b == NULL)
569 return -1;
570 memset(b, 0, blen);
571 len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
572 if (len < 0) {
573 wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
574 free(b);
575 return -1;
577 count = b->NumberOfItems;
579 if (count > max_size)
580 count = max_size;
582 memset(results, 0, max_size * sizeof(struct wpa_scan_result));
583 pos = (char *) &b->Bssid[0];
584 for (i = 0; i < count; i++) {
585 NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
586 memcpy(results[i].bssid, bss->MacAddress, ETH_ALEN);
587 memcpy(results[i].ssid, bss->Ssid.Ssid, bss->Ssid.SsidLength);
588 results[i].ssid_len = bss->Ssid.SsidLength;
589 if (bss->Privacy)
590 results[i].caps |= IEEE80211_CAP_PRIVACY;
591 results[i].level = (int) bss->Rssi;
592 results[i].freq = bss->Configuration.DSConfig / 1000;
593 for (j = 0; j < sizeof(bss->SupportedRates); j++) {
594 if ((bss->SupportedRates[j] & 0x7f) >
595 results[i].maxrate) {
596 results[i].maxrate =
597 bss->SupportedRates[j] & 0x7f;
600 wpa_driver_ndis_get_ies(&results[i], bss->IEs, bss->IELength);
601 pos += bss->Length;
602 if (pos > (char *) b + blen)
603 break;
606 free(b);
607 return count;
611 static int wpa_driver_ndis_remove_key(struct wpa_driver_ndis_data *drv,
612 int key_idx, const u8 *addr,
613 const u8 *bssid, int pairwise)
615 NDIS_802_11_REMOVE_KEY rkey;
616 NDIS_802_11_KEY_INDEX index;
617 int res, res2;
619 memset(&rkey, 0, sizeof(rkey));
621 rkey.Length = sizeof(rkey);
622 rkey.KeyIndex = key_idx;
623 if (pairwise)
624 rkey.KeyIndex |= 1 << 30;
625 memcpy(rkey.BSSID, bssid, ETH_ALEN);
627 res = ndis_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
628 sizeof(rkey));
629 if (!pairwise) {
630 res2 = ndis_set_oid(drv, OID_802_11_REMOVE_WEP,
631 (char *) &index, sizeof(index));
632 } else
633 res2 = 0;
635 if (res < 0 && res2 < 0)
636 return res;
637 return 0;
641 static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv,
642 int pairwise, int key_idx, int set_tx,
643 const u8 *key, size_t key_len)
645 NDIS_802_11_WEP *wep;
646 size_t len;
647 int res;
649 len = 12 + key_len;
650 wep = malloc(len);
651 if (wep == NULL)
652 return -1;
653 memset(wep, 0, len);
654 wep->Length = len;
655 wep->KeyIndex = key_idx;
656 if (set_tx)
657 wep->KeyIndex |= 1 << 31;
658 #if 0 /* Setting bit30 does not seem to work with some NDIS drivers */
659 if (pairwise)
660 wep->KeyIndex |= 1 << 30;
661 #endif
662 wep->KeyLength = key_len;
663 memcpy(wep->KeyMaterial, key, key_len);
665 wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OIS_802_11_ADD_WEP",
666 (char *) wep, len);
667 res = ndis_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
669 free(wep);
671 return res;
674 static int wpa_driver_ndis_set_key(void *priv, wpa_alg alg, const u8 *addr,
675 int key_idx, int set_tx,
676 const u8 *seq, size_t seq_len,
677 const u8 *key, size_t key_len)
679 struct wpa_driver_ndis_data *drv = priv;
680 size_t len;
681 NDIS_802_11_KEY *nkey;
682 int i, res, pairwise;
683 u8 bssid[ETH_ALEN];
685 if (addr == NULL || memcmp(addr, "\xff\xff\xff\xff\xff\xff",
686 ETH_ALEN) == 0) {
687 /* Group Key */
688 pairwise = 0;
689 wpa_driver_ndis_get_bssid(drv, bssid);
690 } else {
691 /* Pairwise Key */
692 pairwise = 1;
693 memcpy(bssid, addr, ETH_ALEN);
696 if (alg == WPA_ALG_NONE || key_len == 0) {
697 return wpa_driver_ndis_remove_key(drv, key_idx, addr, bssid,
698 pairwise);
701 if (alg == WPA_ALG_WEP) {
702 return wpa_driver_ndis_add_wep(drv, pairwise, key_idx, set_tx,
703 key, key_len);
706 len = 12 + 6 + 6 + 8 + key_len;
708 nkey = malloc(len);
709 if (nkey == NULL)
710 return -1;
711 memset(nkey, 0, len);
713 nkey->Length = len;
714 nkey->KeyIndex = key_idx;
715 if (set_tx)
716 nkey->KeyIndex |= 1 << 31;
717 if (pairwise)
718 nkey->KeyIndex |= 1 << 30;
719 if (seq && seq_len)
720 nkey->KeyIndex |= 1 << 29;
721 nkey->KeyLength = key_len;
722 memcpy(nkey->BSSID, bssid, ETH_ALEN);
723 if (seq && seq_len) {
724 for (i = 0; i < seq_len; i++)
725 nkey->KeyRSC |= seq[i] << (i * 8);
727 if (alg == WPA_ALG_TKIP && key_len == 32) {
728 memcpy(nkey->KeyMaterial, key, 16);
729 memcpy(nkey->KeyMaterial + 16, key + 24, 8);
730 memcpy(nkey->KeyMaterial + 24, key + 16, 8);
731 } else {
732 memcpy(nkey->KeyMaterial, key, key_len);
735 wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OIS_802_11_ADD_KEY",
736 (char *) nkey, len);
737 res = ndis_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
738 free(nkey);
740 return res;
744 static int
745 wpa_driver_ndis_associate(void *priv,
746 struct wpa_driver_associate_params *params)
748 struct wpa_driver_ndis_data *drv = priv;
749 u32 auth_mode, encr, priv_mode, mode;
751 /* Note: Setting OID_802_11_INFRASTRUCTURE_MODE clears current keys,
752 * so static WEP keys needs to be set again after this. */
753 if (params->mode == IEEE80211_MODE_IBSS)
754 mode = Ndis802_11IBSS;
755 else
756 mode = Ndis802_11Infrastructure;
757 if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
758 (char *) &mode, sizeof(mode)) < 0) {
759 wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
760 "OID_802_11_INFRASTRUCTURE_MODE (%d)",
761 (int) mode);
762 /* Try to continue anyway */
765 if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
766 if (params->auth_alg & AUTH_ALG_SHARED_KEY) {
767 if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
768 auth_mode = Ndis802_11AuthModeAutoSwitch;
769 else
770 auth_mode = Ndis802_11AuthModeShared;
771 } else
772 auth_mode = Ndis802_11AuthModeOpen;
773 priv_mode = Ndis802_11PrivFilterAcceptAll;
774 } else if (params->wpa_ie[0] == RSN_INFO_ELEM) {
775 priv_mode = Ndis802_11PrivFilter8021xWEP;
776 if (params->key_mgmt_suite == KEY_MGMT_PSK)
777 auth_mode = Ndis802_11AuthModeWPA2PSK;
778 else
779 auth_mode = Ndis802_11AuthModeWPA2;
780 } else {
781 priv_mode = Ndis802_11PrivFilter8021xWEP;
782 if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
783 auth_mode = Ndis802_11AuthModeWPANone;
784 else if (params->key_mgmt_suite == KEY_MGMT_PSK)
785 auth_mode = Ndis802_11AuthModeWPAPSK;
786 else
787 auth_mode = Ndis802_11AuthModeWPA;
790 switch (params->pairwise_suite) {
791 case CIPHER_CCMP:
792 encr = Ndis802_11Encryption3Enabled;
793 break;
794 case CIPHER_TKIP:
795 encr = Ndis802_11Encryption2Enabled;
796 break;
797 case CIPHER_WEP40:
798 case CIPHER_WEP104:
799 encr = Ndis802_11Encryption1Enabled;
800 break;
801 case CIPHER_NONE:
802 if (params->group_suite == CIPHER_CCMP)
803 encr = Ndis802_11Encryption3Enabled;
804 else if (params->group_suite == CIPHER_TKIP)
805 encr = Ndis802_11Encryption2Enabled;
806 else
807 encr = Ndis802_11EncryptionDisabled;
808 break;
809 default:
810 encr = Ndis802_11EncryptionDisabled;
813 if (ndis_set_oid(drv, OID_802_11_PRIVACY_FILTER,
814 (char *) &priv_mode, sizeof(priv_mode)) < 0) {
815 wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
816 "OID_802_11_PRIVACY_FILTER (%d)",
817 (int) priv_mode);
818 /* Try to continue anyway */
821 ndis_set_auth_mode(drv, auth_mode);
822 ndis_set_encr_status(drv, encr);
824 return wpa_driver_ndis_set_ssid(drv, params->ssid, params->ssid_len);
828 static int wpa_driver_ndis_set_pmkid(struct wpa_driver_ndis_data *drv)
830 int len, count, i, ret;
831 struct ndis_pmkid_entry *entry;
832 NDIS_802_11_PMKID *p;
834 count = 0;
835 entry = drv->pmkid;
836 while (entry) {
837 count++;
838 if (count >= drv->no_of_pmkid)
839 break;
840 entry = entry->next;
842 len = 8 + count * sizeof(BSSID_INFO);
843 p = malloc(len);
844 if (p == NULL)
845 return -1;
846 memset(p, 0, len);
847 p->Length = len;
848 p->BSSIDInfoCount = count;
849 entry = drv->pmkid;
850 for (i = 0; i < count; i++) {
851 memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
852 memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
853 entry = entry->next;
855 wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", (char *) p, len);
856 ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
857 free(p);
858 return ret;
862 static int wpa_driver_ndis_add_pmkid(void *priv, const u8 *bssid,
863 const u8 *pmkid)
865 struct wpa_driver_ndis_data *drv = priv;
866 struct ndis_pmkid_entry *entry, *prev;
868 if (drv->no_of_pmkid == 0)
869 return 0;
871 prev = NULL;
872 entry = drv->pmkid;
873 while (entry) {
874 if (memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
875 break;
876 prev = entry;
877 entry = entry->next;
880 if (entry) {
881 /* Replace existing entry for this BSSID and move it into the
882 * beginning of the list. */
883 memcpy(entry->pmkid, pmkid, 16);
884 if (prev) {
885 prev->next = entry->next;
886 entry->next = drv->pmkid;
887 drv->pmkid = entry;
889 } else {
890 entry = malloc(sizeof(*entry));
891 if (entry) {
892 memcpy(entry->bssid, bssid, ETH_ALEN);
893 memcpy(entry->pmkid, pmkid, 16);
894 entry->next = drv->pmkid;
895 drv->pmkid = entry;
899 return wpa_driver_ndis_set_pmkid(drv);
903 static int wpa_driver_ndis_remove_pmkid(void *priv, const u8 *bssid,
904 const u8 *pmkid)
906 struct wpa_driver_ndis_data *drv = priv;
907 struct ndis_pmkid_entry *entry, *prev;
909 if (drv->no_of_pmkid == 0)
910 return 0;
912 entry = drv->pmkid;
913 prev = NULL;
914 drv->pmkid = NULL;
915 while (entry) {
916 if (memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
917 memcmp(entry->pmkid, pmkid, 16) == 0) {
918 if (prev)
919 prev->next = entry->next;
920 else
921 drv->pmkid = entry->next;
922 free(entry);
923 break;
925 prev = entry;
926 entry = entry->next;
928 return wpa_driver_ndis_set_pmkid(drv);
932 static int wpa_driver_ndis_flush_pmkid(void *priv)
934 struct wpa_driver_ndis_data *drv = priv;
935 NDIS_802_11_PMKID p;
936 struct ndis_pmkid_entry *pmkid, *prev;
938 if (drv->no_of_pmkid == 0)
939 return 0;
941 pmkid = drv->pmkid;
942 drv->pmkid = NULL;
943 while (pmkid) {
944 prev = pmkid;
945 pmkid = pmkid->next;
946 free(prev);
949 memset(&p, 0, sizeof(p));
950 p.Length = 8;
951 p.BSSIDInfoCount = 0;
952 wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
953 (char *) &p, 8);
954 return ndis_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
958 static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
960 char buf[512], *pos;
961 NDIS_802_11_ASSOCIATION_INFORMATION *ai;
962 int len, i;
963 union wpa_event_data data;
964 NDIS_802_11_BSSID_LIST_EX *b;
965 size_t blen;
967 len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, buf,
968 sizeof(buf));
969 if (len < 0) {
970 wpa_printf(MSG_DEBUG, "NDIS: failed to get association "
971 "information");
972 return -1;
974 if (len > sizeof(buf)) {
975 /* Some drivers seem to be producing incorrect length for this
976 * data. Limit the length to the current buffer size to avoid
977 * crashing in hexdump. The data seems to be otherwise valid,
978 * so better try to use it. */
979 wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association "
980 "information length %d", len);
981 len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION,
982 buf, sizeof(buf));
983 if (len < -1) {
984 wpa_printf(MSG_DEBUG, "NDIS: re-reading association "
985 "information failed");
986 return -1;
988 if (len > sizeof(buf)) {
989 wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association"
990 " information length %d (re-read)", len);
991 len = sizeof(buf);
994 wpa_hexdump(MSG_MSGDUMP, "NDIS: association information", buf, len);
995 if (len < sizeof(*ai)) {
996 wpa_printf(MSG_DEBUG, "NDIS: too short association "
997 "information");
998 return -1;
1000 ai = (NDIS_802_11_ASSOCIATION_INFORMATION *) buf;
1001 wpa_printf(MSG_DEBUG, "NDIS: ReqFixed=0x%x RespFixed=0x%x off_req=%d "
1002 "off_resp=%d len_req=%d len_resp=%d",
1003 ai->AvailableRequestFixedIEs, ai->AvailableResponseFixedIEs,
1004 (int) ai->OffsetRequestIEs, (int) ai->OffsetResponseIEs,
1005 (int) ai->RequestIELength, (int) ai->ResponseIELength);
1007 if (ai->OffsetRequestIEs + ai->RequestIELength > len ||
1008 ai->OffsetResponseIEs + ai->ResponseIELength > len) {
1009 wpa_printf(MSG_DEBUG, "NDIS: association information - "
1010 "IE overflow");
1011 return -1;
1014 wpa_hexdump(MSG_MSGDUMP, "NDIS: Request IEs",
1015 buf + ai->OffsetRequestIEs, ai->RequestIELength);
1016 wpa_hexdump(MSG_MSGDUMP, "NDIS: Response IEs",
1017 buf + ai->OffsetResponseIEs, ai->ResponseIELength);
1019 memset(&data, 0, sizeof(data));
1020 data.assoc_info.req_ies = buf + ai->OffsetRequestIEs;
1021 data.assoc_info.req_ies_len = ai->RequestIELength;
1022 data.assoc_info.resp_ies = buf + ai->OffsetResponseIEs;
1023 data.assoc_info.resp_ies_len = ai->ResponseIELength;
1025 blen = 65535;
1026 b = malloc(blen);
1027 if (b == NULL)
1028 goto skip_scan_results;
1029 memset(b, 0, blen);
1030 len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
1031 if (len < 0) {
1032 wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
1033 free(b);
1034 b = NULL;
1035 goto skip_scan_results;
1037 wpa_printf(MSG_DEBUG, "NDIS: %d BSSID items to process for AssocInfo",
1038 (unsigned int) b->NumberOfItems);
1040 pos = (char *) &b->Bssid[0];
1041 for (i = 0; i < b->NumberOfItems; i++) {
1042 NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
1043 if (memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 &&
1044 bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) {
1045 data.assoc_info.beacon_ies =
1046 ((u8 *) bss->IEs) +
1047 sizeof(NDIS_802_11_FIXED_IEs);
1048 data.assoc_info.beacon_ies_len =
1049 bss->IELength - sizeof(NDIS_802_11_FIXED_IEs);
1050 wpa_hexdump(MSG_MSGDUMP, "NDIS: Beacon IEs",
1051 data.assoc_info.beacon_ies,
1052 data.assoc_info.beacon_ies_len);
1053 break;
1055 pos += bss->Length;
1056 if (pos > (char *) b + blen)
1057 break;
1060 skip_scan_results:
1061 wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
1063 free(b);
1065 return 0;
1069 static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx)
1071 struct wpa_driver_ndis_data *drv = eloop_ctx;
1072 u8 bssid[ETH_ALEN];
1074 if (drv->wired)
1075 return;
1077 if (wpa_driver_ndis_get_bssid(drv, bssid)) {
1078 /* Disconnected */
1079 if (memcmp(drv->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN)
1080 != 0) {
1081 memset(drv->bssid, 0, ETH_ALEN);
1082 wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
1084 } else {
1085 /* Connected */
1086 if (memcmp(drv->bssid, bssid, ETH_ALEN) != 0) {
1087 memcpy(drv->bssid, bssid, ETH_ALEN);
1088 wpa_driver_ndis_get_associnfo(drv);
1089 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
1092 eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, drv, NULL);
1096 static void wpa_driver_ndis_poll(void *priv)
1098 struct wpa_driver_ndis_data *drv = priv;
1099 eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
1100 wpa_driver_ndis_poll_timeout(drv, NULL);
1104 /* Called when driver generates Media Connect Event by calling
1105 * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_CONNECT */
1106 void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv)
1108 wpa_printf(MSG_DEBUG, "NDIS: Media Connect Event");
1109 if (wpa_driver_ndis_get_bssid(drv, drv->bssid) == 0) {
1110 wpa_driver_ndis_get_associnfo(drv);
1111 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
1116 /* Called when driver generates Media Disconnect Event by calling
1117 * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_DISCONNECT */
1118 void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv)
1120 wpa_printf(MSG_DEBUG, "NDIS: Media Disconnect Event");
1121 memset(drv->bssid, 0, ETH_ALEN);
1122 wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
1126 static void wpa_driver_ndis_event_auth(struct wpa_driver_ndis_data *drv,
1127 const u8 *data, size_t data_len)
1129 NDIS_802_11_AUTHENTICATION_REQUEST *req;
1130 int pairwise = 0, group = 0;
1131 union wpa_event_data event;
1133 if (data_len < sizeof(*req)) {
1134 wpa_printf(MSG_DEBUG, "NDIS: Too short Authentication Request "
1135 "Event (len=%d)", data_len);
1136 return;
1138 req = (NDIS_802_11_AUTHENTICATION_REQUEST *) data;
1140 wpa_printf(MSG_DEBUG, "NDIS: Authentication Request Event: "
1141 "Bssid " MACSTR " Flags 0x%x",
1142 MAC2STR(req->Bssid), (int) req->Flags);
1144 if ((req->Flags & NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR) ==
1145 NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR)
1146 pairwise = 1;
1147 else if ((req->Flags & NDIS_802_11_AUTH_REQUEST_GROUP_ERROR) ==
1148 NDIS_802_11_AUTH_REQUEST_GROUP_ERROR)
1149 group = 1;
1151 if (pairwise || group) {
1152 memset(&event, 0, sizeof(event));
1153 event.michael_mic_failure.unicast = pairwise;
1154 wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE,
1155 &event);
1160 static void wpa_driver_ndis_event_pmkid(struct wpa_driver_ndis_data *drv,
1161 const u8 *data, size_t data_len)
1163 NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
1164 int i;
1165 union wpa_event_data event;
1167 if (data_len < 8) {
1168 wpa_printf(MSG_DEBUG, "NDIS: Too short PMKID Candidate List "
1169 "Event (len=%d)", data_len);
1170 return;
1172 pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
1173 wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List Event - Version %d "
1174 "NumCandidates %d",
1175 (int) pmkid->Version, (int) pmkid->NumCandidates);
1177 if (pmkid->Version != 1) {
1178 wpa_printf(MSG_DEBUG, "NDIS: Unsupported PMKID Candidate List "
1179 "Version %d", (int) pmkid->Version);
1180 return;
1183 if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
1184 wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List underflow");
1185 return;
1188 memset(&event, 0, sizeof(event));
1189 for (i = 0; i < pmkid->NumCandidates; i++) {
1190 PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
1191 wpa_printf(MSG_DEBUG, "NDIS: %d: " MACSTR " Flags 0x%x",
1192 i, MAC2STR(p->BSSID), (int) p->Flags);
1193 memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
1194 event.pmkid_candidate.index = i;
1195 event.pmkid_candidate.preauth =
1196 p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
1197 wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
1198 &event);
1203 /* Called when driver calls NdisMIndicateStatus() with
1204 * NDIS_STATUS_MEDIA_SPECIFIC_INDICATION */
1205 void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv,
1206 const u8 *data, size_t data_len)
1208 NDIS_802_11_STATUS_INDICATION *status;
1210 if (data == NULL || data_len < sizeof(*status))
1211 return;
1213 wpa_hexdump(MSG_DEBUG, "NDIS: Media Specific Indication",
1214 data, data_len);
1216 status = (NDIS_802_11_STATUS_INDICATION *) data;
1217 data += sizeof(status);
1218 data_len -= sizeof(status);
1220 switch (status->StatusType) {
1221 case Ndis802_11StatusType_Authentication:
1222 wpa_driver_ndis_event_auth(drv, data, data_len);
1223 break;
1224 case Ndis802_11StatusType_PMKID_CandidateList:
1225 wpa_driver_ndis_event_pmkid(drv, data, data_len);
1226 break;
1227 default:
1228 wpa_printf(MSG_DEBUG, "NDIS: Unknown StatusType %d",
1229 (int) status->StatusType);
1230 break;
1235 static void
1236 wpa_driver_ndis_get_wpa_capability(struct wpa_driver_ndis_data *drv)
1238 wpa_printf(MSG_DEBUG, "NDIS: verifying driver WPA capability");
1240 if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA) == 0 &&
1241 ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPA) {
1242 wpa_printf(MSG_DEBUG, "NDIS: WPA key management supported");
1243 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA;
1246 if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPAPSK) == 0 &&
1247 ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPAPSK) {
1248 wpa_printf(MSG_DEBUG, "NDIS: WPA-PSK key management "
1249 "supported");
1250 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
1253 if (ndis_set_encr_status(drv, Ndis802_11Encryption3Enabled) == 0 &&
1254 ndis_get_encr_status(drv) == Ndis802_11Encryption3KeyAbsent) {
1255 wpa_printf(MSG_DEBUG, "NDIS: CCMP encryption supported");
1256 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
1259 if (ndis_set_encr_status(drv, Ndis802_11Encryption2Enabled) == 0 &&
1260 ndis_get_encr_status(drv) == Ndis802_11Encryption2KeyAbsent) {
1261 wpa_printf(MSG_DEBUG, "NDIS: TKIP encryption supported");
1262 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
1265 if (ndis_set_encr_status(drv, Ndis802_11Encryption1Enabled) == 0 &&
1266 ndis_get_encr_status(drv) == Ndis802_11Encryption1KeyAbsent) {
1267 wpa_printf(MSG_DEBUG, "NDIS: WEP encryption supported");
1268 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
1269 WPA_DRIVER_CAPA_ENC_WEP104;
1272 if (ndis_set_auth_mode(drv, Ndis802_11AuthModeShared) == 0 &&
1273 ndis_get_auth_mode(drv) == Ndis802_11AuthModeShared) {
1274 drv->capa.auth |= WPA_DRIVER_AUTH_SHARED;
1277 if (ndis_set_auth_mode(drv, Ndis802_11AuthModeOpen) == 0 &&
1278 ndis_get_auth_mode(drv) == Ndis802_11AuthModeOpen) {
1279 drv->capa.auth |= WPA_DRIVER_AUTH_OPEN;
1282 ndis_set_encr_status(drv, Ndis802_11EncryptionDisabled);
1284 /* Could also verify OID_802_11_ADD_KEY error reporting and
1285 * support for OID_802_11_ASSOCIATION_INFORMATION. */
1287 if (drv->capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA &&
1288 drv->capa.enc & (WPA_DRIVER_CAPA_ENC_TKIP |
1289 WPA_DRIVER_CAPA_ENC_CCMP)) {
1290 wpa_printf(MSG_DEBUG, "NDIS: driver supports WPA");
1291 drv->has_capability = 1;
1292 } else {
1293 wpa_printf(MSG_DEBUG, "NDIS: no WPA support found");
1296 wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x "
1297 "enc 0x%x auth 0x%x",
1298 drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth);
1302 static void wpa_driver_ndis_get_capability(struct wpa_driver_ndis_data *drv)
1304 char buf[512];
1305 int len, i;
1306 NDIS_802_11_CAPABILITY *c;
1308 drv->capa.flags = WPA_DRIVER_FLAGS_DRIVER_IE |
1309 WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC;
1311 len = ndis_get_oid(drv, OID_802_11_CAPABILITY, buf, sizeof(buf));
1312 if (len < 0) {
1313 wpa_driver_ndis_get_wpa_capability(drv);
1314 return;
1317 wpa_hexdump(MSG_MSGDUMP, "OID_802_11_CAPABILITY", buf, len);
1318 c = (NDIS_802_11_CAPABILITY *) buf;
1319 if (len < sizeof(*c) || c->Version != 2) {
1320 wpa_printf(MSG_DEBUG, "NDIS: unsupported "
1321 "OID_802_11_CAPABILITY data");
1322 return;
1324 wpa_printf(MSG_DEBUG, "NDIS: Driver supports OID_802_11_CAPABILITY - "
1325 "NoOfPMKIDs %d NoOfAuthEncrPairs %d",
1326 (int) c->NoOfPMKIDs, (int) c->NoOfAuthEncryptPairSupported);
1327 drv->has_capability = 1;
1328 drv->no_of_pmkid = c->NoOfPMKIDs;
1329 for (i = 0; i < c->NoOfAuthEncryptPairSupported; i++) {
1330 NDIS_802_11_AUTHENTICATION_ENCRYPTION *ae;
1331 ae = &c->AuthenticationEncryptionSupported[i];
1332 if ((char *) (ae + 1) > buf + len) {
1333 wpa_printf(MSG_DEBUG, "NDIS: auth/encr pair list "
1334 "overflow");
1335 break;
1337 wpa_printf(MSG_MSGDUMP, "NDIS: %d - auth %d encr %d",
1338 i, (int) ae->AuthModeSupported,
1339 (int) ae->EncryptStatusSupported);
1340 switch (ae->AuthModeSupported) {
1341 case Ndis802_11AuthModeOpen:
1342 drv->capa.auth |= WPA_DRIVER_AUTH_OPEN;
1343 break;
1344 case Ndis802_11AuthModeShared:
1345 drv->capa.auth |= WPA_DRIVER_AUTH_SHARED;
1346 break;
1347 case Ndis802_11AuthModeWPA:
1348 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA;
1349 break;
1350 case Ndis802_11AuthModeWPAPSK:
1351 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
1352 break;
1353 case Ndis802_11AuthModeWPA2:
1354 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2;
1355 break;
1356 case Ndis802_11AuthModeWPA2PSK:
1357 drv->capa.key_mgmt |=
1358 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
1359 break;
1360 case Ndis802_11AuthModeWPANone:
1361 drv->capa.key_mgmt |=
1362 WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE;
1363 break;
1364 default:
1365 break;
1367 switch (ae->EncryptStatusSupported) {
1368 case Ndis802_11Encryption1Enabled:
1369 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40;
1370 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP104;
1371 break;
1372 case Ndis802_11Encryption2Enabled:
1373 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
1374 break;
1375 case Ndis802_11Encryption3Enabled:
1376 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
1377 break;
1378 default:
1379 break;
1383 wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x "
1384 "enc 0x%x auth 0x%x",
1385 drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth);
1389 static int wpa_driver_ndis_get_capa(void *priv, struct wpa_driver_capa *capa)
1391 struct wpa_driver_ndis_data *drv = priv;
1392 if (!drv->has_capability)
1393 return -1;
1394 memcpy(capa, &drv->capa, sizeof(*capa));
1395 return 0;
1399 static const char * wpa_driver_ndis_get_ifname(void *priv)
1401 struct wpa_driver_ndis_data *drv = priv;
1402 return drv->ifname;
1406 static const u8 * wpa_driver_ndis_get_mac_addr(void *priv)
1408 struct wpa_driver_ndis_data *drv = priv;
1409 return drv->own_addr;
1413 static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
1415 PTSTR names, pos, pos2;
1416 ULONG len;
1417 BOOLEAN res;
1418 const int MAX_ADAPTERS = 32;
1419 char *name[MAX_ADAPTERS];
1420 char *desc[MAX_ADAPTERS];
1421 int num_name, num_desc, i, found_name, found_desc;
1422 size_t dlen;
1424 wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
1425 PacketGetVersion());
1427 len = 8192;
1428 names = malloc(len);
1429 if (names == NULL)
1430 return -1;
1431 memset(names, 0, len);
1433 res = PacketGetAdapterNames(names, &len);
1434 if (!res && len > 8192) {
1435 free(names);
1436 names = malloc(len);
1437 if (names == NULL)
1438 return -1;
1439 memset(names, 0, len);
1440 res = PacketGetAdapterNames(names, &len);
1443 if (!res) {
1444 wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
1445 "(PacketGetAdapterNames)");
1446 free(names);
1447 return -1;
1450 /* wpa_hexdump_ascii(MSG_DEBUG, "NDIS: AdapterNames", names, len); */
1452 if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
1453 wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
1454 "UNICODE");
1455 /* Convert to ASCII */
1456 pos2 = pos = names;
1457 while (pos2 < names + len) {
1458 if (pos2[0] == '\0' && pos2[1] == '\0' &&
1459 pos2[2] == '\0' && pos2[3] == '\0') {
1460 pos2 += 4;
1461 break;
1463 *pos++ = pos2[0];
1464 pos2 += 2;
1466 memcpy(pos + 2, names, pos - names);
1467 pos += 2;
1468 } else
1469 pos = names;
1471 num_name = 0;
1472 while (pos < names + len) {
1473 name[num_name] = pos;
1474 while (*pos && pos < names + len)
1475 pos++;
1476 if (pos + 1 >= names + len) {
1477 free(names);
1478 return -1;
1480 pos++;
1481 num_name++;
1482 if (num_name >= MAX_ADAPTERS) {
1483 wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
1484 free(names);
1485 return -1;
1487 if (*pos == '\0') {
1488 wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found",
1489 num_name);
1490 pos++;
1491 break;
1495 num_desc = 0;
1496 while (pos < names + len) {
1497 desc[num_desc] = pos;
1498 while (*pos && pos < names + len)
1499 pos++;
1500 if (pos + 1 >= names + len) {
1501 free(names);
1502 return -1;
1504 pos++;
1505 num_desc++;
1506 if (num_desc >= MAX_ADAPTERS) {
1507 wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
1508 "descriptions");
1509 free(names);
1510 return -1;
1512 if (*pos == '\0') {
1513 wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions "
1514 "found", num_name);
1515 pos++;
1516 break;
1521 * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
1522 * descriptions. Fill in dummy descriptors to work around this.
1524 while (num_desc < num_name)
1525 desc[num_desc++] = "dummy description";
1527 if (num_name != num_desc) {
1528 wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
1529 "description counts (%d != %d)",
1530 num_name, num_desc);
1531 free(names);
1532 return -1;
1535 found_name = found_desc = -1;
1536 for (i = 0; i < num_name; i++) {
1537 wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s",
1538 i, name[i], desc[i]);
1539 if (found_name == -1 && strcmp(name[i], drv->ifname) == 0) {
1540 found_name = i;
1542 if (found_desc == -1 &&
1543 strncmp(desc[i], drv->ifname, strlen(drv->ifname)) == 0) {
1544 found_desc = i;
1548 if (found_name < 0 && found_desc >= 0) {
1549 wpa_printf(MSG_DEBUG, "NDIS: Matched interface '%s' based on "
1550 "description '%s'",
1551 name[found_desc], desc[found_desc]);
1552 found_name = found_desc;
1553 strncpy(drv->ifname, name[found_desc], sizeof(drv->ifname));
1556 if (found_name < 0) {
1557 wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'",
1558 drv->ifname);
1559 free(names);
1560 return -1;
1563 i = found_name;
1564 pos = strchr(desc[i], '(');
1565 if (pos) {
1566 dlen = pos - desc[i];
1567 pos--;
1568 if (pos > desc[i] && *pos == ' ')
1569 dlen--;
1570 } else {
1571 dlen = strlen(desc[i]);
1573 drv->adapter_desc = malloc(dlen + 1);
1574 if (drv->adapter_desc) {
1575 memcpy(drv->adapter_desc, desc[i], dlen);
1576 drv->adapter_desc[dlen] = '\0';
1579 free(names);
1581 if (drv->adapter_desc == NULL)
1582 return -1;
1584 wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'",
1585 drv->adapter_desc);
1587 return 0;
1591 static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
1593 struct wpa_driver_ndis_data *drv;
1594 u32 mode;
1596 drv = malloc(sizeof(*drv));
1597 if (drv == NULL)
1598 return NULL;
1599 memset(drv, 0, sizeof(*drv));
1600 drv->ctx = ctx;
1601 strncpy(drv->ifname, ifname, sizeof(drv->ifname));
1602 drv->event_sock = -1;
1604 if (wpa_driver_ndis_get_names(drv) < 0) {
1605 free(drv);
1606 return NULL;
1609 drv->adapter = PacketOpenAdapter(drv->ifname);
1610 if (drv->adapter == NULL) {
1611 wpa_printf(MSG_DEBUG, "NDIS: PacketOpenAdapter failed for "
1612 "'%s'", drv->ifname);
1613 free(drv);
1614 return NULL;
1617 if (ndis_get_oid(drv, OID_802_3_CURRENT_ADDRESS,
1618 drv->own_addr, ETH_ALEN) < 0) {
1619 wpa_printf(MSG_DEBUG, "NDIS: Get OID_802_3_CURRENT_ADDRESS "
1620 "failed");
1621 PacketCloseAdapter(drv->adapter);
1622 free(drv);
1623 return NULL;
1625 wpa_driver_ndis_get_capability(drv);
1627 /* Make sure that the driver does not have any obsolete PMKID entries.
1629 wpa_driver_ndis_flush_pmkid(drv);
1631 eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, drv, NULL);
1633 wpa_driver_register_event_cb(drv);
1635 /* Set mode here in case card was configured for ad-hoc mode
1636 * previously. */
1637 mode = Ndis802_11Infrastructure;
1638 if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
1639 (char *) &mode, sizeof(mode)) < 0) {
1640 wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
1641 "OID_802_11_INFRASTRUCTURE_MODE (%d)",
1642 (int) mode);
1643 /* Try to continue anyway */
1645 if (!drv->has_capability && drv->capa.enc == 0) {
1646 wpa_printf(MSG_DEBUG, "NDIS: Driver did not provide "
1647 "any wireless capabilities - assume it is "
1648 "a wired interface");
1649 drv->wired = 1;
1653 return drv;
1657 static void wpa_driver_ndis_deinit(void *priv)
1659 struct wpa_driver_ndis_data *drv = priv;
1660 eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
1661 wpa_driver_ndis_flush_pmkid(drv);
1662 wpa_driver_ndis_disconnect(drv);
1663 if (wpa_driver_ndis_radio_off(drv) < 0) {
1664 wpa_printf(MSG_DEBUG, "NDIS: failed to disassociate and turn "
1665 "radio off");
1667 if (drv->event_sock >= 0) {
1668 eloop_unregister_read_sock(drv->event_sock);
1669 close(drv->event_sock);
1671 if (drv->adapter)
1672 PacketCloseAdapter(drv->adapter);
1674 free(drv->adapter_desc);
1675 free(drv);
1679 const struct wpa_driver_ops wpa_driver_ndis_ops = {
1680 .name = "ndis",
1681 .desc = "Windows NDIS driver",
1682 .init = wpa_driver_ndis_init,
1683 .deinit = wpa_driver_ndis_deinit,
1684 .set_wpa = wpa_driver_ndis_set_wpa,
1685 .scan = wpa_driver_ndis_scan,
1686 .get_scan_results = wpa_driver_ndis_get_scan_results,
1687 .get_bssid = wpa_driver_ndis_get_bssid,
1688 .get_ssid = wpa_driver_ndis_get_ssid,
1689 .set_key = wpa_driver_ndis_set_key,
1690 .associate = wpa_driver_ndis_associate,
1691 .deauthenticate = wpa_driver_ndis_deauthenticate,
1692 .disassociate = wpa_driver_ndis_disassociate,
1693 .poll = wpa_driver_ndis_poll,
1694 .add_pmkid = wpa_driver_ndis_add_pmkid,
1695 .remove_pmkid = wpa_driver_ndis_remove_pmkid,
1696 .flush_pmkid = wpa_driver_ndis_flush_pmkid,
1697 .get_capa = wpa_driver_ndis_get_capa,
1698 .get_ifname = wpa_driver_ndis_get_ifname,
1699 .get_mac_addr = wpa_driver_ndis_get_mac_addr,