1209139Srpaulo/* 2209139Srpaulo * WPA Supplicant - Layer2 packet handling with Microsoft NDISUIO 3209139Srpaulo * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi> 4209139Srpaulo * 5209139Srpaulo * This program is free software; you can redistribute it and/or modify 6209139Srpaulo * it under the terms of the GNU General Public License version 2 as 7209139Srpaulo * published by the Free Software Foundation. 8209139Srpaulo * 9209139Srpaulo * Alternatively, this software may be distributed under the terms of BSD 10209139Srpaulo * license. 11209139Srpaulo * 12209139Srpaulo * See README and COPYING for more details. 13209139Srpaulo * 14209139Srpaulo * This implementation requires Windows specific event loop implementation, 15209139Srpaulo * i.e., eloop_win.c. In addition, the NDISUIO connection is shared with 16209139Srpaulo * driver_ndis.c, so only that driver interface can be used and 17209139Srpaulo * CONFIG_USE_NDISUIO must be defined. 18209139Srpaulo * 19209139Srpaulo * WinXP version of the code uses overlapped I/O and a single threaded design 20209139Srpaulo * with callback functions from I/O code. WinCE version uses a separate RX 21209139Srpaulo * thread that blocks on ReadFile() whenever the media status is connected. 22209139Srpaulo */ 23209139Srpaulo 24209139Srpaulo#include "includes.h" 25209139Srpaulo#include <winsock2.h> 26209139Srpaulo#include <ntddndis.h> 27209139Srpaulo 28209139Srpaulo#ifdef _WIN32_WCE 29209139Srpaulo#include <winioctl.h> 30209139Srpaulo#include <nuiouser.h> 31209139Srpaulo#endif /* _WIN32_WCE */ 32209139Srpaulo 33209139Srpaulo#include "common.h" 34209139Srpaulo#include "eloop.h" 35209139Srpaulo#include "l2_packet.h" 36209139Srpaulo 37209139Srpaulo#ifndef _WIN32_WCE 38209139Srpaulo/* from nuiouser.h */ 39209139Srpaulo#define FSCTL_NDISUIO_BASE FILE_DEVICE_NETWORK 40209139Srpaulo#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \ 41209139Srpaulo CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access) 42209139Srpaulo#define IOCTL_NDISUIO_SET_ETHER_TYPE \ 43209139Srpaulo _NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \ 44209139Srpaulo FILE_READ_ACCESS | FILE_WRITE_ACCESS) 45209139Srpaulo#endif /* _WIN32_WCE */ 46209139Srpaulo 47209139Srpaulo/* From driver_ndis.c to shared the handle to NDISUIO */ 48209139SrpauloHANDLE driver_ndis_get_ndisuio_handle(void); 49209139Srpaulo 50209139Srpaulo/* 51209139Srpaulo * NDISUIO supports filtering of only one ethertype at the time, so we must 52209139Srpaulo * fake support for two (EAPOL and RSN pre-auth) by switching to pre-auth 53209139Srpaulo * whenever wpa_supplicant is trying to pre-authenticate and then switching 54209139Srpaulo * back to EAPOL when pre-authentication has been completed. 55209139Srpaulo */ 56209139Srpaulo 57209139Srpaulostruct l2_packet_data; 58209139Srpaulo 59209139Srpaulostruct l2_packet_ndisuio_global { 60209139Srpaulo int refcount; 61209139Srpaulo unsigned short first_proto; 62209139Srpaulo struct l2_packet_data *l2[2]; 63209139Srpaulo#ifdef _WIN32_WCE 64209139Srpaulo HANDLE rx_thread; 65209139Srpaulo HANDLE stop_request; 66209139Srpaulo HANDLE ready_for_read; 67209139Srpaulo HANDLE rx_processed; 68209139Srpaulo#endif /* _WIN32_WCE */ 69209139Srpaulo}; 70209139Srpaulo 71209139Srpaulostatic struct l2_packet_ndisuio_global *l2_ndisuio_global = NULL; 72209139Srpaulo 73209139Srpaulostruct l2_packet_data { 74209139Srpaulo char ifname[100]; 75209139Srpaulo u8 own_addr[ETH_ALEN]; 76209139Srpaulo void (*rx_callback)(void *ctx, const u8 *src_addr, 77209139Srpaulo const u8 *buf, size_t len); 78209139Srpaulo void *rx_callback_ctx; 79209139Srpaulo int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to 80209139Srpaulo * rx_callback and l2_packet_send() */ 81209139Srpaulo HANDLE rx_avail; 82209139Srpaulo#ifndef _WIN32_WCE 83209139Srpaulo OVERLAPPED rx_overlapped; 84209139Srpaulo#endif /* _WIN32_WCE */ 85209139Srpaulo u8 rx_buf[1514]; 86209139Srpaulo DWORD rx_written; 87209139Srpaulo}; 88209139Srpaulo 89209139Srpaulo 90209139Srpauloint l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) 91209139Srpaulo{ 92209139Srpaulo os_memcpy(addr, l2->own_addr, ETH_ALEN); 93209139Srpaulo return 0; 94209139Srpaulo} 95209139Srpaulo 96209139Srpaulo 97209139Srpauloint l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, 98209139Srpaulo const u8 *buf, size_t len) 99209139Srpaulo{ 100209139Srpaulo BOOL res; 101209139Srpaulo DWORD written; 102209139Srpaulo struct l2_ethhdr *eth; 103209139Srpaulo#ifndef _WIN32_WCE 104209139Srpaulo OVERLAPPED overlapped; 105209139Srpaulo#endif /* _WIN32_WCE */ 106209139Srpaulo OVERLAPPED *o; 107209139Srpaulo 108209139Srpaulo if (l2 == NULL) 109209139Srpaulo return -1; 110209139Srpaulo 111209139Srpaulo#ifdef _WIN32_WCE 112209139Srpaulo o = NULL; 113209139Srpaulo#else /* _WIN32_WCE */ 114209139Srpaulo os_memset(&overlapped, 0, sizeof(overlapped)); 115209139Srpaulo o = &overlapped; 116209139Srpaulo#endif /* _WIN32_WCE */ 117209139Srpaulo 118209139Srpaulo if (l2->l2_hdr) { 119209139Srpaulo res = WriteFile(driver_ndis_get_ndisuio_handle(), buf, len, 120209139Srpaulo &written, o); 121209139Srpaulo } else { 122209139Srpaulo size_t mlen = sizeof(*eth) + len; 123209139Srpaulo eth = os_malloc(mlen); 124209139Srpaulo if (eth == NULL) 125209139Srpaulo return -1; 126209139Srpaulo 127209139Srpaulo os_memcpy(eth->h_dest, dst_addr, ETH_ALEN); 128209139Srpaulo os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN); 129209139Srpaulo eth->h_proto = htons(proto); 130209139Srpaulo os_memcpy(eth + 1, buf, len); 131209139Srpaulo res = WriteFile(driver_ndis_get_ndisuio_handle(), eth, mlen, 132209139Srpaulo &written, o); 133209139Srpaulo os_free(eth); 134209139Srpaulo } 135209139Srpaulo 136209139Srpaulo if (!res) { 137209139Srpaulo DWORD err = GetLastError(); 138209139Srpaulo#ifndef _WIN32_WCE 139209139Srpaulo if (err == ERROR_IO_PENDING) { 140214734Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): Wait for pending " 141214734Srpaulo "write to complete"); 142214734Srpaulo res = GetOverlappedResult( 143214734Srpaulo driver_ndis_get_ndisuio_handle(), &overlapped, 144214734Srpaulo &written, TRUE); 145214734Srpaulo if (!res) { 146214734Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): " 147214734Srpaulo "GetOverlappedResult failed: %d", 148214734Srpaulo (int) GetLastError()); 149214734Srpaulo return -1; 150214734Srpaulo } 151209139Srpaulo return 0; 152209139Srpaulo } 153209139Srpaulo#endif /* _WIN32_WCE */ 154209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): WriteFile failed: %d", 155209139Srpaulo (int) GetLastError()); 156209139Srpaulo return -1; 157209139Srpaulo } 158209139Srpaulo 159209139Srpaulo return 0; 160209139Srpaulo} 161209139Srpaulo 162209139Srpaulo 163209139Srpaulostatic void l2_packet_callback(struct l2_packet_data *l2); 164209139Srpaulo 165209139Srpaulo#ifdef _WIN32_WCE 166209139Srpaulostatic void l2_packet_rx_thread_try_read(struct l2_packet_data *l2) 167209139Srpaulo{ 168209139Srpaulo HANDLE handles[2]; 169209139Srpaulo 170209139Srpaulo wpa_printf(MSG_MSGDUMP, "l2_packet_rx_thread: -> ReadFile"); 171209139Srpaulo if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf, 172209139Srpaulo sizeof(l2->rx_buf), &l2->rx_written, NULL)) { 173209139Srpaulo DWORD err = GetLastError(); 174209139Srpaulo wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: ReadFile failed: " 175209139Srpaulo "%d", (int) err); 176209139Srpaulo /* 177209139Srpaulo * ReadFile on NDISUIO/WinCE returns ERROR_DEVICE_NOT_CONNECTED 178209139Srpaulo * error whenever the connection is not up. Yield the thread to 179209139Srpaulo * avoid triggering a busy loop. Connection event should stop 180209139Srpaulo * us from looping for long, but we need to allow enough CPU 181209139Srpaulo * for the main thread to process the media disconnection. 182209139Srpaulo */ 183209139Srpaulo Sleep(100); 184209139Srpaulo return; 185209139Srpaulo } 186209139Srpaulo 187209139Srpaulo wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Read %d byte packet", 188209139Srpaulo (int) l2->rx_written); 189209139Srpaulo 190209139Srpaulo /* 191209139Srpaulo * Notify the main thread about the availability of a frame and wait 192209139Srpaulo * for the frame to be processed. 193209139Srpaulo */ 194209139Srpaulo SetEvent(l2->rx_avail); 195209139Srpaulo handles[0] = l2_ndisuio_global->stop_request; 196209139Srpaulo handles[1] = l2_ndisuio_global->rx_processed; 197209139Srpaulo WaitForMultipleObjects(2, handles, FALSE, INFINITE); 198209139Srpaulo ResetEvent(l2_ndisuio_global->rx_processed); 199209139Srpaulo} 200209139Srpaulo 201209139Srpaulo 202209139Srpaulostatic DWORD WINAPI l2_packet_rx_thread(LPVOID arg) 203209139Srpaulo{ 204209139Srpaulo struct l2_packet_data *l2 = arg; 205209139Srpaulo DWORD res; 206209139Srpaulo HANDLE handles[2]; 207209139Srpaulo int run = 1; 208209139Srpaulo 209209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread started"); 210209139Srpaulo handles[0] = l2_ndisuio_global->stop_request; 211209139Srpaulo handles[1] = l2_ndisuio_global->ready_for_read; 212209139Srpaulo 213209139Srpaulo /* 214209139Srpaulo * Unfortunately, NDISUIO on WinCE does not seem to support waiting 215209139Srpaulo * on the handle. There do not seem to be anything else that we could 216209139Srpaulo * wait for either. If one were to modify NDISUIO to set a named event 217209139Srpaulo * whenever packets are available, this event could be used here to 218209139Srpaulo * avoid having to poll for new packets or we could even move to use a 219209139Srpaulo * single threaded design. 220209139Srpaulo * 221209139Srpaulo * In addition, NDISUIO on WinCE is returning 222209139Srpaulo * ERROR_DEVICE_NOT_CONNECTED whenever ReadFile() is attempted while 223209139Srpaulo * the adapter is not in connected state. For now, we are just using a 224209139Srpaulo * local event to allow ReadFile calls only after having received NDIS 225209139Srpaulo * media connect event. This event could be easily converted to handle 226209139Srpaulo * another event if the protocol driver is replaced with somewhat more 227209139Srpaulo * useful design. 228209139Srpaulo */ 229209139Srpaulo 230209139Srpaulo while (l2_ndisuio_global && run) { 231209139Srpaulo res = WaitForMultipleObjects(2, handles, FALSE, INFINITE); 232209139Srpaulo switch (res) { 233209139Srpaulo case WAIT_OBJECT_0: 234209139Srpaulo wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Received " 235209139Srpaulo "request to stop RX thread"); 236209139Srpaulo run = 0; 237209139Srpaulo break; 238209139Srpaulo case WAIT_OBJECT_0 + 1: 239209139Srpaulo l2_packet_rx_thread_try_read(l2); 240209139Srpaulo break; 241209139Srpaulo case WAIT_FAILED: 242209139Srpaulo default: 243209139Srpaulo wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: " 244209139Srpaulo "WaitForMultipleObjects failed: %d", 245209139Srpaulo (int) GetLastError()); 246209139Srpaulo run = 0; 247209139Srpaulo break; 248209139Srpaulo } 249209139Srpaulo } 250209139Srpaulo 251209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread stopped"); 252209139Srpaulo 253209139Srpaulo return 0; 254209139Srpaulo} 255209139Srpaulo#else /* _WIN32_WCE */ 256209139Srpaulostatic int l2_ndisuio_start_read(struct l2_packet_data *l2, int recursive) 257209139Srpaulo{ 258209139Srpaulo os_memset(&l2->rx_overlapped, 0, sizeof(l2->rx_overlapped)); 259209139Srpaulo l2->rx_overlapped.hEvent = l2->rx_avail; 260209139Srpaulo if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf, 261209139Srpaulo sizeof(l2->rx_buf), &l2->rx_written, &l2->rx_overlapped)) 262209139Srpaulo { 263209139Srpaulo DWORD err = GetLastError(); 264209139Srpaulo if (err != ERROR_IO_PENDING) { 265209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile failed: " 266209139Srpaulo "%d", (int) err); 267209139Srpaulo return -1; 268209139Srpaulo } 269209139Srpaulo /* 270209139Srpaulo * Once read is completed, l2_packet_rx_event() will be 271209139Srpaulo * called. 272209139Srpaulo */ 273209139Srpaulo } else { 274209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile returned data " 275209139Srpaulo "without wait for completion"); 276209139Srpaulo if (!recursive) 277209139Srpaulo l2_packet_callback(l2); 278209139Srpaulo } 279209139Srpaulo 280209139Srpaulo return 0; 281209139Srpaulo} 282209139Srpaulo#endif /* _WIN32_WCE */ 283209139Srpaulo 284209139Srpaulo 285209139Srpaulostatic void l2_packet_callback(struct l2_packet_data *l2) 286209139Srpaulo{ 287209139Srpaulo const u8 *rx_buf, *rx_src; 288209139Srpaulo size_t rx_len; 289209139Srpaulo struct l2_ethhdr *ethhdr = (struct l2_ethhdr *) l2->rx_buf; 290209139Srpaulo 291209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): Read %d bytes", 292209139Srpaulo (int) l2->rx_written); 293209139Srpaulo 294209139Srpaulo if (l2->l2_hdr || l2->rx_written < sizeof(*ethhdr)) { 295209139Srpaulo rx_buf = (u8 *) ethhdr; 296209139Srpaulo rx_len = l2->rx_written; 297209139Srpaulo } else { 298209139Srpaulo rx_buf = (u8 *) (ethhdr + 1); 299209139Srpaulo rx_len = l2->rx_written - sizeof(*ethhdr); 300209139Srpaulo } 301209139Srpaulo rx_src = ethhdr->h_source; 302209139Srpaulo 303209139Srpaulo l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len); 304209139Srpaulo#ifndef _WIN32_WCE 305209139Srpaulo l2_ndisuio_start_read(l2, 1); 306209139Srpaulo#endif /* _WIN32_WCE */ 307209139Srpaulo} 308209139Srpaulo 309209139Srpaulo 310209139Srpaulostatic void l2_packet_rx_event(void *eloop_data, void *user_data) 311209139Srpaulo{ 312209139Srpaulo struct l2_packet_data *l2 = eloop_data; 313209139Srpaulo 314209139Srpaulo if (l2_ndisuio_global) 315209139Srpaulo l2 = l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1]; 316209139Srpaulo 317209139Srpaulo ResetEvent(l2->rx_avail); 318209139Srpaulo 319209139Srpaulo#ifndef _WIN32_WCE 320209139Srpaulo if (!GetOverlappedResult(driver_ndis_get_ndisuio_handle(), 321209139Srpaulo &l2->rx_overlapped, &l2->rx_written, FALSE)) { 322209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): GetOverlappedResult " 323209139Srpaulo "failed: %d", (int) GetLastError()); 324209139Srpaulo return; 325209139Srpaulo } 326209139Srpaulo#endif /* _WIN32_WCE */ 327209139Srpaulo 328209139Srpaulo l2_packet_callback(l2); 329209139Srpaulo 330209139Srpaulo#ifdef _WIN32_WCE 331209139Srpaulo SetEvent(l2_ndisuio_global->rx_processed); 332209139Srpaulo#endif /* _WIN32_WCE */ 333209139Srpaulo} 334209139Srpaulo 335209139Srpaulo 336209139Srpaulostatic int l2_ndisuio_set_ether_type(unsigned short protocol) 337209139Srpaulo{ 338209139Srpaulo USHORT proto = htons(protocol); 339209139Srpaulo DWORD written; 340209139Srpaulo 341209139Srpaulo if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(), 342209139Srpaulo IOCTL_NDISUIO_SET_ETHER_TYPE, &proto, 343209139Srpaulo sizeof(proto), NULL, 0, &written, NULL)) { 344209139Srpaulo wpa_printf(MSG_ERROR, "L2(NDISUIO): " 345209139Srpaulo "IOCTL_NDISUIO_SET_ETHER_TYPE failed: %d", 346209139Srpaulo (int) GetLastError()); 347209139Srpaulo return -1; 348209139Srpaulo } 349209139Srpaulo 350209139Srpaulo return 0; 351209139Srpaulo} 352209139Srpaulo 353209139Srpaulo 354209139Srpaulostruct l2_packet_data * l2_packet_init( 355209139Srpaulo const char *ifname, const u8 *own_addr, unsigned short protocol, 356209139Srpaulo void (*rx_callback)(void *ctx, const u8 *src_addr, 357209139Srpaulo const u8 *buf, size_t len), 358209139Srpaulo void *rx_callback_ctx, int l2_hdr) 359209139Srpaulo{ 360209139Srpaulo struct l2_packet_data *l2; 361209139Srpaulo 362209139Srpaulo if (l2_ndisuio_global == NULL) { 363209139Srpaulo l2_ndisuio_global = os_zalloc(sizeof(*l2_ndisuio_global)); 364209139Srpaulo if (l2_ndisuio_global == NULL) 365209139Srpaulo return NULL; 366209139Srpaulo l2_ndisuio_global->first_proto = protocol; 367209139Srpaulo } 368209139Srpaulo if (l2_ndisuio_global->refcount >= 2) { 369209139Srpaulo wpa_printf(MSG_ERROR, "L2(NDISUIO): Not more than two " 370209139Srpaulo "simultaneous connections allowed"); 371209139Srpaulo return NULL; 372209139Srpaulo } 373209139Srpaulo l2_ndisuio_global->refcount++; 374209139Srpaulo 375209139Srpaulo l2 = os_zalloc(sizeof(struct l2_packet_data)); 376209139Srpaulo if (l2 == NULL) 377209139Srpaulo return NULL; 378209139Srpaulo l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1] = l2; 379209139Srpaulo 380209139Srpaulo os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); 381209139Srpaulo l2->rx_callback = rx_callback; 382209139Srpaulo l2->rx_callback_ctx = rx_callback_ctx; 383209139Srpaulo l2->l2_hdr = l2_hdr; 384209139Srpaulo 385209139Srpaulo if (own_addr) 386209139Srpaulo os_memcpy(l2->own_addr, own_addr, ETH_ALEN); 387209139Srpaulo 388209139Srpaulo if (l2_ndisuio_set_ether_type(protocol) < 0) { 389209139Srpaulo os_free(l2); 390209139Srpaulo return NULL; 391209139Srpaulo } 392209139Srpaulo 393209139Srpaulo if (l2_ndisuio_global->refcount > 1) { 394209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): Temporarily setting " 395209139Srpaulo "filtering ethertype to %04x", protocol); 396209139Srpaulo if (l2_ndisuio_global->l2[0]) 397209139Srpaulo l2->rx_avail = l2_ndisuio_global->l2[0]->rx_avail; 398209139Srpaulo return l2; 399209139Srpaulo } 400209139Srpaulo 401209139Srpaulo l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL); 402209139Srpaulo if (l2->rx_avail == NULL) { 403209139Srpaulo os_free(l2); 404209139Srpaulo return NULL; 405209139Srpaulo } 406209139Srpaulo 407209139Srpaulo eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail), 408209139Srpaulo l2_packet_rx_event, l2, NULL); 409209139Srpaulo 410209139Srpaulo#ifdef _WIN32_WCE 411209139Srpaulo l2_ndisuio_global->stop_request = CreateEvent(NULL, TRUE, FALSE, NULL); 412209139Srpaulo /* 413209139Srpaulo * This event is being set based on media connect/disconnect 414209139Srpaulo * notifications in driver_ndis.c. 415209139Srpaulo */ 416209139Srpaulo l2_ndisuio_global->ready_for_read = 417209139Srpaulo CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected")); 418209139Srpaulo l2_ndisuio_global->rx_processed = CreateEvent(NULL, TRUE, FALSE, NULL); 419209139Srpaulo if (l2_ndisuio_global->stop_request == NULL || 420209139Srpaulo l2_ndisuio_global->ready_for_read == NULL || 421209139Srpaulo l2_ndisuio_global->rx_processed == NULL) { 422209139Srpaulo if (l2_ndisuio_global->stop_request) { 423209139Srpaulo CloseHandle(l2_ndisuio_global->stop_request); 424209139Srpaulo l2_ndisuio_global->stop_request = NULL; 425209139Srpaulo } 426209139Srpaulo if (l2_ndisuio_global->ready_for_read) { 427209139Srpaulo CloseHandle(l2_ndisuio_global->ready_for_read); 428209139Srpaulo l2_ndisuio_global->ready_for_read = NULL; 429209139Srpaulo } 430209139Srpaulo if (l2_ndisuio_global->rx_processed) { 431209139Srpaulo CloseHandle(l2_ndisuio_global->rx_processed); 432209139Srpaulo l2_ndisuio_global->rx_processed = NULL; 433209139Srpaulo } 434209139Srpaulo eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail)); 435209139Srpaulo os_free(l2); 436209139Srpaulo return NULL; 437209139Srpaulo } 438209139Srpaulo 439209139Srpaulo l2_ndisuio_global->rx_thread = CreateThread(NULL, 0, 440209139Srpaulo l2_packet_rx_thread, l2, 0, 441209139Srpaulo NULL); 442209139Srpaulo if (l2_ndisuio_global->rx_thread == NULL) { 443209139Srpaulo wpa_printf(MSG_INFO, "L2(NDISUIO): Failed to create RX " 444209139Srpaulo "thread: %d", (int) GetLastError()); 445209139Srpaulo eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail)); 446209139Srpaulo CloseHandle(l2_ndisuio_global->stop_request); 447209139Srpaulo l2_ndisuio_global->stop_request = NULL; 448209139Srpaulo os_free(l2); 449209139Srpaulo return NULL; 450209139Srpaulo } 451209139Srpaulo#else /* _WIN32_WCE */ 452209139Srpaulo l2_ndisuio_start_read(l2, 0); 453209139Srpaulo#endif /* _WIN32_WCE */ 454209139Srpaulo 455209139Srpaulo return l2; 456209139Srpaulo} 457209139Srpaulo 458209139Srpaulo 459209139Srpaulovoid l2_packet_deinit(struct l2_packet_data *l2) 460209139Srpaulo{ 461209139Srpaulo if (l2 == NULL) 462209139Srpaulo return; 463209139Srpaulo 464209139Srpaulo if (l2_ndisuio_global) { 465209139Srpaulo l2_ndisuio_global->refcount--; 466209139Srpaulo l2_ndisuio_global->l2[l2_ndisuio_global->refcount] = NULL; 467209139Srpaulo if (l2_ndisuio_global->refcount) { 468209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): restore filtering " 469209139Srpaulo "ethertype to %04x", 470209139Srpaulo l2_ndisuio_global->first_proto); 471209139Srpaulo l2_ndisuio_set_ether_type( 472209139Srpaulo l2_ndisuio_global->first_proto); 473209139Srpaulo return; 474209139Srpaulo } 475209139Srpaulo 476209139Srpaulo#ifdef _WIN32_WCE 477209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): Waiting for RX thread to " 478209139Srpaulo "stop"); 479209139Srpaulo SetEvent(l2_ndisuio_global->stop_request); 480209139Srpaulo /* 481209139Srpaulo * Cancel pending ReadFile() in the RX thread (if we were still 482209139Srpaulo * connected at this point). 483209139Srpaulo */ 484209139Srpaulo if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(), 485209139Srpaulo IOCTL_CANCEL_READ, NULL, 0, NULL, 0, NULL, 486209139Srpaulo NULL)) { 487209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): IOCTL_CANCEL_READ " 488209139Srpaulo "failed: %d", (int) GetLastError()); 489209139Srpaulo /* RX thread will exit blocking ReadFile once NDISUIO 490209139Srpaulo * notices that the adapter is disconnected. */ 491209139Srpaulo } 492209139Srpaulo WaitForSingleObject(l2_ndisuio_global->rx_thread, INFINITE); 493209139Srpaulo wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread exited"); 494209139Srpaulo CloseHandle(l2_ndisuio_global->rx_thread); 495209139Srpaulo CloseHandle(l2_ndisuio_global->stop_request); 496209139Srpaulo CloseHandle(l2_ndisuio_global->ready_for_read); 497209139Srpaulo CloseHandle(l2_ndisuio_global->rx_processed); 498209139Srpaulo#endif /* _WIN32_WCE */ 499209139Srpaulo 500209139Srpaulo os_free(l2_ndisuio_global); 501209139Srpaulo l2_ndisuio_global = NULL; 502209139Srpaulo } 503209139Srpaulo 504209139Srpaulo#ifndef _WIN32_WCE 505209139Srpaulo CancelIo(driver_ndis_get_ndisuio_handle()); 506209139Srpaulo#endif /* _WIN32_WCE */ 507209139Srpaulo 508209139Srpaulo eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail)); 509209139Srpaulo CloseHandle(l2->rx_avail); 510209139Srpaulo os_free(l2); 511209139Srpaulo} 512209139Srpaulo 513209139Srpaulo 514209139Srpauloint l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) 515209139Srpaulo{ 516209139Srpaulo return -1; 517209139Srpaulo} 518209139Srpaulo 519209139Srpaulo 520209139Srpaulovoid l2_packet_notify_auth_start(struct l2_packet_data *l2) 521209139Srpaulo{ 522209139Srpaulo} 523