1178 lines
33 KiB
C
1178 lines
33 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
WshIrDA.c
|
|
|
|
Abstract:
|
|
|
|
This module contains necessary routines for the IrDA Windows Sockets
|
|
Helper DLL. This DLL provides the transport-specific support necessary
|
|
for the Windows Sockets DLL to use IrDA as a transport.
|
|
|
|
Author:
|
|
|
|
Zed (mikezin) 28-Aug-1996
|
|
mbert Sept 97
|
|
|
|
--*/
|
|
|
|
#define UNICODE
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <wchar.h>
|
|
#include <tdi.h>
|
|
|
|
#include <winsock2.h>
|
|
#include <wsahelp.h>
|
|
|
|
#include <tdistat.h>
|
|
#include <tdiinfo.h>
|
|
#include <llinfo.h>
|
|
|
|
|
|
typedef unsigned long ulong;
|
|
typedef unsigned short ushort;
|
|
typedef unsigned int uint;
|
|
typedef unsigned char uchar;
|
|
|
|
#define NT /* for tdiinfo.h */
|
|
#include <tdiinfo.h>
|
|
|
|
|
|
#include <basetyps.h>
|
|
#include <nspapi.h>
|
|
#include <nspapip.h>
|
|
|
|
#include <af_irda.h>
|
|
#include <irioctl.h>
|
|
#include <irdatdi.h>
|
|
|
|
#define MIN_SOCKADDR_LEN 8
|
|
#define MAX_SOCKADDR_LEN sizeof(SOCKADDR_IRDA)
|
|
|
|
#ifdef _NOT_DBG
|
|
//#ifdef DBG
|
|
#define DEBUGMSG(s) DbgPrint s
|
|
#else
|
|
#define DEBUGMSG(s)
|
|
#endif
|
|
|
|
typedef struct WshIrdaIasAttrib
|
|
{
|
|
HANDLE AttribHandle;
|
|
struct WshIrdaIasAttrib *pNext;
|
|
} WSHIRDA_IAS_ATTRIBUTE, *PWSHIRDA_IAS_ATTRIBUTE;
|
|
|
|
typedef struct _WSHIRDA_SOCKET_CONTEXT
|
|
{
|
|
PWSHIRDA_IAS_ATTRIBUTE pIasAttribs;
|
|
// all fields copied from parent to child (at accept) must follow
|
|
// (see SetSocketInformation SO_CONTEXT)
|
|
INT AddressFamily;
|
|
INT SocketType;
|
|
INT Protocol;
|
|
DWORD Options;
|
|
HANDLE LazyDscvDevHandle;
|
|
} WSHIRDA_SOCKET_CONTEXT, *PWSHIRDA_SOCKET_CONTEXT;
|
|
|
|
typedef struct
|
|
{
|
|
DWORD Rows;
|
|
DWORD Columns;
|
|
struct {
|
|
DWORD AddressFamily;
|
|
DWORD SocketType;
|
|
DWORD Protocol;
|
|
} Mapping[3];
|
|
} IRDA_WINSOCK_MAPPING;
|
|
|
|
const IRDA_WINSOCK_MAPPING IrDAMapping =
|
|
{ 3, 3,
|
|
AF_IRDA, SOCK_STREAM, IRDA_PROTO_SOCK_STREAM,
|
|
AF_IRDA, SOCK_STREAM, 0,
|
|
AF_IRDA, 0, IRDA_PROTO_SOCK_STREAM };
|
|
|
|
WSAPROTOCOL_INFOW Winsock2Protocols[] =
|
|
{
|
|
{
|
|
XP1_GUARANTEED_DELIVERY // dwServiceFlags1
|
|
| XP1_GUARANTEED_ORDER
|
|
| XP1_IFS_HANDLES,
|
|
0, // dwServiceFlags2
|
|
0, // dwServiceFlags3
|
|
0, // dwServiceFlags4
|
|
PFL_MATCHES_PROTOCOL_ZERO, // dwProviderFlags
|
|
{ // gProviderId
|
|
0, 0, 0,
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0 }
|
|
},
|
|
0, // dwCatalogEntryId
|
|
{ // ProtocolChain
|
|
BASE_PROTOCOL, // ChainLen
|
|
{ 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
|
|
},
|
|
2, // iVersion
|
|
AF_IRDA, // iAddressFamily
|
|
|
|
// winsock doesn't seem to use min and max here,
|
|
// it gets it from inf and is stored
|
|
// in CCS\services\irda\parameters\winsock
|
|
sizeof(SOCKADDR_IRDA), // iMaxSockAddr
|
|
8, // iMinSockAddr
|
|
|
|
SOCK_STREAM, // iSocketType
|
|
IRDA_PROTO_SOCK_STREAM, // iProtocol
|
|
0, // iProtocolMaxOffset
|
|
BIGENDIAN, // iNetworkByteOrder
|
|
SECURITY_PROTOCOL_NONE, // iSecurityScheme
|
|
0, // dwMessageSize
|
|
0, // dwProviderReserved
|
|
L"MSAFD Irda [IrDA]" // szProtocol
|
|
}
|
|
};
|
|
|
|
GUID IrdaProviderGuid = { /* 3972523d-2af1-11d1-b655-00805f3642cc */
|
|
0x3972523d,
|
|
0x2af1,
|
|
0x11d1,
|
|
{0xb6, 0x55, 0x00, 0x80, 0x5f, 0x36, 0x42, 0xcc}
|
|
};
|
|
|
|
VOID
|
|
DeleteSocketAttribs(PWSHIRDA_SOCKET_CONTEXT pSocket);
|
|
|
|
// globals
|
|
CRITICAL_SECTION IrdaCs;
|
|
|
|
BOOLEAN
|
|
DllInitialize(
|
|
IN PVOID DllHandle,
|
|
IN ULONG Reason,
|
|
IN PVOID Context OPTIONAL)
|
|
{
|
|
switch(Reason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
// We don't need to receive thread attach and detach
|
|
// notifications, so disable them to help application
|
|
// performance.
|
|
DisableThreadLibraryCalls(DllHandle);
|
|
|
|
try
|
|
{
|
|
InitializeCriticalSection(&IrdaCs);
|
|
}
|
|
except (STATUS_NO_MEMORY == GetExceptionCode())
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
DeleteCriticalSection(&IrdaCs);
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
INT
|
|
IoStatusToWs(NTSTATUS Status)
|
|
{
|
|
switch (Status)
|
|
{
|
|
case STATUS_SUCCESS:
|
|
return NO_ERROR;
|
|
|
|
case STATUS_PENDING:
|
|
return ERROR_IO_PENDING;
|
|
|
|
case STATUS_INVALID_HANDLE:
|
|
case STATUS_OBJECT_TYPE_MISMATCH:
|
|
return WSAENOTSOCK;
|
|
|
|
case STATUS_INVALID_PARAMETER:
|
|
case STATUS_ADDRESS_CLOSED:
|
|
case STATUS_CONNECTION_INVALID:
|
|
case STATUS_ADDRESS_ALREADY_ASSOCIATED:
|
|
case STATUS_ADDRESS_NOT_ASSOCIATED:
|
|
case STATUS_CONNECTION_ACTIVE:
|
|
case STATUS_INVALID_DEVICE_STATE:
|
|
case STATUS_INVALID_DEVICE_REQUEST:
|
|
return WSAEINVAL;
|
|
|
|
case STATUS_INSUFFICIENT_RESOURCES:
|
|
case STATUS_PAGEFILE_QUOTA:
|
|
case STATUS_COMMITMENT_LIMIT:
|
|
case STATUS_WORKING_SET_QUOTA:
|
|
case STATUS_NO_MEMORY:
|
|
case STATUS_CONFLICTING_ADDRESSES:
|
|
case STATUS_QUOTA_EXCEEDED:
|
|
case STATUS_TOO_MANY_PAGING_FILES:
|
|
case STATUS_REMOTE_RESOURCES:
|
|
case STATUS_TOO_MANY_ADDRESSES:
|
|
return WSAENOBUFS;
|
|
|
|
case STATUS_SHARING_VIOLATION:
|
|
case STATUS_ADDRESS_ALREADY_EXISTS:
|
|
return WSAEADDRINUSE;
|
|
|
|
case STATUS_LINK_TIMEOUT:
|
|
case STATUS_IO_TIMEOUT:
|
|
case STATUS_TIMEOUT:
|
|
return WSAETIMEDOUT;
|
|
|
|
case STATUS_GRACEFUL_DISCONNECT:
|
|
return WSAEDISCON;
|
|
|
|
case STATUS_REMOTE_DISCONNECT:
|
|
case STATUS_CONNECTION_RESET:
|
|
case STATUS_LINK_FAILED:
|
|
case STATUS_CONNECTION_DISCONNECTED:
|
|
return WSAECONNRESET;
|
|
|
|
case STATUS_LOCAL_DISCONNECT:
|
|
case STATUS_TRANSACTION_ABORTED:
|
|
case STATUS_CONNECTION_ABORTED:
|
|
return WSAECONNRESET; // WSAECONNABORTED; Make HAPI happy
|
|
|
|
case STATUS_INVALID_NETWORK_RESPONSE:
|
|
return WSAENETDOWN;
|
|
|
|
case STATUS_BAD_NETWORK_PATH:
|
|
case STATUS_NETWORK_UNREACHABLE:
|
|
case STATUS_PROTOCOL_UNREACHABLE:
|
|
return WSAENETUNREACH;
|
|
|
|
case STATUS_HOST_UNREACHABLE:
|
|
return WSAEHOSTUNREACH;
|
|
|
|
case STATUS_CANCELLED:
|
|
case STATUS_REQUEST_ABORTED:
|
|
return WSAEINTR;
|
|
|
|
case STATUS_BUFFER_OVERFLOW:
|
|
case STATUS_INVALID_BUFFER_SIZE:
|
|
return WSAEMSGSIZE;
|
|
|
|
case STATUS_BUFFER_TOO_SMALL:
|
|
case STATUS_ACCESS_VIOLATION:
|
|
return WSAEFAULT;
|
|
|
|
case STATUS_DEVICE_NOT_READY:
|
|
case STATUS_REQUEST_NOT_ACCEPTED:
|
|
return WSAEWOULDBLOCK;
|
|
|
|
case STATUS_NETWORK_BUSY:
|
|
case STATUS_NO_SUCH_DEVICE:
|
|
case STATUS_NO_SUCH_FILE:
|
|
case STATUS_OBJECT_PATH_NOT_FOUND:
|
|
case STATUS_UNEXPECTED_NETWORK_ERROR:
|
|
return WSAENETDOWN;
|
|
|
|
case STATUS_INVALID_CONNECTION:
|
|
return WSAENOTCONN;
|
|
|
|
case STATUS_REMOTE_NOT_LISTENING:
|
|
case STATUS_CONNECTION_REFUSED:
|
|
return WSAECONNREFUSED;
|
|
|
|
case STATUS_PIPE_DISCONNECTED:
|
|
return WSAESHUTDOWN;
|
|
|
|
case STATUS_INVALID_ADDRESS:
|
|
case STATUS_INVALID_ADDRESS_COMPONENT:
|
|
return WSAEADDRNOTAVAIL;
|
|
|
|
case STATUS_NOT_SUPPORTED:
|
|
case STATUS_NOT_IMPLEMENTED:
|
|
return WSAEOPNOTSUPP;
|
|
|
|
case STATUS_PORT_UNREACHABLE:
|
|
return WSAEREMOTE;
|
|
|
|
case STATUS_UNSUCCESSFUL:
|
|
return WSAEINVAL;
|
|
|
|
case STATUS_ACCESS_DENIED:
|
|
return WSAEACCES;
|
|
|
|
default:
|
|
DEBUGMSG(("Didn't map NT status %X, returning WSAEINVAL\n", Status));
|
|
return WSAEINVAL;
|
|
}
|
|
}
|
|
|
|
INT
|
|
WSHGetSockaddrType(
|
|
IN PSOCKADDR Sockaddr,
|
|
IN DWORD SockaddrLength,
|
|
OUT PSOCKADDR_INFO SockaddrInfo)
|
|
{
|
|
UNALIGNED SOCKADDR *pSockaddr = (PSOCKADDR) Sockaddr;
|
|
|
|
if (SockaddrLength < sizeof(SOCKADDR_IRDA))
|
|
{
|
|
DEBUGMSG(("WSHGetSockaddrType(irda): SockaddrLength(%d) < sizeof(SOCKADDR_IRDA)%d ret WSAEFAULT\n",
|
|
SockaddrLength, sizeof(SOCKADDR_IRDA)));
|
|
return WSAEFAULT;
|
|
}
|
|
|
|
if (pSockaddr->sa_family != AF_IRDA)
|
|
{
|
|
DEBUGMSG(("WSHGetSockaddrType(irda): pSockaddr->sa_family != AF_IRDA ret WSAEAFNOSUPPORT\n"));
|
|
return WSAEAFNOSUPPORT;
|
|
}
|
|
|
|
if (((SOCKADDR_IRDA *) pSockaddr)->irdaServiceName[0] == 0)
|
|
{
|
|
SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
|
|
SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
|
|
}
|
|
else
|
|
{
|
|
SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
|
|
SockaddrInfo->EndpointInfo = SockaddrEndpointInfoNormal;
|
|
}
|
|
|
|
DEBUGMSG(("WSHGetSockaddrType(irda): returning no error\n"));
|
|
return NO_ERROR;
|
|
}
|
|
|
|
INT
|
|
ControlIoctl(
|
|
ULONG IoctlCode,
|
|
OUT PCHAR OptionValue,
|
|
OUT PINT OptionLength,
|
|
OUT HANDLE *pDevHandle)
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjAttr;
|
|
UNICODE_STRING DeviceName;
|
|
HANDLE DeviceHandle;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
|
|
|
|
if (pDevHandle)
|
|
{
|
|
*pDevHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjAttr,
|
|
&DeviceName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtCreateFile(
|
|
&DeviceHandle, // PHANDLE FileHandle
|
|
SYNCHRONIZE | GENERIC_EXECUTE, // ACCESS_MASK DesiredAccess
|
|
&ObjAttr, // POBJECT_ATTRIBUTES ObjAttr
|
|
&IoStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
|
|
NULL, // PLARGE_INTEGER AllocationSize
|
|
FILE_ATTRIBUTE_NORMAL, // ULONG FileAttributes
|
|
FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE, // ULONG ShareAccess
|
|
FILE_OPEN_IF, // ULONG CreateDisposition
|
|
FILE_SYNCHRONOUS_IO_NONALERT, // ULONG CreateOptions
|
|
NULL, // PVOID EaBuffer
|
|
0); // ULONG EaLength
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
Status = NtDeviceIoControlFile(
|
|
DeviceHandle, // HANDLE FileHandle
|
|
NULL, // HANDLE Event OPTIONAL
|
|
NULL, // PIO_APC_ROUTINE ApcRoutine
|
|
NULL, // PVOID ApcContext
|
|
&IoStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
|
|
IoctlCode, // ULONG IoControlCode
|
|
OptionValue, // PVOID InputBuffer
|
|
*OptionLength, // ULONG InputBufferLength
|
|
OptionValue, // PVOID OutputBuffer
|
|
*OptionLength); // ULONG OutputBufferLength
|
|
|
|
DEBUGMSG(("IoControlFile returned %x\n", Status));
|
|
|
|
if (Status == STATUS_SUCCESS)
|
|
{
|
|
*OptionLength = (INT) IoStatusBlock.Information;
|
|
}
|
|
|
|
if (pDevHandle && Status == STATUS_SUCCESS)
|
|
{
|
|
*pDevHandle = DeviceHandle;
|
|
}
|
|
else
|
|
{
|
|
NtClose(DeviceHandle);
|
|
}
|
|
|
|
return IoStatusToWs(Status);
|
|
}
|
|
|
|
INT
|
|
WSHGetSocketInformation(
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN INT Level,
|
|
IN INT OptionName,
|
|
OUT PCHAR OptionValue,
|
|
OUT PINT OptionLength)
|
|
{
|
|
PWSHIRDA_SOCKET_CONTEXT pContext = HelperDllSocketContext;
|
|
|
|
UNREFERENCED_PARAMETER( SocketHandle );
|
|
UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
|
|
UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
|
|
|
|
DEBUGMSG(("WSHGetSocketInformation\n"));
|
|
|
|
if (Level == SOL_INTERNAL && OptionName == SO_CONTEXT)
|
|
{
|
|
if (OptionValue != NULL)
|
|
{
|
|
if (*OptionLength < sizeof(WSHIRDA_SOCKET_CONTEXT))
|
|
{
|
|
return WSAEFAULT;
|
|
}
|
|
|
|
RtlCopyMemory(OptionValue, pContext,
|
|
sizeof(WSHIRDA_SOCKET_CONTEXT));
|
|
}
|
|
|
|
*OptionLength = sizeof(WSHIRDA_SOCKET_CONTEXT);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if (Level == SOL_IRLMP)
|
|
{
|
|
switch (OptionName)
|
|
{
|
|
case IRLMP_ENUMDEVICES:
|
|
// need remove for at least 1 device
|
|
if (*OptionLength < (sizeof(DWORD) +
|
|
sizeof(IRDA_DEVICE_INFO)))
|
|
{
|
|
return WSAEFAULT;
|
|
}
|
|
return ControlIoctl(IOCTL_IRDA_GET_INFO_ENUM_DEV,
|
|
OptionValue, OptionLength, NULL);
|
|
|
|
case IRLMP_IAS_QUERY:
|
|
if (*OptionLength < sizeof(IAS_QUERY))
|
|
{
|
|
return WSAEFAULT;
|
|
}
|
|
return ControlIoctl(IOCTL_IRDA_QUERY_IAS,
|
|
OptionValue, OptionLength, NULL);
|
|
|
|
case IRLMP_SEND_PDU_LEN:
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
Status = NtDeviceIoControlFile(
|
|
TdiConnectionObjectHandle,
|
|
NULL, // HANDLE Event OPTIONAL
|
|
NULL, // PIO_APC_ROUTINE ApcRoutine
|
|
NULL, // PVOID ApcContext
|
|
&IoStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
|
|
IOCTL_IRDA_GET_SEND_PDU_LEN,// ULONG IoControlCode
|
|
NULL, // PVOID InputBuffer
|
|
0, // ULONG InputBufferLength
|
|
OptionValue, // PVOID OutputBuffer
|
|
sizeof(DWORD)); // ULONG OutputBufferLength
|
|
|
|
return IoStatusToWs(Status);
|
|
}
|
|
}
|
|
}
|
|
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
INT
|
|
WSHSetSocketInformation(
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN INT Level,
|
|
IN INT OptionName,
|
|
IN PCHAR OptionValue,
|
|
IN INT OptionLength)
|
|
{
|
|
PWSHIRDA_SOCKET_CONTEXT pSocketContext =
|
|
(PWSHIRDA_SOCKET_CONTEXT) HelperDllSocketContext;
|
|
|
|
DEBUGMSG(("WSHSetSocketInformation\n"));
|
|
|
|
if (Level == SOL_INTERNAL && OptionName == SO_CONTEXT)
|
|
{
|
|
int CopyOffset;
|
|
|
|
if (OptionLength < sizeof(WSHIRDA_SOCKET_CONTEXT))
|
|
return WSAEINVAL;
|
|
|
|
if (HelperDllSocketContext == NULL)
|
|
{
|
|
// Socket was inherited or duped, create a new context.
|
|
if ((pSocketContext =
|
|
RtlAllocateHeap(RtlProcessHeap(), 0,
|
|
sizeof(WSHIRDA_SOCKET_CONTEXT)))
|
|
== NULL)
|
|
{
|
|
return WSAENOBUFS;
|
|
}
|
|
|
|
// Copy the parent's context into the child's context.
|
|
RtlCopyMemory(pSocketContext, OptionValue,
|
|
sizeof(WSHIRDA_SOCKET_CONTEXT));
|
|
|
|
pSocketContext->pIasAttribs = NULL;
|
|
|
|
// Return the address of the new context in pOptionVal.
|
|
*(PWSHIRDA_SOCKET_CONTEXT *) OptionValue = pSocketContext;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
// The socket was accept()'ed and it needs to have the same
|
|
// properties as it's parent. The OptionValue buffer
|
|
// contains the context information of this socket's parent.
|
|
CopyOffset = FIELD_OFFSET(WSHIRDA_SOCKET_CONTEXT, AddressFamily);
|
|
RtlCopyMemory((char *) pSocketContext + CopyOffset,
|
|
OptionValue + CopyOffset,
|
|
sizeof(WSHIRDA_SOCKET_CONTEXT) - CopyOffset);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if (Level == SOL_IRLMP)
|
|
{
|
|
switch (OptionName)
|
|
{
|
|
case IRLMP_IRLPT_MODE:
|
|
DEBUGMSG(("Set options for %x\n", pSocketContext));
|
|
pSocketContext->Options |= OPT_IRLPT_MODE;
|
|
return NO_ERROR;
|
|
|
|
case IRLMP_9WIRE_MODE:
|
|
pSocketContext->Options |= OPT_9WIRE_MODE;
|
|
return NO_ERROR;
|
|
|
|
case IRLMP_IAS_SET:
|
|
{
|
|
INT rc;
|
|
PWSHIRDA_IAS_ATTRIBUTE pIasAttrib;
|
|
INT OptLen;
|
|
PWSHIRDA_SOCKET_CONTEXT SockContext = (PWSHIRDA_SOCKET_CONTEXT) HelperDllSocketContext;
|
|
HANDLE AttribHandle;
|
|
|
|
rc = ControlIoctl(IOCTL_IRDA_SET_IAS,
|
|
OptionValue, &OptionLength, &AttribHandle);
|
|
|
|
if (rc == NO_ERROR)
|
|
{
|
|
if ((pIasAttrib = RtlAllocateHeap(RtlProcessHeap(), 0,
|
|
sizeof(WSHIRDA_SOCKET_CONTEXT))) == NULL)
|
|
{
|
|
rc = WSAENOBUFS;
|
|
}
|
|
else
|
|
{
|
|
pIasAttrib->AttribHandle = AttribHandle;
|
|
|
|
EnterCriticalSection(&IrdaCs);
|
|
|
|
DEBUGMSG(("Added attrib %x to socket %x\n",
|
|
AttribHandle, SockContext));
|
|
|
|
pIasAttrib->pNext = SockContext->pIasAttribs;
|
|
SockContext->pIasAttribs = pIasAttrib;
|
|
|
|
LeaveCriticalSection(&IrdaCs);
|
|
}
|
|
}
|
|
|
|
if (rc != NO_ERROR && AttribHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(AttribHandle);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
INT
|
|
WSHGetWildcardSockaddr(
|
|
IN PVOID HelperDllSocketContext,
|
|
OUT PSOCKADDR Sockaddr,
|
|
OUT PINT SockaddrLength)
|
|
{
|
|
|
|
DEBUGMSG(("WSHGetWildcarSockaddr\n"));
|
|
|
|
if (*SockaddrLength < sizeof(SOCKADDR_IRDA))
|
|
{
|
|
return WSAEFAULT;
|
|
}
|
|
|
|
*SockaddrLength = sizeof(SOCKADDR_IRDA);
|
|
|
|
RtlZeroMemory(Sockaddr, sizeof(SOCKADDR_IRDA));
|
|
|
|
Sockaddr->sa_family = AF_IRDA;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
WSHGetWinsockMapping(
|
|
OUT PWINSOCK_MAPPING Mapping,
|
|
IN DWORD MappingLength)
|
|
{
|
|
|
|
DEBUGMSG(("WSHGetWinsockMapping\n"));
|
|
|
|
if (MappingLength >= sizeof(IrDAMapping))
|
|
RtlMoveMemory(Mapping, &IrDAMapping, sizeof(IRDA_WINSOCK_MAPPING));
|
|
|
|
return(sizeof(IRDA_WINSOCK_MAPPING));
|
|
}
|
|
|
|
//****************************************************************************
|
|
//
|
|
//
|
|
INT
|
|
WSHOpenSocket(
|
|
IN OUT PINT AddressFamily,
|
|
IN OUT PINT SocketType,
|
|
IN OUT PINT Protocol,
|
|
OUT PUNICODE_STRING TransportDeviceName,
|
|
OUT PVOID *HelperDllSocketContext,
|
|
OUT PDWORD NotificationEvents)
|
|
{
|
|
PWSHIRDA_SOCKET_CONTEXT pSocket;
|
|
|
|
if (*AddressFamily != (int) IrDAMapping.Mapping[0].AddressFamily)
|
|
return WSAEINVAL;
|
|
|
|
ASSERT(IrDAMapping.Rows == 3);
|
|
|
|
if (! ((*SocketType == (int) IrDAMapping.Mapping[0].SocketType &&
|
|
*Protocol == (int) IrDAMapping.Mapping[0].Protocol) ||
|
|
(*SocketType == (int) IrDAMapping.Mapping[1].SocketType &&
|
|
*Protocol == (int) IrDAMapping.Mapping[1].Protocol) ||
|
|
(*SocketType == (int) IrDAMapping.Mapping[2].SocketType &&
|
|
*Protocol == (int) IrDAMapping.Mapping[2].Protocol)))
|
|
{
|
|
DEBUGMSG(("WSHOpenSocket failed! WSAEINVAL\n"));
|
|
return WSAEINVAL;
|
|
}
|
|
|
|
RtlInitUnicodeString(TransportDeviceName, IRDA_DEVICE_NAME);
|
|
|
|
if ((pSocket = RtlAllocateHeap(RtlProcessHeap(),
|
|
0, sizeof(WSHIRDA_SOCKET_CONTEXT))) == NULL)
|
|
{
|
|
DEBUGMSG(("WSHOpenSocket failed! WSAENOBUFS\n"));
|
|
return WSAENOBUFS;
|
|
}
|
|
|
|
*HelperDllSocketContext = pSocket;
|
|
|
|
pSocket->AddressFamily = AF_IRDA;
|
|
pSocket->SocketType = SOCK_STREAM;
|
|
pSocket->Protocol = IRDA_PROTO_SOCK_STREAM;
|
|
pSocket->Options = 0;
|
|
pSocket->pIasAttribs = NULL;
|
|
pSocket->LazyDscvDevHandle = NULL;
|
|
|
|
*NotificationEvents = WSH_NOTIFY_CLOSE | WSH_NOTIFY_BIND;
|
|
|
|
DEBUGMSG(("WSHOpenSocket %X\n", pSocket));
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
VOID
|
|
DeleteSocketAttribs(PWSHIRDA_SOCKET_CONTEXT pSocket)
|
|
{
|
|
PWSHIRDA_IAS_ATTRIBUTE pIasAttrib;
|
|
|
|
// Assumes IrdaCs is held
|
|
|
|
DEBUGMSG(("Delete attribs for socket %X\n", pSocket));
|
|
|
|
while (pSocket->pIasAttribs)
|
|
{
|
|
pIasAttrib = pSocket->pIasAttribs;
|
|
|
|
pSocket->pIasAttribs = pIasAttrib->pNext;
|
|
|
|
DEBUGMSG(("Delete attrib %x socket %x\n",
|
|
pIasAttrib->AttribHandle, pSocket));
|
|
|
|
CloseHandle(pIasAttrib->AttribHandle);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, pIasAttrib);
|
|
}
|
|
}
|
|
|
|
INT
|
|
WSHNotify(
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN DWORD NotifyEvent)
|
|
{
|
|
PWSHIRDA_SOCKET_CONTEXT pSocket = HelperDllSocketContext;
|
|
|
|
DEBUGMSG(("WSHNotify\n"));
|
|
|
|
switch (NotifyEvent)
|
|
{
|
|
case WSH_NOTIFY_CLOSE:
|
|
DEBUGMSG(("WSH_NOTIFY_CLOSE %x\n", pSocket));
|
|
|
|
EnterCriticalSection(&IrdaCs);
|
|
|
|
DeleteSocketAttribs(pSocket);
|
|
|
|
LeaveCriticalSection(&IrdaCs);
|
|
|
|
if (pSocket->LazyDscvDevHandle != NULL)
|
|
{
|
|
NtClose(pSocket->LazyDscvDevHandle);
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, pSocket);
|
|
|
|
break;
|
|
|
|
case WSH_NOTIFY_CONNECT:
|
|
DEBUGMSG(("WSH_NOTIFY_CONNECT\n"));
|
|
break;
|
|
|
|
case WSH_NOTIFY_BIND:
|
|
DEBUGMSG(("WSH_NOTIFY_BIND AddrObj:%x, ConnObj:%x Context %x Options %d\n",
|
|
TdiAddressObjectHandle, TdiConnectionObjectHandle,
|
|
pSocket, pSocket->Options));
|
|
|
|
if (pSocket->Options != 0)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
Status = NtDeviceIoControlFile(
|
|
TdiAddressObjectHandle,
|
|
NULL, // HANDLE Event OPTIONAL
|
|
NULL, // PIO_APC_ROUTINE ApcRoutine
|
|
NULL, // PVOID ApcContext
|
|
&IoStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
|
|
IOCTL_IRDA_SET_OPTIONS, // ULONG IoControlCode
|
|
(char *) &pSocket->Options, // PVOID InputBuffer
|
|
sizeof(DWORD), // ULONG InputBufferLength
|
|
NULL, // PVOID OutputBuffer
|
|
0); // ULONG OutputBufferLength
|
|
|
|
DEBUGMSG(("IOCTL_IRDA_SET_OPTIONS rc %x\n", Status));
|
|
|
|
}
|
|
break;
|
|
|
|
case WSH_NOTIFY_LISTEN:
|
|
DEBUGMSG(("WSH_NOTIFY_LISTEN\n"));
|
|
break;
|
|
|
|
case WSH_NOTIFY_ACCEPT:
|
|
DEBUGMSG(("WSH_NOTIFY_ACCEPT\n"));
|
|
break;
|
|
|
|
default:
|
|
DEBUGMSG(("WSHNotify unknown event %d\n", NotifyEvent));
|
|
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
INT
|
|
WSHEnumProtocols(
|
|
IN LPINT lpiProtocols,
|
|
IN LPWSTR lpTransportKeyName,
|
|
IN OUT LPVOID lpProtocolBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength)
|
|
{
|
|
BOOL UseIrDA = FALSE;
|
|
PPROTOCOL_INFO pIrDAProtocolInfo;
|
|
DWORD BytesRequired;
|
|
DWORD i;
|
|
|
|
lpTransportKeyName; // Avoid compiler warnings.
|
|
|
|
DEBUGMSG(("WSHEnumProtocols\n"));
|
|
|
|
if (ARGUMENT_PRESENT(lpiProtocols))
|
|
{
|
|
for (i = 0; lpiProtocols[i] != 0; i++)
|
|
{
|
|
if (lpiProtocols[i] == IRDA_PROTO_SOCK_STREAM)
|
|
{
|
|
UseIrDA = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UseIrDA = TRUE;
|
|
}
|
|
|
|
if (! UseIrDA)
|
|
{
|
|
*lpdwBufferLength = 0;
|
|
return 0;
|
|
}
|
|
|
|
BytesRequired = sizeof(PROTOCOL_INFO) +
|
|
((wcslen(IRDA_NAME) + 1) * sizeof(WCHAR));
|
|
|
|
if (BytesRequired > *lpdwBufferLength)
|
|
{
|
|
*lpdwBufferLength = BytesRequired;
|
|
return -1;
|
|
}
|
|
|
|
pIrDAProtocolInfo = lpProtocolBuffer;
|
|
|
|
pIrDAProtocolInfo->dwServiceFlags =
|
|
XP_GUARANTEED_DELIVERY |
|
|
XP_GUARANTEED_ORDER;
|
|
pIrDAProtocolInfo->iAddressFamily = AF_IRDA;
|
|
pIrDAProtocolInfo->iMaxSockAddr = MIN_SOCKADDR_LEN;
|
|
pIrDAProtocolInfo->iMinSockAddr = MAX_SOCKADDR_LEN;
|
|
pIrDAProtocolInfo->iSocketType = SOCK_STREAM;
|
|
pIrDAProtocolInfo->iProtocol = IRDA_PROTO_SOCK_STREAM;
|
|
pIrDAProtocolInfo->dwMessageSize = 0;
|
|
pIrDAProtocolInfo->lpProtocol = (LPWSTR)
|
|
((PBYTE) lpProtocolBuffer + *lpdwBufferLength -
|
|
((wcslen(IRDA_NAME) + 1) * sizeof(WCHAR)));
|
|
|
|
wcscpy(pIrDAProtocolInfo->lpProtocol, IRDA_NAME );
|
|
|
|
*lpdwBufferLength = BytesRequired;
|
|
|
|
return (1);
|
|
}
|
|
|
|
INT
|
|
WINAPI
|
|
WSHGetWSAProtocolInfo (
|
|
IN LPWSTR ProviderName,
|
|
OUT LPWSAPROTOCOL_INFOW * ProtocolInfo,
|
|
OUT LPDWORD ProtocolInfoEntries
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves a pointer to the WSAPROTOCOL_INFOW structure(s) describing
|
|
the protocol(s) supported by this helper.
|
|
|
|
Arguments:
|
|
|
|
ProviderName - Contains the name of the provider, such as "TcpIp".
|
|
|
|
ProtocolInfo - Receives a pointer to the WSAPROTOCOL_INFOW array.
|
|
|
|
ProtocolInfoEntries - Receives the number of entries in the array.
|
|
|
|
Return Value:
|
|
|
|
INT - 0 if successful, WinSock error code if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DEBUGMSG(("WSHGetWSAProtocolInfo\n"));
|
|
|
|
if( ProviderName == NULL ||
|
|
ProtocolInfo == NULL ||
|
|
ProtocolInfoEntries == NULL ) {
|
|
|
|
return WSAEFAULT;
|
|
|
|
}
|
|
|
|
if( _wcsicmp( ProviderName, L"IrDA" ) == 0 ) {
|
|
|
|
*ProtocolInfo = Winsock2Protocols;
|
|
*ProtocolInfoEntries = 1;
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
return WSAEINVAL;
|
|
|
|
} // WSHGetWSAProtocolInfo
|
|
|
|
INT
|
|
WINAPI
|
|
WSHGetProviderGuid (
|
|
IN LPWSTR ProviderName,
|
|
OUT LPGUID ProviderGuid
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the GUID identifying the protocols supported by this helper.
|
|
|
|
Arguments:
|
|
|
|
ProviderName - Contains the name of the provider, such as "TcpIp".
|
|
|
|
ProviderGuid - Points to a buffer that receives the provider's GUID.
|
|
|
|
Return Value:
|
|
|
|
INT - 0 if successful, WinSock error code if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if( ProviderName == NULL ||
|
|
ProviderGuid == NULL ) {
|
|
|
|
return WSAEFAULT;
|
|
|
|
}
|
|
|
|
if( _wcsicmp( ProviderName, L"irda" ) == 0 ) {
|
|
|
|
RtlCopyMemory(
|
|
ProviderGuid,
|
|
&IrdaProviderGuid,
|
|
sizeof(GUID)
|
|
);
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
return WSAEINVAL;
|
|
|
|
} // WSHGetProviderGuid
|
|
|
|
VOID
|
|
WINAPI
|
|
IoctlCompletionRoutine (
|
|
PVOID ApcContext,
|
|
PIO_STATUS_BLOCK IoStatusBlock,
|
|
DWORD Reserved
|
|
)
|
|
{
|
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine;
|
|
LPWSAOVERLAPPED lpOverlapped;
|
|
DWORD dwErrorCode = 0;
|
|
DWORD dwNumberOfBytesTransfered;
|
|
DWORD dwFlags = 0;
|
|
|
|
DEBUGMSG(("IoctlCompletionRoutine\n"));
|
|
|
|
if (NT_ERROR(IoStatusBlock->Status))
|
|
{
|
|
if (IoStatusBlock->Status != STATUS_CANCELLED)
|
|
{
|
|
dwErrorCode = IoStatusToWs(IoStatusBlock->Status);
|
|
}
|
|
else
|
|
{
|
|
dwErrorCode = WSA_OPERATION_ABORTED;
|
|
}
|
|
|
|
dwNumberOfBytesTransfered = 0;
|
|
}
|
|
else
|
|
{
|
|
dwErrorCode = 0;
|
|
dwNumberOfBytesTransfered = (ULONG) IoStatusBlock->Information;
|
|
}
|
|
|
|
CompletionRoutine = (LPWSAOVERLAPPED_COMPLETION_ROUTINE)ApcContext;
|
|
lpOverlapped = (LPWSAOVERLAPPED)CONTAINING_RECORD(IoStatusBlock,WSAOVERLAPPED,Internal);
|
|
|
|
(CompletionRoutine)(
|
|
dwErrorCode,
|
|
dwNumberOfBytesTransfered,
|
|
lpOverlapped,
|
|
dwFlags);
|
|
}
|
|
|
|
INT
|
|
WSHIoctl(
|
|
IN PVOID HelperDllSocketContext,
|
|
IN SOCKET SocketHandle,
|
|
IN HANDLE TdiAddressObjectHandle,
|
|
IN HANDLE TdiConnectionObjectHandle,
|
|
IN DWORD IoControlCode,
|
|
IN LPVOID InputBuffer,
|
|
IN DWORD InputBufferLength,
|
|
IN LPVOID OutputBuffer,
|
|
IN DWORD OutputBufferLength,
|
|
OUT LPDWORD NumberOfBytesReturned,
|
|
IN LPWSAOVERLAPPED Overlapped,
|
|
IN LPWSAOVERLAPPED_COMPLETION_ROUTINE CallerCompletionRoutine,
|
|
OUT LPBOOL NeedsCompletion)
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjAttr;
|
|
UNICODE_STRING DeviceName;
|
|
HANDLE DeviceHandle;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
BOOL Result;
|
|
PWSHIRDA_SOCKET_CONTEXT pSocket = HelperDllSocketContext;
|
|
PIO_APC_ROUTINE apcRoutine;
|
|
|
|
DEBUGMSG(("WSHIoctl: Sock %d, AddrObj %X, ConnObj %X\n", SocketHandle,
|
|
TdiAddressObjectHandle, TdiConnectionObjectHandle));
|
|
|
|
if (HelperDllSocketContext == NULL ||
|
|
SocketHandle == INVALID_SOCKET ||
|
|
NumberOfBytesReturned == NULL ||
|
|
NeedsCompletion == NULL ||
|
|
IoControlCode != SIO_LAZY_DISCOVERY ||
|
|
(CallerCompletionRoutine != NULL && Overlapped == NULL) ||
|
|
// I am using the Overlapped for the IoStatusBlock
|
|
// for the completion routine so if a CallerCompletionRoutine
|
|
// is specified, an Overlapped must be passed in as well
|
|
OutputBufferLength < (sizeof(DWORD) + sizeof(IRDA_DEVICE_INFO)))
|
|
{
|
|
return WSAEINVAL;
|
|
|
|
}
|
|
|
|
*NeedsCompletion = FALSE;
|
|
|
|
*NumberOfBytesReturned = OutputBufferLength;
|
|
|
|
if (pSocket->LazyDscvDevHandle == NULL)
|
|
{
|
|
RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjAttr,
|
|
&DeviceName,
|
|
OBJ_INHERIT | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
|
|
Status = NtCreateFile(
|
|
&pSocket->LazyDscvDevHandle, // PHANDLE FileHandle
|
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,//SYNCHRONIZE | GENERIC_EXECUTE, // ACCESS_MASK DesiredAccess
|
|
&ObjAttr, // POBJECT_ATTRIBUTES ObjAttr
|
|
&IoStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
|
|
NULL, // PLARGE_INTEGER AllocationSize
|
|
0, // ULONG FileAttributes
|
|
FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE, // ULONG ShareAccess
|
|
FILE_OPEN_IF, // ULONG CreateDisposition
|
|
0, // ULONG CreateOptions
|
|
NULL, // PVOID EaBuffer
|
|
0); // ULONG EaLength
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return WSAEINVAL;
|
|
}
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
if (CallerCompletionRoutine == NULL)
|
|
{
|
|
// let Win32 do the dirty work
|
|
|
|
DEBUGMSG(("No CallerCompletionRoutine, using DeviceIoControl()\n"));
|
|
Result = DeviceIoControl(pSocket->LazyDscvDevHandle,
|
|
IOCTL_IRDA_LAZY_DISCOVERY,
|
|
NULL, 0, OutputBuffer, OutputBufferLength,
|
|
NumberOfBytesReturned, Overlapped);
|
|
|
|
if (Result == FALSE)
|
|
{
|
|
Status = GetLastError();
|
|
|
|
if (Status == ERROR_IO_PENDING)
|
|
{
|
|
Status = STATUS_PENDING;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DEBUGMSG(("Using NtDeviceIoControlFile\n"));
|
|
|
|
Status = NtDeviceIoControlFile(
|
|
pSocket->LazyDscvDevHandle,
|
|
NULL,
|
|
IoctlCompletionRoutine,
|
|
CallerCompletionRoutine,
|
|
(PIO_STATUS_BLOCK)&Overlapped->Internal,
|
|
IOCTL_IRDA_LAZY_DISCOVERY,
|
|
NULL,
|
|
0,
|
|
OutputBuffer,
|
|
OutputBufferLength);
|
|
|
|
if (Status == STATUS_SUCCESS)
|
|
{
|
|
*NumberOfBytesReturned = (DWORD) IoStatusBlock.Information;
|
|
}
|
|
}
|
|
|
|
DEBUGMSG(("IoControlFile returned %x\n", Status));
|
|
|
|
return IoStatusToWs(Status);
|
|
}
|