cardif_windows_wmi.c

来自「linux 下通过802.1认证的安装包」· C语言 代码 · 共 2,302 行 · 第 1/5 页

C
2,302
字号
/**
 * Interface to Windows WMI for events, and getting various data.
 *
 * Licensed under a dual GPL/BSD license.  (See LICENSE file for more info.)
 *
 * \file cardif_windows_wmi.c
 *
 * \author chris@open1x.org
 *
 * \todo Implement calls to get the list of DNS servers.
 *
 * $Id: cardif_windows_wmi.c,v 1.1.2.57 2008/01/21 22:51:48 chessing Exp $
 * $Date: 2008/01/21 22:51:48 $
 **/

#define _WIN32_DCOM

// We need to define COBJMACROS so that we can make the C calls
// to the IWbem* interfaces.
#ifndef COBJMACROS
#define COBJMACROS
#endif 

#include <wbemidl.h>

#include <windows.h>
#include <iphlpapi.h>
#include <process.h>

#include "../../xsup_common.h"
#include "../../../lib/libxsupconfig/xsupconfig.h"
#include "../../../lib/libxsupconfig/xsupconfig_structs.h"
#include "../../context.h"
#include "../../xsup_debug.h"
#include "../../xsup_err.h"
#include "cardif_windows.h"
#include "../../event_core_win.h"
#include "../../ipc_events_index.h"
#include "../../eap_sm.h"
#include "../../error_prequeue.h"
#include "cardif_windows_wmi_async.h"
#include "cardif_windows_wmi.h"

///< The WQL select string that is needed to get adapter information for a specific interface.
#define GET_ADAPTER_BY_IDX           L"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Index = %d"

typedef struct {
	wchar_t *intName;
	uint8_t numChecks;
	uint8_t interval;
} check_type;

#define BIND_INTERVAL            5  // The amount of time to wait between bind checks.
#define NUM_BIND_CHECKS          3  // The number of times to attempt to bind before we give up.
#define BIND_CHECKS_SIZE         5  // We can only have 5 outstanding binding requests.  This is probably plenty since they shouldn't last long.
check_type checks[5];            

#define WMI_BIND_ADD     0
#define WMI_BIND_CHECK   1

// Some globals to make life easy.
IWbemLocator *wmiLoc = NULL;
IWbemServices *wmiSvc = NULL;
IWbemServices *wmiEvents = NULL;
IEnumWbemClassObject *pConnectEvent = NULL;
IEnumWbemClassObject *pDisconnectEvent = NULL;
IEnumWbemClassObject *pMediaSpecificEvent = NULL;
IEnumWbemClassObject *pInsertEvent = NULL;
IEnumWbemClassObject *pRemoveEvent = NULL;
int WMIConnected = FALSE;

// XXX ICK..  Do this better.
extern void (*imc_disconnect_callback)(uint32_t connectionID);

/**
 * \brief Create an event handler to watch for media connect events.
 *
 * \retval 0 on success.
 **/
int cardif_windows_wmi_event_setup_connect()
{
	HRESULT hr;

	hr = IWbemServices_ExecNotificationQuery(wmiEvents,
        L"WQL",
        L"SELECT * FROM MSNdis_StatusMediaConnect" ,
        WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, 
        NULL, &pConnectEvent);

	if (FAILED(hr)) return -1;

	return 0;
}

/**
 * \brief Check an event handler to see if any media connect events have happened.
 *
 *  When an event is triggered here, this function will also take care of processing
 *  the event, and changing the needed state options for interfaces.
 *
 * \retval 0 on success
 **/
