windows-nt/Source/XPSP1/NT/net/irda/winsock/wshirda.c
2020-09-26 16:20:57 +08:00

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);
}