/*++ 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 #include #include #include #include #include #include #include #include #include #include #include #include typedef unsigned long ulong; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned char uchar; #define NT /* for tdiinfo.h */ #include #include #include #include #include #include #include #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); }