⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 l2_packet_ndis.c

📁 最新的Host AP 新添加了许多pcmcia 的驱动
💻 C
字号:
/* * WPA Supplicant - Layer2 packet handling with Microsoft NDISUIO * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This implementation requires Windows specific event loop implementation, * i.e., eloop_win.c. In addition, the NDISUIO connection is shared with * driver_ndis.c, so only that driver interface can be used and * CONFIG_USE_NDISUIO must be defined. * * WinXP version of the code uses overlapped I/O and a single threaded design * with callback functions from I/O code. WinCE version uses a separate RX * thread that blocks on ReadFile() whenever the media status is connected. */#include "includes.h"#include <winsock2.h>#include <ntddndis.h>#ifdef _WIN32_WCE#include <winioctl.h>#include <nuiouser.h>#endif /* _WIN32_WCE */#include "common.h"#include "eloop.h"#include "l2_packet.h"#ifndef _WIN32_WCE/* from nuiouser.h */#define FSCTL_NDISUIO_BASE      FILE_DEVICE_NETWORK#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \	CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)#define IOCTL_NDISUIO_SET_ETHER_TYPE \	_NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)#endif /* _WIN32_WCE *//* From driver_ndis.c to shared the handle to NDISUIO */HANDLE driver_ndis_get_ndisuio_handle(void);/* * NDISUIO supports filtering of only one ethertype at the time, so we must * fake support for two (EAPOL and RSN pre-auth) by switching to pre-auth * whenever wpa_supplicant is trying to pre-authenticate and then switching * back to EAPOL when pre-authentication has been completed. */struct l2_packet_data;struct l2_packet_ndisuio_global {	int refcount;	unsigned short first_proto;	struct l2_packet_data *l2[2];#ifdef _WIN32_WCE	HANDLE rx_thread;	HANDLE stop_request;	HANDLE ready_for_read;	HANDLE rx_processed;#endif /* _WIN32_WCE */};static struct l2_packet_ndisuio_global *l2_ndisuio_global = NULL;struct l2_packet_data {	char ifname[100];	u8 own_addr[ETH_ALEN];	void (*rx_callback)(void *ctx, const u8 *src_addr,			    const u8 *buf, size_t len);	void *rx_callback_ctx;	int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to		     * rx_callback and l2_packet_send() */	HANDLE rx_avail;#ifndef _WIN32_WCE	OVERLAPPED rx_overlapped;#endif /* _WIN32_WCE */	u8 rx_buf[1514];	DWORD rx_written;};int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr){	os_memcpy(addr, l2->own_addr, ETH_ALEN);	return 0;}int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,		   const u8 *buf, size_t len){	BOOL res;	DWORD written;	struct l2_ethhdr *eth;#ifndef _WIN32_WCE	OVERLAPPED overlapped;#endif /* _WIN32_WCE */	OVERLAPPED *o;	if (l2 == NULL)		return -1;#ifdef _WIN32_WCE	o = NULL;#else /* _WIN32_WCE */	os_memset(&overlapped, 0, sizeof(overlapped));	o = &overlapped;#endif /* _WIN32_WCE */	if (l2->l2_hdr) {		res = WriteFile(driver_ndis_get_ndisuio_handle(), buf, len,				&written, o);	} else {		size_t mlen = sizeof(*eth) + len;		eth = os_malloc(mlen);		if (eth == NULL)			return -1;		os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);		os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);		eth->h_proto = htons(proto);		os_memcpy(eth + 1, buf, len);		res = WriteFile(driver_ndis_get_ndisuio_handle(), eth, mlen,				&written, o);		os_free(eth);	}	if (!res) {		DWORD err = GetLastError();#ifndef _WIN32_WCE		if (err == ERROR_IO_PENDING) {			/* For now, just assume that the packet will be sent in			 * time before the next write happens. This could be			 * cleaned up at some point to actually wait for			 * completion before starting new writes.			 */			return 0;		}#endif /* _WIN32_WCE */		wpa_printf(MSG_DEBUG, "L2(NDISUIO): WriteFile failed: %d",			   (int) GetLastError());		return -1;	}	return 0;}static void l2_packet_callback(struct l2_packet_data *l2);#ifdef _WIN32_WCEstatic void l2_packet_rx_thread_try_read(struct l2_packet_data *l2){	HANDLE handles[2];	wpa_printf(MSG_MSGDUMP, "l2_packet_rx_thread: -> ReadFile");	if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,		      sizeof(l2->rx_buf), &l2->rx_written, NULL)) {		DWORD err = GetLastError();		wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: ReadFile failed: "			   "%d", (int) err);		/*		 * ReadFile on NDISUIO/WinCE returns ERROR_DEVICE_NOT_CONNECTED		 * error whenever the connection is not up. Yield the thread to		 * avoid triggering a busy loop. Connection event should stop		 * us from looping for long, but we need to allow enough CPU		 * for the main thread to process the media disconnection.		 */		Sleep(100);		return;	}	wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Read %d byte packet",		   (int) l2->rx_written);	/*	 * Notify the main thread about the availability of a frame and wait	 * for the frame to be processed.	 */	SetEvent(l2->rx_avail);	handles[0] = l2_ndisuio_global->stop_request;	handles[1] = l2_ndisuio_global->rx_processed;	WaitForMultipleObjects(2, handles, FALSE, INFINITE);	ResetEvent(l2_ndisuio_global->rx_processed);}static DWORD WINAPI l2_packet_rx_thread(LPVOID arg){	struct l2_packet_data *l2 = arg;	DWORD res;	HANDLE handles[2];	int run = 1;	wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread started");	handles[0] = l2_ndisuio_global->stop_request;	handles[1] = l2_ndisuio_global->ready_for_read;	/*	 * Unfortunately, NDISUIO on WinCE does not seem to support waiting	 * on the handle. There do not seem to be anything else that we could	 * wait for either. If one were to modify NDISUIO to set a named event	 * whenever packets are available, this event could be used here to	 * avoid having to poll for new packets or we could even move to use a	 * single threaded design.	 *	 * In addition, NDISUIO on WinCE is returning	 * ERROR_DEVICE_NOT_CONNECTED whenever ReadFile() is attempted while	 * the adapter is not in connected state. For now, we are just using a	 * local event to allow ReadFile calls only after having received NDIS	 * media connect event. This event could be easily converted to handle	 * another event if the protocol driver is replaced with somewhat more	 * useful design.	 */	while (l2_ndisuio_global && run) {		res = WaitForMultipleObjects(2, handles, FALSE, INFINITE);		switch (res) {		case WAIT_OBJECT_0:			wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Received "				   "request to stop RX thread");			run = 0;			break;		case WAIT_OBJECT_0 + 1:			l2_packet_rx_thread_try_read(l2);			break;		case WAIT_FAILED:		default:			wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: "				   "WaitForMultipleObjects failed: %d",				   (int) GetLastError());			run = 0;			break;		}	}	wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread stopped");	return 0;}#else /* _WIN32_WCE */static int l2_ndisuio_start_read(struct l2_packet_data *l2, int recursive){	os_memset(&l2->rx_overlapped, 0, sizeof(l2->rx_overlapped));	l2->rx_overlapped.hEvent = l2->rx_avail;	if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,		      sizeof(l2->rx_buf), &l2->rx_written, &l2->rx_overlapped))	{		DWORD err = GetLastError();		if (err != ERROR_IO_PENDING) {			wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile failed: "				   "%d", (int) err);			return -1;		}		/*		 * Once read is completed, l2_packet_rx_event() will be		 * called.		 */	} else {		wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile returned data "			   "without wait for completion");		if (!recursive)			l2_packet_callback(l2);	}	return 0;}#endif /* _WIN32_WCE */static void l2_packet_callback(struct l2_packet_data *l2){	const u8 *rx_buf, *rx_src;	size_t rx_len;	struct l2_ethhdr *ethhdr = (struct l2_ethhdr *) l2->rx_buf;	wpa_printf(MSG_DEBUG, "L2(NDISUIO): Read %d bytes",		   (int) l2->rx_written);	if (l2->l2_hdr || l2->rx_written < sizeof(*ethhdr)) {		rx_buf = (u8 *) ethhdr;		rx_len = l2->rx_written;	} else {		rx_buf = (u8 *) (ethhdr + 1);		rx_len = l2->rx_written - sizeof(*ethhdr);	}	rx_src = ethhdr->h_source;	l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len);#ifndef _WIN32_WCE	l2_ndisuio_start_read(l2, 1);#endif /* _WIN32_WCE */}static void l2_packet_rx_event(void *eloop_data, void *user_data){	struct l2_packet_data *l2 = eloop_data;	if (l2_ndisuio_global)		l2 = l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1];	ResetEvent(l2->rx_avail);#ifndef _WIN32_WCE	if (!GetOverlappedResult(driver_ndis_get_ndisuio_handle(),				 &l2->rx_overlapped, &l2->rx_written, FALSE)) {		wpa_printf(MSG_DEBUG, "L2(NDISUIO): GetOverlappedResult "			   "failed: %d", (int) GetLastError());		return;	}#endif /* _WIN32_WCE */	l2_packet_callback(l2);#ifdef _WIN32_WCE	SetEvent(l2_ndisuio_global->rx_processed);#endif /* _WIN32_WCE */}static int l2_ndisuio_set_ether_type(unsigned short protocol){	USHORT proto = htons(protocol);	DWORD written;	if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),			     IOCTL_NDISUIO_SET_ETHER_TYPE, &proto,			     sizeof(proto), NULL, 0, &written, NULL)) {		wpa_printf(MSG_ERROR, "L2(NDISUIO): "			   "IOCTL_NDISUIO_SET_ETHER_TYPE failed: %d",			   (int) GetLastError());		return -1;	}	return 0;}struct l2_packet_data * l2_packet_init(	const char *ifname, const u8 *own_addr, unsigned short protocol,	void (*rx_callback)(void *ctx, const u8 *src_addr,			    const u8 *buf, size_t len),	void *rx_callback_ctx, int l2_hdr){	struct l2_packet_data *l2;	if (l2_ndisuio_global == NULL) {		l2_ndisuio_global = os_zalloc(sizeof(*l2_ndisuio_global));		if (l2_ndisuio_global == NULL)			return NULL;		l2_ndisuio_global->first_proto = protocol;	}	if (l2_ndisuio_global->refcount >= 2) {		wpa_printf(MSG_ERROR, "L2(NDISUIO): Not more than two "			   "simultaneous connections allowed");		return NULL;	}	l2_ndisuio_global->refcount++;	l2 = os_zalloc(sizeof(struct l2_packet_data));	if (l2 == NULL)		return NULL;	l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1] = l2;	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));	l2->rx_callback = rx_callback;	l2->rx_callback_ctx = rx_callback_ctx;	l2->l2_hdr = l2_hdr;	if (own_addr)		os_memcpy(l2->own_addr, own_addr, ETH_ALEN);	if (l2_ndisuio_set_ether_type(protocol) < 0) {		os_free(l2);		return NULL;	}	if (l2_ndisuio_global->refcount > 1) {		wpa_printf(MSG_DEBUG, "L2(NDISUIO): Temporarily setting "			   "filtering ethertype to %04x", protocol);		if (l2_ndisuio_global->l2[0])			l2->rx_avail = l2_ndisuio_global->l2[0]->rx_avail;		return l2;	}	l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);	if (l2->rx_avail == NULL) {		os_free(l2);		return NULL;	}	eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),			     l2_packet_rx_event, l2, NULL);#ifdef _WIN32_WCE	l2_ndisuio_global->stop_request = CreateEvent(NULL, TRUE, FALSE, NULL);	/*	 * This event is being set based on media connect/disconnect	 * notifications in driver_ndis.c.	 */	l2_ndisuio_global->ready_for_read =		CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));	l2_ndisuio_global->rx_processed = CreateEvent(NULL, TRUE, FALSE, NULL);	if (l2_ndisuio_global->stop_request == NULL ||	    l2_ndisuio_global->ready_for_read == NULL ||	    l2_ndisuio_global->rx_processed == NULL) {		if (l2_ndisuio_global->stop_request) {			CloseHandle(l2_ndisuio_global->stop_request);			l2_ndisuio_global->stop_request = NULL;		}		if (l2_ndisuio_global->ready_for_read) {			CloseHandle(l2_ndisuio_global->ready_for_read);			l2_ndisuio_global->ready_for_read = NULL;		}		if (l2_ndisuio_global->rx_processed) {			CloseHandle(l2_ndisuio_global->rx_processed);			l2_ndisuio_global->rx_processed = NULL;		}		eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));		os_free(l2);		return NULL;	}	l2_ndisuio_global->rx_thread = CreateThread(NULL, 0,						    l2_packet_rx_thread, l2, 0,						    NULL);	if (l2_ndisuio_global->rx_thread == NULL) {		wpa_printf(MSG_INFO, "L2(NDISUIO): Failed to create RX "			   "thread: %d", (int) GetLastError());		eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));		CloseHandle(l2_ndisuio_global->stop_request);		l2_ndisuio_global->stop_request = NULL;		os_free(l2);		return NULL;	}#else /* _WIN32_WCE */	l2_ndisuio_start_read(l2, 0);#endif /* _WIN32_WCE */	return l2;}void l2_packet_deinit(struct l2_packet_data *l2){	if (l2 == NULL)		return;	if (l2_ndisuio_global) {		l2_ndisuio_global->refcount--;		l2_ndisuio_global->l2[l2_ndisuio_global->refcount] = NULL;		if (l2_ndisuio_global->refcount) {			wpa_printf(MSG_DEBUG, "L2(NDISUIO): restore filtering "				   "ethertype to %04x",				   l2_ndisuio_global->first_proto);			l2_ndisuio_set_ether_type(				l2_ndisuio_global->first_proto);			return;		}#ifdef _WIN32_WCE		wpa_printf(MSG_DEBUG, "L2(NDISUIO): Waiting for RX thread to "			   "stop");		SetEvent(l2_ndisuio_global->stop_request);		/*		 * Cancel pending ReadFile() in the RX thread (if we were still		 * connected at this point).		 */		if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),				     IOCTL_CANCEL_READ, NULL, 0, NULL, 0, NULL,				     NULL)) {			wpa_printf(MSG_DEBUG, "L2(NDISUIO): IOCTL_CANCEL_READ "				   "failed: %d", (int) GetLastError());			/* RX thread will exit blocking ReadFile once NDISUIO			 * notices that the adapter is disconnected. */		}		WaitForSingleObject(l2_ndisuio_global->rx_thread, INFINITE);		wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread exited");		CloseHandle(l2_ndisuio_global->rx_thread);		CloseHandle(l2_ndisuio_global->stop_request);		CloseHandle(l2_ndisuio_global->ready_for_read);		CloseHandle(l2_ndisuio_global->rx_processed);#endif /* _WIN32_WCE */		os_free(l2_ndisuio_global);		l2_ndisuio_global = NULL;	}#ifndef _WIN32_WCE	CancelIo(driver_ndis_get_ndisuio_handle());#endif /* _WIN32_WCE */	eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));	CloseHandle(l2->rx_avail);	os_free(l2);}int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len){	return -1;}void l2_packet_notify_auth_start(struct l2_packet_data *l2){}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -