18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA Supplicant - Layer2 packet handling with Microsoft NDISUIO
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This implementation requires Windows specific event loop implementation,
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * i.e., eloop_win.c. In addition, the NDISUIO connection is shared with
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * driver_ndis.c, so only that driver interface can be used and
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * CONFIG_USE_NDISUIO must be defined.
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WinXP version of the code uses overlapped I/O and a single threaded design
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * with callback functions from I/O code. WinCE version uses a separate RX
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * thread that blocks on ReadFile() whenever the media status is connected.
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <winsock2.h>
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <ntddndis.h>
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef _WIN32_WCE
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <winioctl.h>
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <nuiouser.h>
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "l2_packet.h"
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef _WIN32_WCE
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* from nuiouser.h */
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define FSCTL_NDISUIO_BASE      FILE_DEVICE_NETWORK
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IOCTL_NDISUIO_SET_ETHER_TYPE \
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	_NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* From driver_ndis.c to shared the handle to NDISUIO */
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtHANDLE driver_ndis_get_ndisuio_handle(void);
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * NDISUIO supports filtering of only one ethertype at the time, so we must
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * fake support for two (EAPOL and RSN pre-auth) by switching to pre-auth
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * whenever wpa_supplicant is trying to pre-authenticate and then switching
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * back to EAPOL when pre-authentication has been completed.
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct l2_packet_data;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct l2_packet_ndisuio_global {
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int refcount;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned short first_proto;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct l2_packet_data *l2[2];
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef _WIN32_WCE
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HANDLE rx_thread;
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HANDLE stop_request;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HANDLE ready_for_read;
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HANDLE rx_processed;
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct l2_packet_ndisuio_global *l2_ndisuio_global = NULL;
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct l2_packet_data {
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char ifname[100];
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 own_addr[ETH_ALEN];
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void (*rx_callback)(void *ctx, const u8 *src_addr,
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *buf, size_t len);
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *rx_callback_ctx;
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     * rx_callback and l2_packet_send() */
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HANDLE rx_avail;
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef _WIN32_WCE
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	OVERLAPPED rx_overlapped;
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 rx_buf[1514];
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	DWORD rx_written;
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(addr, l2->own_addr, ETH_ALEN);
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   const u8 *buf, size_t len)
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BOOL res;
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	DWORD written;
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct l2_ethhdr *eth;
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef _WIN32_WCE
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	OVERLAPPED overlapped;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	OVERLAPPED *o;
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2 == NULL)
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef _WIN32_WCE
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	o = NULL;
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* _WIN32_WCE */
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&overlapped, 0, sizeof(overlapped));
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	o = &overlapped;
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2->l2_hdr) {
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res = WriteFile(driver_ndis_get_ndisuio_handle(), buf, len,
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				&written, o);
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t mlen = sizeof(*eth) + len;
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eth = os_malloc(mlen);
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (eth == NULL)
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eth->h_proto = htons(proto);
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(eth + 1, buf, len);
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res = WriteFile(driver_ndis_get_ndisuio_handle(), eth, mlen,
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				&written, o);
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(eth);
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!res) {
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		DWORD err = GetLastError();
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef _WIN32_WCE
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (err == ERROR_IO_PENDING) {
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "L2(NDISUIO): Wait for pending "
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "write to complete");
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res = GetOverlappedResult(
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				driver_ndis_get_ndisuio_handle(), &overlapped,
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				&written, TRUE);
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (!res) {
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "L2(NDISUIO): "
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "GetOverlappedResult failed: %d",
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   (int) GetLastError());
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "L2(NDISUIO): WriteFile failed: %d",
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (int) GetLastError());
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void l2_packet_callback(struct l2_packet_data *l2);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef _WIN32_WCE
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void l2_packet_rx_thread_try_read(struct l2_packet_data *l2)
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HANDLE handles[2];
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_MSGDUMP, "l2_packet_rx_thread: -> ReadFile");
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      sizeof(l2->rx_buf), &l2->rx_written, NULL)) {
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		DWORD err = GetLastError();
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: ReadFile failed: "
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%d", (int) err);
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * ReadFile on NDISUIO/WinCE returns ERROR_DEVICE_NOT_CONNECTED
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * error whenever the connection is not up. Yield the thread to
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * avoid triggering a busy loop. Connection event should stop
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * us from looping for long, but we need to allow enough CPU
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * for the main thread to process the media disconnection.
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		Sleep(100);
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Read %d byte packet",
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (int) l2->rx_written);
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Notify the main thread about the availability of a frame and wait
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * for the frame to be processed.
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SetEvent(l2->rx_avail);
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	handles[0] = l2_ndisuio_global->stop_request;
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	handles[1] = l2_ndisuio_global->rx_processed;
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ResetEvent(l2_ndisuio_global->rx_processed);
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic DWORD WINAPI l2_packet_rx_thread(LPVOID arg)
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct l2_packet_data *l2 = arg;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	DWORD res;
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HANDLE handles[2];
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int run = 1;
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread started");
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	handles[0] = l2_ndisuio_global->stop_request;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	handles[1] = l2_ndisuio_global->ready_for_read;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Unfortunately, NDISUIO on WinCE does not seem to support waiting
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * on the handle. There do not seem to be anything else that we could
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * wait for either. If one were to modify NDISUIO to set a named event
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * whenever packets are available, this event could be used here to
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * avoid having to poll for new packets or we could even move to use a
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * single threaded design.
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * In addition, NDISUIO on WinCE is returning
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * ERROR_DEVICE_NOT_CONNECTED whenever ReadFile() is attempted while
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * the adapter is not in connected state. For now, we are just using a
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * local event to allow ReadFile calls only after having received NDIS
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * media connect event. This event could be easily converted to handle
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * another event if the protocol driver is replaced with somewhat more
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * useful design.
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (l2_ndisuio_global && run) {
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (res) {
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WAIT_OBJECT_0:
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Received "
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "request to stop RX thread");
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			run = 0;
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WAIT_OBJECT_0 + 1:
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			l2_packet_rx_thread_try_read(l2);
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WAIT_FAILED:
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: "
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "WaitForMultipleObjects failed: %d",
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (int) GetLastError());
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			run = 0;
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread stopped");
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* _WIN32_WCE */
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int l2_ndisuio_start_read(struct l2_packet_data *l2, int recursive)
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&l2->rx_overlapped, 0, sizeof(l2->rx_overlapped));
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2->rx_overlapped.hEvent = l2->rx_avail;
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      sizeof(l2->rx_buf), &l2->rx_written, &l2->rx_overlapped))
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		DWORD err = GetLastError();
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (err != ERROR_IO_PENDING) {
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile failed: "
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "%d", (int) err);
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Once read is completed, l2_packet_rx_event() will be
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * called.
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile returned data "
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "without wait for completion");
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!recursive)
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			l2_packet_callback(l2);
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void l2_packet_callback(struct l2_packet_data *l2)
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *rx_buf, *rx_src;
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t rx_len;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct l2_ethhdr *ethhdr = (struct l2_ethhdr *) l2->rx_buf;
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "L2(NDISUIO): Read %d bytes",
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (int) l2->rx_written);
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2->l2_hdr || l2->rx_written < sizeof(*ethhdr)) {
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rx_buf = (u8 *) ethhdr;
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rx_len = l2->rx_written;
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rx_buf = (u8 *) (ethhdr + 1);
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rx_len = l2->rx_written - sizeof(*ethhdr);
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rx_src = ethhdr->h_source;
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len);
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef _WIN32_WCE
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2_ndisuio_start_read(l2, 1);
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void l2_packet_rx_event(void *eloop_data, void *user_data)
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct l2_packet_data *l2 = eloop_data;
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2_ndisuio_global)
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		l2 = l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1];
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ResetEvent(l2->rx_avail);
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef _WIN32_WCE
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!GetOverlappedResult(driver_ndis_get_ndisuio_handle(),
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 &l2->rx_overlapped, &l2->rx_written, FALSE)) {
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "L2(NDISUIO): GetOverlappedResult "
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "failed: %d", (int) GetLastError());
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2_packet_callback(l2);
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef _WIN32_WCE
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SetEvent(l2_ndisuio_global->rx_processed);
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int l2_ndisuio_set_ether_type(unsigned short protocol)
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	USHORT proto = htons(protocol);
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	DWORD written;
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     IOCTL_NDISUIO_SET_ETHER_TYPE, &proto,
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     sizeof(proto), NULL, 0, &written, NULL)) {
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "L2(NDISUIO): "
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "IOCTL_NDISUIO_SET_ETHER_TYPE failed: %d",
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (int) GetLastError());
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct l2_packet_data * l2_packet_init(
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *ifname, const u8 *own_addr, unsigned short protocol,
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void (*rx_callback)(void *ctx, const u8 *src_addr,
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *buf, size_t len),
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *rx_callback_ctx, int l2_hdr)
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct l2_packet_data *l2;
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2_ndisuio_global == NULL) {
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		l2_ndisuio_global = os_zalloc(sizeof(*l2_ndisuio_global));
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (l2_ndisuio_global == NULL)
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		l2_ndisuio_global->first_proto = protocol;
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2_ndisuio_global->refcount >= 2) {
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "L2(NDISUIO): Not more than two "
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "simultaneous connections allowed");
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2_ndisuio_global->refcount++;
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2 = os_zalloc(sizeof(struct l2_packet_data));
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2 == NULL)
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1] = l2;
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2->rx_callback = rx_callback;
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2->rx_callback_ctx = rx_callback_ctx;
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2->l2_hdr = l2_hdr;
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (own_addr)
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2_ndisuio_set_ether_type(protocol) < 0) {
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(l2);
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2_ndisuio_global->refcount > 1) {
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "L2(NDISUIO): Temporarily setting "
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "filtering ethertype to %04x", protocol);
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (l2_ndisuio_global->l2[0])
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			l2->rx_avail = l2_ndisuio_global->l2[0]->rx_avail;
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return l2;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2->rx_avail == NULL) {
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(l2);
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     l2_packet_rx_event, l2, NULL);
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef _WIN32_WCE
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2_ndisuio_global->stop_request = CreateEvent(NULL, TRUE, FALSE, NULL);
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * This event is being set based on media connect/disconnect
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * notifications in driver_ndis.c.
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2_ndisuio_global->ready_for_read =
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2_ndisuio_global->rx_processed = CreateEvent(NULL, TRUE, FALSE, NULL);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2_ndisuio_global->stop_request == NULL ||
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    l2_ndisuio_global->ready_for_read == NULL ||
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    l2_ndisuio_global->rx_processed == NULL) {
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (l2_ndisuio_global->stop_request) {
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			CloseHandle(l2_ndisuio_global->stop_request);
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			l2_ndisuio_global->stop_request = NULL;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (l2_ndisuio_global->ready_for_read) {
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			CloseHandle(l2_ndisuio_global->ready_for_read);
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			l2_ndisuio_global->ready_for_read = NULL;
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (l2_ndisuio_global->rx_processed) {
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			CloseHandle(l2_ndisuio_global->rx_processed);
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			l2_ndisuio_global->rx_processed = NULL;
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(l2);
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2_ndisuio_global->rx_thread = CreateThread(NULL, 0,
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						    l2_packet_rx_thread, l2, 0,
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						    NULL);
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2_ndisuio_global->rx_thread == NULL) {
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "L2(NDISUIO): Failed to create RX "
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "thread: %d", (int) GetLastError());
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CloseHandle(l2_ndisuio_global->stop_request);
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		l2_ndisuio_global->stop_request = NULL;
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(l2);
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* _WIN32_WCE */
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	l2_ndisuio_start_read(l2, 0);
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return l2;
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid l2_packet_deinit(struct l2_packet_data *l2)
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2 == NULL)
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (l2_ndisuio_global) {
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		l2_ndisuio_global->refcount--;
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		l2_ndisuio_global->l2[l2_ndisuio_global->refcount] = NULL;
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (l2_ndisuio_global->refcount) {
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "L2(NDISUIO): restore filtering "
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "ethertype to %04x",
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   l2_ndisuio_global->first_proto);
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			l2_ndisuio_set_ether_type(
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				l2_ndisuio_global->first_proto);
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef _WIN32_WCE
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "L2(NDISUIO): Waiting for RX thread to "
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "stop");
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SetEvent(l2_ndisuio_global->stop_request);
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Cancel pending ReadFile() in the RX thread (if we were still
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * connected at this point).
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     IOCTL_CANCEL_READ, NULL, 0, NULL, 0, NULL,
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     NULL)) {
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "L2(NDISUIO): IOCTL_CANCEL_READ "
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "failed: %d", (int) GetLastError());
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* RX thread will exit blocking ReadFile once NDISUIO
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * notices that the adapter is disconnected. */
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WaitForSingleObject(l2_ndisuio_global->rx_thread, INFINITE);
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread exited");
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CloseHandle(l2_ndisuio_global->rx_thread);
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CloseHandle(l2_ndisuio_global->stop_request);
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CloseHandle(l2_ndisuio_global->ready_for_read);
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CloseHandle(l2_ndisuio_global->rx_processed);
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(l2_ndisuio_global);
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		l2_ndisuio_global = NULL;
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef _WIN32_WCE
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CancelIo(driver_ndis_get_ndisuio_handle());
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* _WIN32_WCE */
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CloseHandle(l2->rx_avail);
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(l2);
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid l2_packet_notify_auth_start(struct l2_packet_data *l2)
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
517