cardif_windows.c
来自「linux 下通过802.1认证的安装包」· C语言 代码 · 共 2,063 行 · 第 1/5 页
C
2,063 行
/**
* Windows card interface implementation.
*
* Licensed under a dual GPL/BSD license. (See LICENSE file for more info.)
*
* \file cardif_windows.c
*
* \author chris@open1x.org
*
* $Id: cardif_windows.c,v 1.1.2.81 2008/01/29 18:31:52 chessing Exp $
* $Date: 2008/01/29 18:31:52 $
**/
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <winsock2.h>
#include <NtDDNdis.h>
// The nuiouser.h file is included with the Windows DDK. Please
// download the DDK and copy the file to the proper location.
#include "../../../vs2005/ndis_proto_driver/nuiouser.h"
#include "../../xsup_common.h"
#include "../../../lib/libxsupconfig/xsupconfig.h"
#include "../../../lib/libxsupconfig/xsupconfig_structs.h"
#include "../../context.h"
#include "../../config_ssid.h"
#include "cardif_windows.h"
#include "../cardif.h"
#include "../../xsup_debug.h"
#include "../../xsup_err.h"
#include "../../snmp.h"
#include "../../statemachine.h"
#include "../../wireless_sm.h"
#include "../../timer.h"
#include "../../event_core_win.h"
#include "../../interfaces.h"
#include "../../ipc_events.h"
#include "../../ipc_events_index.h"
#include "cardif_windows_wireless.h"
#include "cardif_windows_dot11.h"
#include "cardif_windows_wmi.h"
#include "wzc_ctrl.h"
#include "windows_eapol_ctrl.h"
#ifdef USE_EFENCE
#include <efence.h>
#endif
#ifndef ETH_P_EAPOL
#define ETH_P_EAPOL 0x888e
#endif
// This contains a pointer to the functions needed for wireless.
struct cardif_funcs *wireless = NULL;
// Store values about what state our interface was in before we start messing
// with it.
struct int_starting_data *startup;
// The device node we use to communicate with the protocol layer.
char NdisDev[] = "\\\\.\\\\Open1X";
/**
* \brief Issue a non-blocking IOCTL request to Windows. (And wait up to 7 seconds for an answer.)
*
* Since we opened the handle in non-blocking mode, we have to handle our ioctls in
* non-blocking mode as well. (Or, according to the Windows documentation, bad things
* can happen.) So, this is a "drop-in" replacement for the normal DeviceIoControl()
* function that blocks for up to 1 second waiting for a response.
*
* @param[in] hDevice A handle to the device that we want to execute the IOCTL
* against.
* @param[in] dwIoCtl A DWORD that specifies the IOCTL that we want to execute.
* @param[in] lpInBuf A pointer to a buffer that contains the data that the IOCTL
* being executed needs.
* @param[in] nInBufSiz The size of the buffer specified by lpInBuf.
* @param[out] lpOutBuf A pointer to a buffer that will contain the results from the
* IOCTL.
* @param[out] nOutBufSiz The size of the buffer specified by lpOutBuf.
* @param[out] lpBytesReturned A pointer to a DWORD that will contain the number of
* bytes returned by the IOCTL. (This will be the
* number of bytes in lpOutBuf that are valid.)
*
* \retval result One of the result codes returned by the call to WaitForSingleObjectEx().
**/
DWORD devioctl7(HANDLE hDevice, DWORD dwIoCtl, LPVOID lpInBuf, DWORD nInBufSiz,
LPVOID lpOutBuf, DWORD nOutBufSiz, LPDWORD lpBytesReturned)
{
OVERLAPPED ovr;
DWORD result;
HANDLE ioctlEvent = INVALID_HANDLE_VALUE;
if (hDevice == INVALID_HANDLE_VALUE)
{
debug_printf(DEBUG_NORMAL, "Invalid handle value passed in to %s()!\n", __FUNCTION__);
return WAIT_ABANDONED;
}
(*lpBytesReturned) = 0;
memset(&ovr, 0x00, sizeof(OVERLAPPED));
if (ioctlEvent == INVALID_HANDLE_VALUE)
{
ioctlEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
if (ioctlEvent == INVALID_HANDLE_VALUE)
{
debug_printf(DEBUG_NORMAL, "Couldn't create event handle!\n");
return 0xffffffff;
}
}
else
{
ResetEvent(ioctlEvent);
}
ovr.hEvent = ioctlEvent;
if (!DeviceIoControl(hDevice, dwIoCtl, lpInBuf, nInBufSiz, lpOutBuf,
nOutBufSiz, lpBytesReturned, &ovr))
{
if (GetLastError() != 997)
{
debug_printf(DEBUG_INT, "Couldn't do IOCTL.\n");
//printf("Couldn't do IOCTL!\n");
debug_printf(DEBUG_INT, "Error : %d\n", GetLastError());
CloseHandle(ioctlEvent);
return 0xffffffff;
}
}
result = WaitForSingleObjectEx(ioctlEvent, 7000, FALSE);
switch (result)
{
case WAIT_ABANDONED:
debug_printf(DEBUG_INT, "IOCTL returned WAIT_ABANDONED\n");
//printf("IOCTL return WAIT_ABANDONED!\n");
break;
case WAIT_IO_COMPLETION:
debug_printf(DEBUG_INT, "IOCTL returned WAIT_IO_COMPLETION\n");
//printf("IOCTL returned WAIT_IO_COMPLETION\n");
break;
case WAIT_OBJECT_0:
// Don't send any output here, to avoid cluttering the output.
//debug_printf(DEBUG_INT, "IOCTL returned WAIT_OBJECT_0\n");
break;
case WAIT_TIMEOUT:
debug_printf(DEBUG_INT, "IOCTL returned WAIT_TIMEOUT\n");
//printf("Timeout\n");
break;
case WAIT_FAILED:
debug_printf(DEBUG_INT, "IOCTL returned WAIT_FAILED\n");
//printf("Failed\n");
break;
default:
debug_printf(DEBUG_INT, "IOCTL returned UNKNOWN value!\n");
//printf("Unknown.\n");
break;
}
CloseHandle(ioctlEvent);
return result;
}
/**
* \brief Issue a non-blocking IOCTL request to Windows.
*
* Since we opened the handle in non-blocking mode, we have to handle our ioctls in
* non-blocking mode as well. (Or, according to the Windows documentation, bad things
* can happen.) So, this is a "drop-in" replacement for the normal DeviceIoControl()
* function that blocks for up to 1 second waiting for a response.
*
* @param[in] hDevice A handle to the device that we want to execute the IOCTL
* against.
* @param[in] dwIoCtl A DWORD that specifies the IOCTL that we want to execute.
* @param[in] lpInBuf A pointer to a buffer that contains the data that the IOCTL
* being executed needs.
* @param[in] nInBufSiz The size of the buffer specified by lpInBuf.
* @param[out] lpOutBuf A pointer to a buffer that will contain the results from the
* IOCTL.
* @param[out] nOutBufSiz The size of the buffer specified by lpOutBuf.
* @param[out] lpBytesReturned A pointer to a DWORD that will contain the number of
* bytes returned by the IOCTL. (This will be the
* number of bytes in lpOutBuf that are valid.)
*
* \retval result One of the result codes returned by the call to WaitForSingleObjectEx().
**/
DWORD devioctl(HANDLE hDevice, DWORD dwIoCtl, LPVOID lpInBuf, DWORD nInBufSiz,
LPVOID lpOutBuf, DWORD nOutBufSiz, LPDWORD lpBytesReturned)
{
OVERLAPPED ovr;
DWORD result;
HANDLE ioctlEvent = INVALID_HANDLE_VALUE;
if (hDevice == INVALID_HANDLE_VALUE)
{
debug_printf(DEBUG_NORMAL, "Invalid handle value passed in to %s()!\n", __FUNCTION__);
return WAIT_ABANDONED;
}
if (lpInBuf == NULL)
{
debug_printf(DEBUG_NORMAL, "Invalid buffer passed in to %s!\n", __FUNCTION__);
return WAIT_ABANDONED;
}
(*lpBytesReturned) = 0;
memset(&ovr, 0x00, sizeof(OVERLAPPED));
if (ioctlEvent == INVALID_HANDLE_VALUE)
{
ioctlEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
if (ioctlEvent == INVALID_HANDLE_VALUE)
{
debug_printf(DEBUG_NORMAL, "Couldn't create event handle!\n");
return 0xffffffff;
}
}
else
{
ResetEvent(ioctlEvent);
}
ovr.hEvent = ioctlEvent;
SetLastError(0); // Clear the last error so we don't get false positives.
if (!DeviceIoControl(hDevice, dwIoCtl, lpInBuf, nInBufSiz, lpOutBuf,
nOutBufSiz, lpBytesReturned, &ovr))
{
if (GetLastError() != 997)
{
debug_printf(DEBUG_INT, "Couldn't do IOCTL %04X. Error : %d\n", dwIoCtl, GetLastError());
CloseHandle(ioctlEvent);
return 0xffffffff;
}
}
result = WaitForSingleObjectEx(ioctlEvent, 1000, FALSE);
switch (result)
{
case WAIT_ABANDONED:
debug_printf(DEBUG_INT, "IOCTL returned WAIT_ABANDONED\n");
//printf("IOCTL return WAIT_ABANDONED!\n");
break;
case WAIT_IO_COMPLETION:
debug_printf(DEBUG_INT, "IOCTL returned WAIT_IO_COMPLETION\n");
//printf("IOCTL returned WAIT_IO_COMPLETION\n");
break;
case WAIT_OBJECT_0:
// Don't send any output here, to avoid cluttering the output.
//debug_printf(DEBUG_INT, "IOCTL returned WAIT_OBJECT_0\n");
break;
case WAIT_TIMEOUT:
debug_printf(DEBUG_INT, "IOCTL returned WAIT_TIMEOUT\n");
//printf("Timeout\n");
break;
case WAIT_FAILED:
debug_printf(DEBUG_INT, "IOCTL returned WAIT_FAILED\n");
//printf("Failed\n");
break;
default:
debug_printf(DEBUG_INT, "IOCTL returned UNKNOWN value!\n");
//printf("Unknown.\n");
break;
}
CloseHandle(ioctlEvent);
return result;
}
/**
* \brief Issue an IOCTL, and block until there is a result.
*
* A simplified IOCTL call that blocks until it has a result. Rather than returning
* a detailed status value (like devioctl() does), it just returns true/false depending
* on if the call was successful, or not.
*
* @param[in] hDevice A handle to the device that we want to execute the IOCTL
* against.
* @param[in] dwIoCtl A DWORD that specifies the IOCTL that we want to execute.
* @param[in] lpInBuf A pointer to a buffer that contains the data that the IOCTL
* being executed needs.
* @param[in] nInBufSiz The size of the buffer specified by lpInBuf.
* @param[out] lpOutBuf A pointer to a buffer that will contain the results from the
* IOCTL.
* @param[out] nOutBufSiz The size of the buffer specified by lpOutBuf.
* @param[out] lpBytesReturned A pointer to a DWORD that will contain the number of
* bytes returned by the IOCTL. (This will be the
* number of bytes in lpOutBuf that are valid.)
*
* \retval TRUE if IOCTL was successful
* \retval FALSE if IOCTL failed
**/
int devioctl_blk(HANDLE devHandle, DWORD ioctlValue, LPVOID lpInBuf, DWORD nInBufSiz,
LPVOID lpOutBuf, DWORD nOutBufSiz, LPDWORD lpBytesReturned)
{
DWORD result;
// Make sure we have some valid values.
if (devHandle == INVALID_HANDLE_VALUE)
{
debug_printf(DEBUG_INT, "Invalid handle passed in to %s()!\n", __FUNCTION__);
return FALSE;
}
if (lpBytesReturned == NULL)
{
debug_printf(DEBUG_INT, "Variable for 'BytesReturned' was NULL!\n", __FUNCTION__);
return FALSE;
}
result = devioctl(devHandle, ioctlValue, lpInBuf, nInBufSiz, lpOutBuf, nOutBufSiz,
lpBytesReturned);
if ((result != WAIT_OBJECT_0) && (result != WAIT_IO_COMPLETION) && (GetLastError() != 0))
{
return FALSE;
}
return TRUE;
}
/**
* \brief Set the protocol layer to listen for the multicast MAC address
* used by 802.1X. (01:80:c2:00:00:03)
*
* @param[in] devHandle A handle to the device that we want to set the multicast
* address on.
*
* \retval TRUE on success
* \retval FALSE on error
**/
int SetMulticastAddress(HANDLE devHandle)
{
DWORD BytesReturned;
DWORD result;
DWORD test;
UCHAR QueryBuffer[sizeof(NDIS_OID)+6];
PNDISPROT_QUERY_OID pQueryOid;
pQueryOid = (PNDISPROT_QUERY_OID)&QueryBuffer[0];
pQueryOid->Oid = OID_802_3_MULTICAST_LIST;
// The multicast MAC address defined by the standard.
pQueryOid->Data[0] = 0x01;
pQueryOid->Data[1] = 0x80;
pQueryOid->Data[2] = 0xc2;
pQueryOid->Data[3] = 0x00;
pQueryOid->Data[4] = 0x00;
pQueryOid->Data[5] = 0x03;
result = devioctl(devHandle, IOCTL_NDISPROT_SET_OID_VALUE,
(LPVOID)&QueryBuffer[0], sizeof(NDIS_OID)+6,
(LPVOID)&QueryBuffer[0], sizeof(NDIS_OID)+6, &BytesReturned);
if ((result != WAIT_OBJECT_0) && (result != WAIT_IO_COMPLETION))
{
return FALSE;
}
return TRUE;
}
/**
* \brief Convert a windows error code to a displayable string.
*
* Rather than just showing an error code, we want to show a string.
* This function will return a string to the last error that was
* generated. It is up to the caller to LocalFree() the result.
*
* @param[in] error The windows error code that was returned from a previous
* function call.
*
* \retval ptr to a displayable string that describes the error code.
**/
LPVOID GetLastErrorStr(DWORD error)
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL );
return lpMsgBuf;
}
/**
* \brief Get an handle to the "file" that the Open1X protocol handler
* presents.
*
* @param[in] devName A pointer to a non-unicode version of the "file" name that
* is presented by the protocol handler.
*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?