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