int cardif_windows_wmi_event_check_connect()
{
	HRESULT hr;
    IWbemClassObject *pclsObj = NULL;
	ULONG uReturn;
	context *ctx = NULL;
	wireless_ctx *wctx = NULL;
	char *intdesc = NULL;
	VARIANT vtProp;
	uint8_t bssid[6];
	char ssid[34];
	int ssidsize = 34;

	if (pConnectEvent == NULL) return -1;

	hr = IEnumWbemClassObject_Next(pConnectEvent, 0, 1, &pclsObj, &uReturn);
	if (FAILED(hr)) return -1;

	if (uReturn > 0)
	{
		// We have an event.
		debug_printf(DEBUG_INT, "!!!!!!!!!!!!!!!!!!!! Connect Event !!!!!!!!!!!!!!!!!!!!!\n");
		hr = IWbemClassObject_Get(pclsObj, L"InstanceName", 0, &vtProp, 0, 0);
		if (FAILED(hr))
		{
			debug_printf(DEBUG_NORMAL, "Got a connect event, but it didn't seem to have any "
					"information in it.\n");
		}
		
		// Locate the context we want to work on.
		debug_printf(DEBUG_INT, "Looking for interface with caption : %ws\n", vtProp.bstrVal);
		ctx = event_core_locate_by_caption(vtProp.bstrVal, FALSE);

		if (ctx == NULL)
		{
			intdesc = uni_to_ascii(vtProp.bstrVal);
			debug_printf(DEBUG_INT, "Couldn't find by caption, looking by description.\n");
			ctx = event_core_locate_by_desc_strstr(intdesc);
			if (ctx == NULL)
			{
				debug_printf(DEBUG_INT, "Couldn't locate a context for connect event. (Perhaps "
					"we aren't managing this interface?)\n");
				VariantClear(&vtProp);
				return -1;
			}
		}
		VariantClear(&vtProp);

		debug_printf(DEBUG_INT, "Interface is : %s\n", ctx->intName);

		// Send event.
		ipc_events_ui(NULL, IPC_EVENT_UI_LINK_UP, ctx->desc);

		if (ctx->intType == ETH_802_11_INT)
		{
			wctx = (wireless_ctx *)ctx->intTypeData;
			if (wctx == NULL)
			{
				debug_printf(DEBUG_NORMAL, "Interface %s claims to be wireless, but doesn't "
					"have a wireless context!?\n", ctx->intName);
				return -1;
			}

			if (cardif_windows_wireless_get_bssid(ctx, &bssid) != 0)
			{
				debug_printf(DEBUG_NORMAL, "Unable to get BSSID for interface '%s'.\n", ctx->desc);
				ctx->auths = 0;     // Reset the number of authentications this interface has done.
			}
			else
			{
				if (cardif_windows_wireless_get_ssid(ctx, &ssid, ssidsize) != 0)
				{
					debug_printf(DEBUG_NORMAL, "Interface '%s' assocated to the AP with BSSID %02X:%02X:%02X:%02X:%02X:%02X\n",
						ctx->desc, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
				}
				else
				{
					debug_printf(DEBUG_NORMAL, "Interface '%s' assocated to the SSID '%s' with BSSID %02X:%02X:%02X:%02X:%02X:%02X\n",
						ctx->desc, ssid, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
				}

				if ((wctx->cur_essid != NULL) && (strcmp(ssid, wctx->cur_essid) != 0))
				{
					// We hopped to a new SSID.  Reset our counters.
					ctx->auths = 0;
				}
			}

			if (memcmp(wctx->cur_bssid, &bssid, 6) != 0)
			{
				SET_FLAG(wctx->flags, WIRELESS_SM_ASSOCIATED);  // We are now associated.
				UNSET_FLAG(wctx->flags, WIRELESS_SM_STALE_ASSOCIATION);

				// Reset the EAP state machine.
				eap_sm_force_init(ctx->eap_state);
				memcpy(wctx->cur_bssid, bssid, 6);
			}
			else
			{
				debug_printf(DEBUG_NORMAL, "Interface '%s' sent us an associate event about a BSSID we are already associated to.  This usually indicates a firmware, driver, or environmental issue.  This event has been ignored.\n", ctx->desc);
				debug_printf(DEBUG_PHYSICAL_STATE, "Clearing replay counter.\n");
				memset(&ctx->statemachine->replay_counter, 0x00, 8);
			}

			if (TEST_FLAG(wctx->flags, WIRELESS_SM_DOING_PSK))
			{
				ipc_events_ui(ctx, IPC_EVENT_BAD_PSK, ctx->intName);

				// We sent the error so unset the flag.
				UNSET_FLAG(wctx->flags, WIRELESS_SM_DOING_PSK);
			}
		}
		else
		{
			debug_printf(DEBUG_INT, "Enabling wired port.\n");
			debug_printf(DEBUG_NORMAL, "Interface '%s' now has link.\n", ctx->desc);
			ctx->auths = 0;

			// Reset the EAP state machine.
			eap_sm_force_init(ctx->eap_state);
		}
	}

	return 0;
}

/**
 * \brief Create an event handler to watch for card insertion events.
 *
 * \retval 0 on success.
 **/
int cardif_windows_wmi_event_setup_insert()
{
	HRESULT hr;

	hr = IWbemServices_ExecNotificationQuery(wmiEvents,
        L"WQL",
        L"SELECT * FROM MSNdis_NotifyAdapterArrival" ,
        WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, 
        NULL, &pInsertEvent);

	if (FAILED(hr)) return -1;

	return 0;
}

/**
 * \brief On some machines and interfaces Windows will send the WMI "card inserted"
 *		message before the interface is bound to our protocol driver.  So, we need
 *      to give it some time to get bound.
 *
 * @param[in] action   An int that defines the action to take.  (One of WMI_BIND_ADD,
 *                     WMI_BIND_CHECK)
 * @param[in] name     The name of the device we want to look for.  (Only needed 
 *	                   when action == WMI_BIND_ADD)
 **/
void cardif_windows_wmi_late_bind_insert_check(int action, wchar_t *name)
{
	int i = 0;
	int retval = 0;

	switch (action)
	{
	case WMI_BIND_ADD:
		while ((checks[i].intName != NULL) && (i < BIND_CHECKS_SIZE)) i++;

		if (i >= BIND_CHECKS_SIZE)
		{
			debug_printf(DEBUG_NORMAL, "All bind check slots are currently in use.  The newly inserted interface won't be discovered!\n");
			return;
		}

		checks[i].intName = wcsdup(name);
		checks[i].interval = BIND_INTERVAL;
		checks[i].numChecks = NUM_BIND_CHECKS;
		return;
		break;

	case WMI_BIND_CHECK:
		while (i < BIND_CHECKS_SIZE)
		{
			if (checks[i].intName != NULL)
			{
				checks[i].interval--;

				if (checks[i].interval <= 0)
				{
					// Try to bind again.
					retval = cardif_windows_wmi_post_insert_bind(checks[i].intName);
					if (retval != -1)
					{
						// We are done looking for this interface!
						if (retval == -2)
						{
							debug_printf(DEBUG_NORMAL, "An unrecoverable error was encountered binding the newly inserted interface '%ws'. "
								"It will not be available for use.\n", checks[i].intName);
						}

						FREE(checks[i].intName);
						return;
					}

					checks[i].numChecks--;
					if (checks[i].numChecks <= 0)
					{
						debug_printf(DEBUG_NORMAL, "Failed to bind newly discovered interface '%ws'.  It will not be usable.\n", checks[i].intName);
						FREE(checks[i].intName);
						return;
					}

					// Otherwise, reset 'interval'.
					checks[i].interval = BIND_INTERVAL;
				}
			}

			i++;
		}
		return;
		break;

	default:
		debug_printf(DEBUG_NORMAL, "You attempted to make use of the function %s() in an naughty way!  Stop that! ;)\n", __FUNCTION__);
		break;
	}
}

/**
 * \brief Check an event handler to see if any insertion events have happened.
 *
 *  When an event is triggered here, this function will also take care of processing
 *  the event, and sending an IPC event..
 *
 * \retval 0 on success
 **/
int cardif_windows_wmi_event_check_insert()
{
	HRESULT hr;
    IWbemClassObject *pclsObj = NULL;
	ULONG uReturn;
	VARIANT vtProp;

	if (pInsertEvent == NULL) return -1;

	hr = IEnumWbemClassObject_Next(pInsertEvent, 0, 1, &pclsObj, &uReturn);
	if (FAILED(hr)) return -1;

	if (uReturn > 0)
	{
		// We have an event.
		debug_printf(DEBUG_INT, "!!!!!!!!!!!!!!!!!!!! Card Insertion Event !!!!!!!!!!!!!!!!!!!!!\n");
		hr = IWbemClassObject_Get(pclsObj, L"InstanceName", 0, &vtProp, 0, 0);
		if (FAILED(hr))
		{
			debug_printf(DEBUG_NORMAL, "Got a card insertion event, but it didn't seem to have any "
					"information in it.\n");
		}
		
		// Locate the context we want to work on.
		debug_printf(DEBUG_INT, "Looking for interface with caption : %ws\n", vtProp.bstrVal);

		if (cardif_windows_wmi_post_insert_bind(vtProp.bstrVal) == -1)
		{
			// We get a LOT of insert events.  The ones we care about have "Packet Scheduler Miniport" in the name.
			if (wcsstr(vtProp.bstrVal, L"Packet Scheduler Miniport") != NULL)
			{
				// Need to queue it up to try to bind later.
				debug_printf(DEBUG_NORMAL, "Windows indicated that an interface was inserted, but it doesn't appear to have bound to the "
					"Open1X driver yet.   We will wait and try again...\n");
				cardif_windows_wmi_late_bind_insert_check(WMI_BIND_ADD, vtProp.bstrVal);
			}
		}

		VariantClear(&vtProp);
	}

	return 0;
}

/**
 * \brief Attempt to bind the interface that Windows told us was inserted.
 *
 * @param[in] name   The name of the interface that we need to bind to.
 *
 * \retval 0 on success
 * \retval -1 on failed (should try again.. to some point)
 * \retval -2 on failed (unrecoverable failure)
 **/
int cardif_windows_wmi_post_insert_bind(wchar_t *name)
{
	char *intname = NULL;
	char *intdesc = NULL;
	struct xsup_interfaces *confints = NULL;
	char mac[6];
	char is_wireless = 0;
	context *ctx = NULL;

	intname = cardif_windows_find_os_name_from_desc(name);
	intdesc = uni_to_ascii(name);
		
	if (intname == NULL)
	{
		debug_printf(DEBUG_INT, "Couldn't locate information about this instance, ignoring.\n");
		FREE(intdesc);
		return -1;
	}

	if (intdesc == NULL)
	{
		debug_printf(DEBUG_INT, "Couldn't convert description string from this interface, ignoring.\n");
		FREE(intname);
		return 0;
	}

	// Send event.
	ipc_events_ui(NULL, IPC_EVENT_INTERFACE_INSERTED, intname);

	if (get_mac_by_name(intname, (char *)&mac) != 0)
	{
		debug_printf(DEBUG_NORMAL, "Unable to get the MAC address for interface with description '%s'.  (OS Device Name : %s)\n", intdesc, intname);
		return -2;
	}

	is_wireless = cardif_is_wireless_by_name(intname);

	if (interfaces_add(intname, intdesc, mac, is_wireless) != 0)
	{
		debug_printf(DEBUG_NORMAL, "Unable to add interface '%s' to our live interfaces cache!\n", intdesc);
		// Don't die here, because we may be able to manage it, which would at least be something.
	}

	confints = config_get_config_ints();

	while ((confints != NULL) && (memcmp(mac, confints->mac, 6) != 0))
		confints = confints->next;

	if (confints != NULL)
	{
		// Build the interface, and start watching it.
		if (context_init_interface(&ctx, intdesc, intname, NULL, 0) != XENONE)
		{
			debug_printf(DEBUG_NORMAL, "Couldn't allocate context to manage newly inserted interface!\n");
		}
		else
		{
			// Add it to the event loop.
			debug_printf(DEBUG_NORMAL, "Interface '%s' was inserted or enabled.\n", intdesc);
		}
	}
	else
	{
		debug_printf(DEBUG_NORMAL, "Interface '%s' isn't in our configuration file.  We will not manage it.\n", intdesc);
	}

	FREE(intname);
	FREE(intdesc);
	
	return 0;
}

⌨️ 快捷键说明

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