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