|
|
#include "precomp.h"
#include <malloc.h>
#include <ssdp.h>
#include <iptypes.h>
#include <iphlpapi.h>
#include <mswsock.h>
#ifdef IP_OBEX
#define Trace1 DbgPrint
GUID gWsMobilityServiceClassGuid = NLA_SERVICE_CLASS_GUID;
#define MAX_ADDRESSES (16)
typedef struct _NLA_ADDRESS_LIST {
LONG AddressCount; sockaddr_in Address[MAX_ADDRESSES];
} NLA_ADDRESS_LIST, *PNLA_ADDRESS_LIST;
BOOL GetIpAddressFromAdapterName( CHAR *AdapterName, ULONG *IpAddress );
VOID AddressListChangeHandler( DWORD Error, DWORD BytesTransfered, LPWSAOVERLAPPED WsOverLapped, DWORD Flags );
DWORD NetWorkWorker( PVOID Context );
typedef struct _ADDRESS_ENTRY {
in_addr IpAddress; PVOID AddressContext; HANDLE SsdpHandle; BOOL InUse; BOOL Present; BOOL Reported;
CHAR AdapterName[MAX_ADAPTER_NAME_LENGTH + 4]; NLA_CONNECTIVITY_TYPE Type;
} ADDRESS_ENTRY, *PADDRESS_ENTRY;
typedef struct _NET_CONTROL {
LONG ReferenceCount; BOOL Closing; HANDLE QueryHandle; WSAOVERLAPPED WsOverlapped;
HANDLE RegistrationContext; NEW_ADDRESS_CALLBACK NewAddressCallback; ADDRESS_GONE_CALLBACK AddressGoneCallback;
ADDRESS_ENTRY AddressEntry[MAX_ADDRESSES];
} NET_CONTROL, *PNET_CONTROL;
VOID GetAddressList( PNET_CONTROL NetControl, HANDLE QueryHandle );
VOID RemoveReferenceOnNetControl( PNET_CONTROL NetControl )
{
LONG CurrentCount;
CurrentCount=InterlockedDecrement(&NetControl->ReferenceCount);
if (CurrentCount == 0) {
HeapFree(GetProcessHeap(),0,NetControl); }
return;
}
VOID UnRegisterForAdhocNetworksNotification( HANDLE RegistrationHandle )
{ PNET_CONTROL NetControl=(PNET_CONTROL)RegistrationHandle;
NetControl->Closing=TRUE;
WSALookupServiceEnd(NetControl->QueryHandle);
RemoveReferenceOnNetControl(NetControl);
return;
}
HANDLE RegisterForAdhocNetworksNotification( HANDLE RegistrationContext, NEW_ADDRESS_CALLBACK NewAddressCallback, ADDRESS_GONE_CALLBACK AddressGoneCallback )
{
PNET_CONTROL NetControl=NULL; WORD wVersionRequested; WSADATA wsaData; int err; BOOL bResult; int j; LONG Status;
NetControl=(PNET_CONTROL)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*NetControl));
if (NetControl == NULL) {
goto CleanUp; }
NetControl->NewAddressCallback=NewAddressCallback; NetControl->AddressGoneCallback=AddressGoneCallback; NetControl->RegistrationContext=RegistrationContext;
for (j=0; j< MAX_ADDRESSES; j++) {
NetControl->AddressEntry[j].InUse=FALSE; }
WSAQUERYSET restrictions;
ZeroMemory(&restrictions, sizeof(restrictions)); restrictions.dwSize = sizeof(restrictions); restrictions.lpServiceClassId = &gWsMobilityServiceClassGuid; restrictions.dwNameSpace = NS_NLA;
Status = WSALookupServiceBegin( &restrictions, LUP_NOCONTAINERS | LUP_RETURN_ALL | LUP_DEEP , &NetControl->QueryHandle );
if (Status != ERROR_SUCCESS) {
goto CleanUp; }
//
// one refcount for the creation of the object
//
NetControl->ReferenceCount=1;
//
// add one refcount for the workitem
//
InterlockedIncrement(&NetControl->ReferenceCount);
bResult=QueueUserWorkItem( NetWorkWorker, NetControl, WT_EXECUTEINIOTHREAD );
if (bResult) {
return NetControl; }
CleanUp:
if (NetControl != NULL) {
HeapFree(GetProcessHeap(),0,NetControl); }
return NULL; }
DWORD NetWorkWorker( PVOID Context )
{
PNET_CONTROL NetControl=(PNET_CONTROL)Context; int err; DWORD BytesReturned; BOOL bResult;
GetAddressList(NetControl,NetControl->QueryHandle);
ZeroMemory(&NetControl->WsOverlapped,sizeof(NetControl->WsOverlapped));
NetControl->WsOverlapped.hEvent=NetControl;
WSACOMPLETION Completion;
Completion.Type=NSP_NOTIFY_APC; Completion.Parameters.Apc.lpOverlapped=&NetControl->WsOverlapped; Completion.Parameters.Apc.lpfnCompletionProc=AddressListChangeHandler;
err=WSANSPIoctl( NetControl->QueryHandle, SIO_NSP_NOTIFY_CHANGE, NULL, 0, NULL, 0, &BytesReturned, &Completion );
if (err == SOCKET_ERROR) {
if (WSAGetLastError() != WSA_IO_PENDING) { //
// the call failed and return value was not pending
//
RemoveReferenceOnNetControl(NetControl); } }
return 0;
}
VOID AddressListChangeHandler( DWORD Error, DWORD BytesTransfered, LPWSAOVERLAPPED WsOverlapped, DWORD Flags )
{
PNET_CONTROL NetControl=(PNET_CONTROL)WsOverlapped->hEvent;
if (!NetControl->Closing) {
NetWorkWorker( NetControl );
} else { //
// we are closing, remove all the addresses
//
ULONG i;
for (i=0; i< MAX_ADDRESSES; i++) { //
// See if any address disappeared
//
if (NetControl->AddressEntry[i].InUse) { //
// was in use at one time
//
if (NetControl->AddressEntry[i].Reported) {
DbgPrint("IRMON: removing address %s\n",inet_ntoa(NetControl->AddressEntry[i].IpAddress));
(NetControl->AddressGoneCallback)( NetControl->RegistrationContext, NetControl->AddressEntry[i].AddressContext );
UnregisterWithSsdp( NetControl->AddressEntry[i].SsdpHandle );
ZeroMemory(&NetControl->AddressEntry[i],sizeof(NetControl->AddressEntry[i])); } } }
RemoveReferenceOnNetControl(NetControl); }
return; }
VOID AddAddressToList( PNET_CONTROL NetControl, CHAR *AdapterName, in_addr IpAddress, NLA_CONNECTIVITY_TYPE Type )
{ ULONG j; ULONG i; LONG FreeSlot; BOOL bResult;
for (j=0; j< MAX_ADDRESSES; j++) {
if (NetControl->AddressEntry[j].InUse) {
// if (NetControl->AddressEntry[j].IpAddress.S_un.S_addr == IpAddress.S_un.S_addr) {
if (0 == lstrcmpA(AdapterName,NetControl->AddressEntry[j].AdapterName)) { //
// we have already seen this address
//
DbgPrint("net: dup local address %s\n",inet_ntoa(IpAddress)); NetControl->AddressEntry[j].Present=TRUE; break; }
} else {
FreeSlot=j; } }
if (j == MAX_ADDRESSES) { //
// we have a new address
//
SOCKET ListenSocket;
NetControl->AddressEntry[FreeSlot].InUse=TRUE; NetControl->AddressEntry[FreeSlot].Present=TRUE; NetControl->AddressEntry[FreeSlot].IpAddress = IpAddress; lstrcpyA(NetControl->AddressEntry[FreeSlot].AdapterName,AdapterName); NetControl->AddressEntry[FreeSlot].Type=Type;
if (((IpAddress.S_un.S_addr != INADDR_NONE) && (IpAddress.S_un.S_addr != 0)) && ((Type == NLA_NETWORK_AD_HOC) || (Type == NLA_NETWORK_UNMANAGED))) {
NetControl->AddressEntry[FreeSlot].Reported=TRUE;
bResult=RegisterWithSsdp( &IpAddress, &ListenSocket, &NetControl->AddressEntry[FreeSlot].SsdpHandle, 650 );
if (!bResult) {
DbgPrint("IRMON: failed to register with ssdp\n"); NetControl->AddressEntry[FreeSlot].Reported=FALSE;
} else {
(NetControl->NewAddressCallback)( NetControl->RegistrationContext, ListenSocket, &NetControl->AddressEntry[FreeSlot].AddressContext ); } } }
return;
}
VOID RemoveAddressFromList( PNET_CONTROL NetControl, CHAR *AdapterName )
{ ULONG i;
for (i=0; i< MAX_ADDRESSES; i++) { //
// See if any address disappeared
//
if (NetControl->AddressEntry[i].InUse) { //
// was in use at one time
//
if (0 == lstrcmpA(AdapterName,NetControl->AddressEntry[i].AdapterName)) { //
// This matched the device that is being removed
//
if (NetControl->AddressEntry[i].Reported) { //
// this one was reported to the client
//
DbgPrint("IRMON: removing address %s\n",inet_ntoa(NetControl->AddressEntry[i].IpAddress));
(NetControl->AddressGoneCallback)( NetControl->RegistrationContext, NetControl->AddressEntry[i].AddressContext );
UnregisterWithSsdp( NetControl->AddressEntry[i].SsdpHandle ); }
ZeroMemory(&NetControl->AddressEntry[i],sizeof(NetControl->AddressEntry[i])); }
} } return;
}
VOID GetAddressList( PNET_CONTROL NetControl, HANDLE QueryHandle )
{
int ret = FALSE; WSADATA wsaData;
PWSAQUERYSET result = NULL; DWORD length; DWORD LengthRequested; int error;
ret = TRUE;
while (1) {
length = 0; WSALookupServiceNext(QueryHandle, 0, &length, NULL);
if (((error = WSAGetLastError()) != WSAEFAULT) && (error != WSA_E_NO_MORE)) { Trace1("WSALookupServiceNext1 failed %d\n", error); ret = FALSE; break; }
result = (PWSAQUERYSET)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,length);
if (result != NULL) {
LengthRequested=length;
ret = WSALookupServiceNext(QueryHandle, 0, &length, result);
if (ret == ERROR_SUCCESS) {
if (result->lpBlob != NULL) {
NLA_BLOB *blob = (NLA_BLOB *)result->lpBlob->pBlobData; int next; IN_ADDR IpAddress; NLA_CONNECTIVITY_TYPE ConnectivityType=NLA_NETWORK_UNKNOWN; CHAR AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
AdapterName[0]='\0'; IpAddress.S_un.S_addr=INADDR_NONE;
do { // The next four lines need changing when network interface type is implemented
DbgPrint("NLA: Blob type %d\n",blob->header.type);
if (blob->header.type == NLA_CONNECTIVITY) {
DbgPrint("NLA: connectivity=%d, Internet=%d\n",blob->data.connectivity.type,blob->data.connectivity.internet); ConnectivityType=blob->data.connectivity.type;
}
if (blob->header.type == NLA_INTERFACE) {
DbgPrint("NLA: adapter name %s, speed %d\n",blob->data.interfaceData.adapterName,blob->data.interfaceData.dwSpeed); GetIpAddressFromAdapterName(blob->data.interfaceData.adapterName,&IpAddress.S_un.S_addr); lstrcpynA(AdapterName,blob->data.interfaceData.adapterName,sizeof(AdapterName)-1); }
next = blob->header.nextOffset; blob = (NLA_BLOB *)(((char *)blob) + next);
} while(next != 0);
if (AdapterName[0] != '\0') { //
// we got an adapter name
//
if (result->dwOutputFlags & RESULT_IS_ADDED) { //
// new interface
//
DbgPrint("NLA: add\n");
AddAddressToList( NetControl, AdapterName, IpAddress, ConnectivityType );
} else {
if (result->dwOutputFlags & RESULT_IS_DELETED) {
DbgPrint("NLA: delete\n");
RemoveAddressFromList( NetControl, AdapterName );
} else {
if (result->dwOutputFlags & RESULT_IS_CHANGED) {
DbgPrint("NLA: change\n");
RemoveAddressFromList( NetControl, AdapterName );
AddAddressToList( NetControl, AdapterName, IpAddress, ConnectivityType );
} else {
DbgPrint("NLA: other dwOutputFlags %x\n",result->dwOutputFlags); } } } } }
} else {
if ((error = WSAGetLastError()) != WSA_E_NO_MORE) { Trace1("WSALookupServiceNext failed %d, needed=%d, req=%d\n", error,length, LengthRequested); ret = FALSE; } break; }
HeapFree(GetProcessHeap(),0,result); result=NULL; } }
return ; }
BOOL GetIpAddressFromAdapterName( CHAR *AdapterName, ULONG *IpAddress )
{
PIP_ADAPTER_INFO AdapterInfo; PIP_ADAPTER_INFO CurrentAdapter; ULONG BufferNeeded; DWORD ReturnValue; BOOL bReturn=FALSE;
BufferNeeded=0;
// DbgPrint("irmon: GetIpAddressFromAdapterName\n");
ReturnValue=GetAdaptersInfo( NULL, &BufferNeeded );
if (ReturnValue != ERROR_BUFFER_OVERFLOW) { //
// failed for some other reason
//
DbgPrint("irmon: GetAdaptersInfo(1) failed\n"); return FALSE; }
AdapterInfo=(PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,BufferNeeded);
if (AdapterInfo != NULL) {
ReturnValue=GetAdaptersInfo( AdapterInfo, &BufferNeeded );
if (ReturnValue == ERROR_SUCCESS) {
CurrentAdapter=AdapterInfo;
while (CurrentAdapter != NULL) {
int Match;
// DbgPrint("IRMON: comp AdapterName=%s, comp=%s\n",AdapterName,CurrentAdapter->AdapterName);
Match=lstrcmpiA(AdapterName,CurrentAdapter->AdapterName);
if (Match == 0) {
DbgPrint("IRMON: match AdapterName=%s, ip=%s\n",CurrentAdapter->AdapterName,CurrentAdapter->IpAddressList.IpAddress.String);
*IpAddress=inet_addr(&CurrentAdapter->IpAddressList.IpAddress.String[0]);
if (*IpAddress != INADDR_NONE) {
bReturn=TRUE; break; }
} else {
// DbgPrint("IRMON: mismatch AdapterName=%s, comp=%s\n",AdapterName,CurrentAdapter->AdapterName);
}
CurrentAdapter=CurrentAdapter->Next; } } else {
DbgPrint("irmon: GetAdaptersInfo(2) failed\n"); }
HeapFree(GetProcessHeap(),0,AdapterInfo); AdapterInfo=NULL;
} else {
DbgPrint("irmon: allocation failed\n");
}
return bReturn; }
#endif //ip_obex
|