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 + -
显示快捷键?