Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1178 lines
34 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. WshIrDA.c
  5. Abstract:
  6. This module contains necessary routines for the IrDA Windows Sockets
  7. Helper DLL. This DLL provides the transport-specific support necessary
  8. for the Windows Sockets DLL to use IrDA as a transport.
  9. Author:
  10. Zed (mikezin) 28-Aug-1996
  11. mbert Sept 97
  12. --*/
  13. #define UNICODE
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <windows.h>
  18. #include <stdio.h>
  19. #include <ctype.h>
  20. #include <wchar.h>
  21. #include <tdi.h>
  22. #include <winsock2.h>
  23. #include <wsahelp.h>
  24. #include <tdistat.h>
  25. #include <tdiinfo.h>
  26. #include <llinfo.h>
  27. typedef unsigned long ulong;
  28. typedef unsigned short ushort;
  29. typedef unsigned int uint;
  30. typedef unsigned char uchar;
  31. #define NT /* for tdiinfo.h */
  32. #include <tdiinfo.h>
  33. #include <basetyps.h>
  34. #include <nspapi.h>
  35. #include <nspapip.h>
  36. #include <af_irda.h>
  37. #include <irioctl.h>
  38. #include <irdatdi.h>
  39. #define MIN_SOCKADDR_LEN 8
  40. #define MAX_SOCKADDR_LEN sizeof(SOCKADDR_IRDA)
  41. #ifdef _NOT_DBG
  42. //#ifdef DBG
  43. #define DEBUGMSG(s) DbgPrint s
  44. #else
  45. #define DEBUGMSG(s)
  46. #endif
  47. typedef struct WshIrdaIasAttrib
  48. {
  49. HANDLE AttribHandle;
  50. struct WshIrdaIasAttrib *pNext;
  51. } WSHIRDA_IAS_ATTRIBUTE, *PWSHIRDA_IAS_ATTRIBUTE;
  52. typedef struct _WSHIRDA_SOCKET_CONTEXT
  53. {
  54. PWSHIRDA_IAS_ATTRIBUTE pIasAttribs;
  55. // all fields copied from parent to child (at accept) must follow
  56. // (see SetSocketInformation SO_CONTEXT)
  57. INT AddressFamily;
  58. INT SocketType;
  59. INT Protocol;
  60. DWORD Options;
  61. HANDLE LazyDscvDevHandle;
  62. } WSHIRDA_SOCKET_CONTEXT, *PWSHIRDA_SOCKET_CONTEXT;
  63. typedef struct
  64. {
  65. DWORD Rows;
  66. DWORD Columns;
  67. struct {
  68. DWORD AddressFamily;
  69. DWORD SocketType;
  70. DWORD Protocol;
  71. } Mapping[3];
  72. } IRDA_WINSOCK_MAPPING;
  73. const IRDA_WINSOCK_MAPPING IrDAMapping =
  74. { 3, 3,
  75. AF_IRDA, SOCK_STREAM, IRDA_PROTO_SOCK_STREAM,
  76. AF_IRDA, SOCK_STREAM, 0,
  77. AF_IRDA, 0, IRDA_PROTO_SOCK_STREAM };
  78. WSAPROTOCOL_INFOW Winsock2Protocols[] =
  79. {
  80. {
  81. XP1_GUARANTEED_DELIVERY // dwServiceFlags1
  82. | XP1_GUARANTEED_ORDER
  83. | XP1_IFS_HANDLES,
  84. 0, // dwServiceFlags2
  85. 0, // dwServiceFlags3
  86. 0, // dwServiceFlags4
  87. PFL_MATCHES_PROTOCOL_ZERO, // dwProviderFlags
  88. { // gProviderId
  89. 0, 0, 0,
  90. { 0, 0, 0, 0, 0, 0, 0, 0 }
  91. },
  92. 0, // dwCatalogEntryId
  93. { // ProtocolChain
  94. BASE_PROTOCOL, // ChainLen
  95. { 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
  96. },
  97. 2, // iVersion
  98. AF_IRDA, // iAddressFamily
  99. // winsock doesn't seem to use min and max here,
  100. // it gets it from inf and is stored
  101. // in CCS\services\irda\parameters\winsock
  102. sizeof(SOCKADDR_IRDA), // iMaxSockAddr
  103. 8, // iMinSockAddr
  104. SOCK_STREAM, // iSocketType
  105. IRDA_PROTO_SOCK_STREAM, // iProtocol
  106. 0, // iProtocolMaxOffset
  107. BIGENDIAN, // iNetworkByteOrder
  108. SECURITY_PROTOCOL_NONE, // iSecurityScheme
  109. 0, // dwMessageSize
  110. 0, // dwProviderReserved
  111. L"MSAFD Irda [IrDA]" // szProtocol
  112. }
  113. };
  114. GUID IrdaProviderGuid = { /* 3972523d-2af1-11d1-b655-00805f3642cc */
  115. 0x3972523d,
  116. 0x2af1,
  117. 0x11d1,
  118. {0xb6, 0x55, 0x00, 0x80, 0x5f, 0x36, 0x42, 0xcc}
  119. };
  120. VOID
  121. DeleteSocketAttribs(PWSHIRDA_SOCKET_CONTEXT pSocket);
  122. // globals
  123. CRITICAL_SECTION IrdaCs;
  124. BOOLEAN
  125. DllInitialize(
  126. IN PVOID DllHandle,
  127. IN ULONG Reason,
  128. IN PVOID Context OPTIONAL)
  129. {
  130. switch(Reason)
  131. {
  132. case DLL_PROCESS_ATTACH:
  133. // We don't need to receive thread attach and detach
  134. // notifications, so disable them to help application
  135. // performance.
  136. DisableThreadLibraryCalls(DllHandle);
  137. try
  138. {
  139. InitializeCriticalSection(&IrdaCs);
  140. }
  141. except (STATUS_NO_MEMORY == GetExceptionCode())
  142. {
  143. return FALSE;
  144. }
  145. return TRUE;
  146. case DLL_THREAD_ATTACH:
  147. break;
  148. case DLL_PROCESS_DETACH:
  149. DeleteCriticalSection(&IrdaCs);
  150. break;
  151. case DLL_THREAD_DETACH:
  152. break;
  153. }
  154. return TRUE;
  155. }
  156. INT
  157. IoStatusToWs(NTSTATUS Status)
  158. {
  159. switch (Status)
  160. {
  161. case STATUS_SUCCESS:
  162. return NO_ERROR;
  163. case STATUS_PENDING:
  164. return ERROR_IO_PENDING;
  165. case STATUS_INVALID_HANDLE:
  166. case STATUS_OBJECT_TYPE_MISMATCH:
  167. return WSAENOTSOCK;
  168. case STATUS_INVALID_PARAMETER:
  169. case STATUS_ADDRESS_CLOSED:
  170. case STATUS_CONNECTION_INVALID:
  171. case STATUS_ADDRESS_ALREADY_ASSOCIATED:
  172. case STATUS_ADDRESS_NOT_ASSOCIATED:
  173. case STATUS_CONNECTION_ACTIVE:
  174. case STATUS_INVALID_DEVICE_STATE:
  175. case STATUS_INVALID_DEVICE_REQUEST:
  176. return WSAEINVAL;
  177. case STATUS_INSUFFICIENT_RESOURCES:
  178. case STATUS_PAGEFILE_QUOTA:
  179. case STATUS_COMMITMENT_LIMIT:
  180. case STATUS_WORKING_SET_QUOTA:
  181. case STATUS_NO_MEMORY:
  182. case STATUS_CONFLICTING_ADDRESSES:
  183. case STATUS_QUOTA_EXCEEDED:
  184. case STATUS_TOO_MANY_PAGING_FILES:
  185. case STATUS_REMOTE_RESOURCES:
  186. case STATUS_TOO_MANY_ADDRESSES:
  187. return WSAENOBUFS;
  188. case STATUS_SHARING_VIOLATION:
  189. case STATUS_ADDRESS_ALREADY_EXISTS:
  190. return WSAEADDRINUSE;
  191. case STATUS_LINK_TIMEOUT:
  192. case STATUS_IO_TIMEOUT:
  193. case STATUS_TIMEOUT:
  194. return WSAETIMEDOUT;
  195. case STATUS_GRACEFUL_DISCONNECT:
  196. return WSAEDISCON;
  197. case STATUS_REMOTE_DISCONNECT:
  198. case STATUS_CONNECTION_RESET:
  199. case STATUS_LINK_FAILED:
  200. case STATUS_CONNECTION_DISCONNECTED:
  201. return WSAECONNRESET;
  202. case STATUS_LOCAL_DISCONNECT:
  203. case STATUS_TRANSACTION_ABORTED:
  204. case STATUS_CONNECTION_ABORTED:
  205. return WSAECONNRESET; // WSAECONNABORTED; Make HAPI happy
  206. case STATUS_INVALID_NETWORK_RESPONSE:
  207. return WSAENETDOWN;
  208. case STATUS_BAD_NETWORK_PATH:
  209. case STATUS_NETWORK_UNREACHABLE:
  210. case STATUS_PROTOCOL_UNREACHABLE:
  211. return WSAENETUNREACH;
  212. case STATUS_HOST_UNREACHABLE:
  213. return WSAEHOSTUNREACH;
  214. case STATUS_CANCELLED:
  215. case STATUS_REQUEST_ABORTED:
  216. return WSAEINTR;
  217. case STATUS_BUFFER_OVERFLOW:
  218. case STATUS_INVALID_BUFFER_SIZE:
  219. return WSAEMSGSIZE;
  220. case STATUS_BUFFER_TOO_SMALL:
  221. case STATUS_ACCESS_VIOLATION:
  222. return WSAEFAULT;
  223. case STATUS_DEVICE_NOT_READY:
  224. case STATUS_REQUEST_NOT_ACCEPTED:
  225. return WSAEWOULDBLOCK;
  226. case STATUS_NETWORK_BUSY:
  227. case STATUS_NO_SUCH_DEVICE:
  228. case STATUS_NO_SUCH_FILE:
  229. case STATUS_OBJECT_PATH_NOT_FOUND:
  230. case STATUS_UNEXPECTED_NETWORK_ERROR:
  231. return WSAENETDOWN;
  232. case STATUS_INVALID_CONNECTION:
  233. return WSAENOTCONN;
  234. case STATUS_REMOTE_NOT_LISTENING:
  235. case STATUS_CONNECTION_REFUSED:
  236. return WSAECONNREFUSED;
  237. case STATUS_PIPE_DISCONNECTED:
  238. return WSAESHUTDOWN;
  239. case STATUS_INVALID_ADDRESS:
  240. case STATUS_INVALID_ADDRESS_COMPONENT:
  241. return WSAEADDRNOTAVAIL;
  242. case STATUS_NOT_SUPPORTED:
  243. case STATUS_NOT_IMPLEMENTED:
  244. return WSAEOPNOTSUPP;
  245. case STATUS_PORT_UNREACHABLE:
  246. return WSAEREMOTE;
  247. case STATUS_UNSUCCESSFUL:
  248. return WSAEINVAL;
  249. case STATUS_ACCESS_DENIED:
  250. return WSAEACCES;
  251. default:
  252. DEBUGMSG(("Didn't map NT status %X, returning WSAEINVAL\n", Status));
  253. return WSAEINVAL;
  254. }
  255. }
  256. INT
  257. WSHGetSockaddrType(
  258. IN PSOCKADDR Sockaddr,
  259. IN DWORD SockaddrLength,
  260. OUT PSOCKADDR_INFO SockaddrInfo)
  261. {
  262. UNALIGNED SOCKADDR *pSockaddr = (PSOCKADDR) Sockaddr;
  263. if (SockaddrLength < sizeof(SOCKADDR_IRDA))
  264. {
  265. DEBUGMSG(("WSHGetSockaddrType(irda): SockaddrLength(%d) < sizeof(SOCKADDR_IRDA)%d ret WSAEFAULT\n",
  266. SockaddrLength, sizeof(SOCKADDR_IRDA)));
  267. return WSAEFAULT;
  268. }
  269. if (pSockaddr->sa_family != AF_IRDA)
  270. {
  271. DEBUGMSG(("WSHGetSockaddrType(irda): pSockaddr->sa_family != AF_IRDA ret WSAEAFNOSUPPORT\n"));
  272. return WSAEAFNOSUPPORT;
  273. }
  274. if (((SOCKADDR_IRDA *) pSockaddr)->irdaServiceName[0] == 0)
  275. {
  276. SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
  277. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
  278. }
  279. else
  280. {
  281. SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
  282. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoNormal;
  283. }
  284. DEBUGMSG(("WSHGetSockaddrType(irda): returning no error\n"));
  285. return NO_ERROR;
  286. }
  287. INT
  288. ControlIoctl(
  289. ULONG IoctlCode,
  290. OUT PCHAR OptionValue,
  291. OUT PINT OptionLength,
  292. OUT HANDLE *pDevHandle)
  293. {
  294. NTSTATUS Status;
  295. OBJECT_ATTRIBUTES ObjAttr;
  296. UNICODE_STRING DeviceName;
  297. HANDLE DeviceHandle;
  298. IO_STATUS_BLOCK IoStatusBlock;
  299. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  300. if (pDevHandle)
  301. {
  302. *pDevHandle = INVALID_HANDLE_VALUE;
  303. }
  304. InitializeObjectAttributes(
  305. &ObjAttr,
  306. &DeviceName,
  307. OBJ_CASE_INSENSITIVE,
  308. NULL,
  309. NULL);
  310. Status = NtCreateFile(
  311. &DeviceHandle, // PHANDLE FileHandle
  312. SYNCHRONIZE | GENERIC_EXECUTE, // ACCESS_MASK DesiredAccess
  313. &ObjAttr, // POBJECT_ATTRIBUTES ObjAttr
  314. &IoStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
  315. NULL, // PLARGE_INTEGER AllocationSize
  316. FILE_ATTRIBUTE_NORMAL, // ULONG FileAttributes
  317. FILE_SHARE_READ |
  318. FILE_SHARE_WRITE, // ULONG ShareAccess
  319. FILE_OPEN_IF, // ULONG CreateDisposition
  320. FILE_SYNCHRONOUS_IO_NONALERT, // ULONG CreateOptions
  321. NULL, // PVOID EaBuffer
  322. 0); // ULONG EaLength
  323. if (!NT_SUCCESS(Status))
  324. {
  325. return WSAEINVAL;
  326. }
  327. Status = NtDeviceIoControlFile(
  328. DeviceHandle, // HANDLE FileHandle
  329. NULL, // HANDLE Event OPTIONAL
  330. NULL, // PIO_APC_ROUTINE ApcRoutine
  331. NULL, // PVOID ApcContext
  332. &IoStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
  333. IoctlCode, // ULONG IoControlCode
  334. OptionValue, // PVOID InputBuffer
  335. *OptionLength, // ULONG InputBufferLength
  336. OptionValue, // PVOID OutputBuffer
  337. *OptionLength); // ULONG OutputBufferLength
  338. DEBUGMSG(("IoControlFile returned %x\n", Status));
  339. if (Status == STATUS_SUCCESS)
  340. {
  341. *OptionLength = (INT) IoStatusBlock.Information;
  342. }
  343. if (pDevHandle && Status == STATUS_SUCCESS)
  344. {
  345. *pDevHandle = DeviceHandle;
  346. }
  347. else
  348. {
  349. NtClose(DeviceHandle);
  350. }
  351. return IoStatusToWs(Status);
  352. }
  353. INT
  354. WSHGetSocketInformation(
  355. IN PVOID HelperDllSocketContext,
  356. IN SOCKET SocketHandle,
  357. IN HANDLE TdiAddressObjectHandle,
  358. IN HANDLE TdiConnectionObjectHandle,
  359. IN INT Level,
  360. IN INT OptionName,
  361. OUT PCHAR OptionValue,
  362. OUT PINT OptionLength)
  363. {
  364. PWSHIRDA_SOCKET_CONTEXT pContext = HelperDllSocketContext;
  365. UNREFERENCED_PARAMETER( SocketHandle );
  366. UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
  367. UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
  368. DEBUGMSG(("WSHGetSocketInformation\n"));
  369. if (Level == SOL_INTERNAL && OptionName == SO_CONTEXT)
  370. {
  371. if (OptionValue != NULL)
  372. {
  373. if (*OptionLength < sizeof(WSHIRDA_SOCKET_CONTEXT))
  374. {
  375. return WSAEFAULT;
  376. }
  377. RtlCopyMemory(OptionValue, pContext,
  378. sizeof(WSHIRDA_SOCKET_CONTEXT));
  379. }
  380. *OptionLength = sizeof(WSHIRDA_SOCKET_CONTEXT);
  381. return NO_ERROR;
  382. }
  383. if (Level == SOL_IRLMP)
  384. {
  385. switch (OptionName)
  386. {
  387. case IRLMP_ENUMDEVICES:
  388. // need remove for at least 1 device
  389. if (*OptionLength < (sizeof(DWORD) +
  390. sizeof(IRDA_DEVICE_INFO)))
  391. {
  392. return WSAEFAULT;
  393. }
  394. return ControlIoctl(IOCTL_IRDA_GET_INFO_ENUM_DEV,
  395. OptionValue, OptionLength, NULL);
  396. case IRLMP_IAS_QUERY:
  397. if (*OptionLength < sizeof(IAS_QUERY))
  398. {
  399. return WSAEFAULT;
  400. }
  401. return ControlIoctl(IOCTL_IRDA_QUERY_IAS,
  402. OptionValue, OptionLength, NULL);
  403. case IRLMP_SEND_PDU_LEN:
  404. {
  405. NTSTATUS Status;
  406. IO_STATUS_BLOCK IoStatusBlock;
  407. Status = NtDeviceIoControlFile(
  408. TdiConnectionObjectHandle,
  409. NULL, // HANDLE Event OPTIONAL
  410. NULL, // PIO_APC_ROUTINE ApcRoutine
  411. NULL, // PVOID ApcContext
  412. &IoStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
  413. IOCTL_IRDA_GET_SEND_PDU_LEN,// ULONG IoControlCode
  414. NULL, // PVOID InputBuffer
  415. 0, // ULONG InputBufferLength
  416. OptionValue, // PVOID OutputBuffer
  417. sizeof(DWORD)); // ULONG OutputBufferLength
  418. return IoStatusToWs(Status);
  419. }
  420. }
  421. }
  422. return WSAEINVAL;
  423. }
  424. INT
  425. WSHSetSocketInformation(
  426. IN PVOID HelperDllSocketContext,
  427. IN SOCKET SocketHandle,
  428. IN HANDLE TdiAddressObjectHandle,
  429. IN HANDLE TdiConnectionObjectHandle,
  430. IN INT Level,
  431. IN INT OptionName,
  432. IN PCHAR OptionValue,
  433. IN INT OptionLength)
  434. {
  435. PWSHIRDA_SOCKET_CONTEXT pSocketContext =
  436. (PWSHIRDA_SOCKET_CONTEXT) HelperDllSocketContext;
  437. DEBUGMSG(("WSHSetSocketInformation\n"));
  438. if (Level == SOL_INTERNAL && OptionName == SO_CONTEXT)
  439. {
  440. int CopyOffset;
  441. if (OptionLength < sizeof(WSHIRDA_SOCKET_CONTEXT))
  442. return WSAEINVAL;
  443. if (HelperDllSocketContext == NULL)
  444. {
  445. // Socket was inherited or duped, create a new context.
  446. if ((pSocketContext =
  447. RtlAllocateHeap(RtlProcessHeap(), 0,
  448. sizeof(WSHIRDA_SOCKET_CONTEXT)))
  449. == NULL)
  450. {
  451. return WSAENOBUFS;
  452. }
  453. // Copy the parent's context into the child's context.
  454. RtlCopyMemory(pSocketContext, OptionValue,
  455. sizeof(WSHIRDA_SOCKET_CONTEXT));
  456. pSocketContext->pIasAttribs = NULL;
  457. // Return the address of the new context in pOptionVal.
  458. *(PWSHIRDA_SOCKET_CONTEXT *) OptionValue = pSocketContext;
  459. return NO_ERROR;
  460. }
  461. // The socket was accept()'ed and it needs to have the same
  462. // properties as it's parent. The OptionValue buffer
  463. // contains the context information of this socket's parent.
  464. CopyOffset = FIELD_OFFSET(WSHIRDA_SOCKET_CONTEXT, AddressFamily);
  465. RtlCopyMemory((char *) pSocketContext + CopyOffset,
  466. OptionValue + CopyOffset,
  467. sizeof(WSHIRDA_SOCKET_CONTEXT) - CopyOffset);
  468. return NO_ERROR;
  469. }
  470. if (Level == SOL_IRLMP)
  471. {
  472. switch (OptionName)
  473. {
  474. case IRLMP_IRLPT_MODE:
  475. DEBUGMSG(("Set options for %x\n", pSocketContext));
  476. pSocketContext->Options |= OPT_IRLPT_MODE;
  477. return NO_ERROR;
  478. case IRLMP_9WIRE_MODE:
  479. pSocketContext->Options |= OPT_9WIRE_MODE;
  480. return NO_ERROR;
  481. case IRLMP_IAS_SET:
  482. {
  483. INT rc;
  484. PWSHIRDA_IAS_ATTRIBUTE pIasAttrib;
  485. INT OptLen;
  486. PWSHIRDA_SOCKET_CONTEXT SockContext = (PWSHIRDA_SOCKET_CONTEXT) HelperDllSocketContext;
  487. HANDLE AttribHandle;
  488. rc = ControlIoctl(IOCTL_IRDA_SET_IAS,
  489. OptionValue, &OptionLength, &AttribHandle);
  490. if (rc == NO_ERROR)
  491. {
  492. pIasAttrib = RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(*pIasAttrib));
  493. if (pIasAttrib == NULL)
  494. {
  495. rc = WSAENOBUFS;
  496. }
  497. else
  498. {
  499. pIasAttrib->AttribHandle = AttribHandle;
  500. EnterCriticalSection(&IrdaCs);
  501. DEBUGMSG(("Added attrib %x to socket %x\n",
  502. AttribHandle, SockContext));
  503. pIasAttrib->pNext = SockContext->pIasAttribs;
  504. SockContext->pIasAttribs = pIasAttrib;
  505. LeaveCriticalSection(&IrdaCs);
  506. }
  507. }
  508. if (rc != NO_ERROR && AttribHandle != INVALID_HANDLE_VALUE)
  509. {
  510. CloseHandle(AttribHandle);
  511. }
  512. return rc;
  513. }
  514. }
  515. }
  516. return WSAEINVAL;
  517. }
  518. INT
  519. WSHGetWildcardSockaddr(
  520. IN PVOID HelperDllSocketContext,
  521. OUT PSOCKADDR Sockaddr,
  522. OUT PINT SockaddrLength)
  523. {
  524. DEBUGMSG(("WSHGetWildcarSockaddr\n"));
  525. if (*SockaddrLength < sizeof(SOCKADDR_IRDA))
  526. {
  527. return WSAEFAULT;
  528. }
  529. *SockaddrLength = sizeof(SOCKADDR_IRDA);
  530. RtlZeroMemory(Sockaddr, sizeof(SOCKADDR_IRDA));
  531. Sockaddr->sa_family = AF_IRDA;
  532. return NO_ERROR;
  533. }
  534. DWORD
  535. WSHGetWinsockMapping(
  536. OUT PWINSOCK_MAPPING Mapping,
  537. IN DWORD MappingLength)
  538. {
  539. DEBUGMSG(("WSHGetWinsockMapping\n"));
  540. if (MappingLength >= sizeof(IrDAMapping))
  541. RtlMoveMemory(Mapping, &IrDAMapping, sizeof(IRDA_WINSOCK_MAPPING));
  542. return(sizeof(IRDA_WINSOCK_MAPPING));
  543. }
  544. //****************************************************************************
  545. //
  546. //
  547. INT
  548. WSHOpenSocket(
  549. IN OUT PINT AddressFamily,
  550. IN OUT PINT SocketType,
  551. IN OUT PINT Protocol,
  552. OUT PUNICODE_STRING TransportDeviceName,
  553. OUT PVOID *HelperDllSocketContext,
  554. OUT PDWORD NotificationEvents)
  555. {
  556. PWSHIRDA_SOCKET_CONTEXT pSocket;
  557. if (*AddressFamily != (int) IrDAMapping.Mapping[0].AddressFamily)
  558. return WSAEINVAL;
  559. ASSERT(IrDAMapping.Rows == 3);
  560. if (! ((*SocketType == (int) IrDAMapping.Mapping[0].SocketType &&
  561. *Protocol == (int) IrDAMapping.Mapping[0].Protocol) ||
  562. (*SocketType == (int) IrDAMapping.Mapping[1].SocketType &&
  563. *Protocol == (int) IrDAMapping.Mapping[1].Protocol) ||
  564. (*SocketType == (int) IrDAMapping.Mapping[2].SocketType &&
  565. *Protocol == (int) IrDAMapping.Mapping[2].Protocol)))
  566. {
  567. DEBUGMSG(("WSHOpenSocket failed! WSAEINVAL\n"));
  568. return WSAEINVAL;
  569. }
  570. RtlInitUnicodeString(TransportDeviceName, IRDA_DEVICE_NAME);
  571. if ((pSocket = RtlAllocateHeap(RtlProcessHeap(),
  572. 0, sizeof(WSHIRDA_SOCKET_CONTEXT))) == NULL)
  573. {
  574. DEBUGMSG(("WSHOpenSocket failed! WSAENOBUFS\n"));
  575. return WSAENOBUFS;
  576. }
  577. *HelperDllSocketContext = pSocket;
  578. pSocket->AddressFamily = AF_IRDA;
  579. pSocket->SocketType = SOCK_STREAM;
  580. pSocket->Protocol = IRDA_PROTO_SOCK_STREAM;
  581. pSocket->Options = 0;
  582. pSocket->pIasAttribs = NULL;
  583. pSocket->LazyDscvDevHandle = NULL;
  584. *NotificationEvents = WSH_NOTIFY_CLOSE | WSH_NOTIFY_BIND;
  585. DEBUGMSG(("WSHOpenSocket %X\n", pSocket));
  586. return NO_ERROR;
  587. }
  588. VOID
  589. DeleteSocketAttribs(PWSHIRDA_SOCKET_CONTEXT pSocket)
  590. {
  591. PWSHIRDA_IAS_ATTRIBUTE pIasAttrib;
  592. // Assumes IrdaCs is held
  593. DEBUGMSG(("Delete attribs for socket %X\n", pSocket));
  594. while (pSocket->pIasAttribs)
  595. {
  596. pIasAttrib = pSocket->pIasAttribs;
  597. pSocket->pIasAttribs = pIasAttrib->pNext;
  598. DEBUGMSG(("Delete attrib %x socket %x\n",
  599. pIasAttrib->AttribHandle, pSocket));
  600. CloseHandle(pIasAttrib->AttribHandle);
  601. RtlFreeHeap(RtlProcessHeap(), 0, pIasAttrib);
  602. }
  603. }
  604. INT
  605. WSHNotify(
  606. IN PVOID HelperDllSocketContext,
  607. IN SOCKET SocketHandle,
  608. IN HANDLE TdiAddressObjectHandle,
  609. IN HANDLE TdiConnectionObjectHandle,
  610. IN DWORD NotifyEvent)
  611. {
  612. PWSHIRDA_SOCKET_CONTEXT pSocket = HelperDllSocketContext;
  613. DEBUGMSG(("WSHNotify\n"));
  614. switch (NotifyEvent)
  615. {
  616. case WSH_NOTIFY_CLOSE:
  617. DEBUGMSG(("WSH_NOTIFY_CLOSE %x\n", pSocket));
  618. EnterCriticalSection(&IrdaCs);
  619. DeleteSocketAttribs(pSocket);
  620. LeaveCriticalSection(&IrdaCs);
  621. if (pSocket->LazyDscvDevHandle != NULL)
  622. {
  623. NtClose(pSocket->LazyDscvDevHandle);
  624. }
  625. RtlFreeHeap(RtlProcessHeap(), 0, pSocket);
  626. break;
  627. case WSH_NOTIFY_CONNECT:
  628. DEBUGMSG(("WSH_NOTIFY_CONNECT\n"));
  629. break;
  630. case WSH_NOTIFY_BIND:
  631. DEBUGMSG(("WSH_NOTIFY_BIND AddrObj:%x, ConnObj:%x Context %x Options %d\n",
  632. TdiAddressObjectHandle, TdiConnectionObjectHandle,
  633. pSocket, pSocket->Options));
  634. if (pSocket->Options != 0)
  635. {
  636. NTSTATUS Status;
  637. IO_STATUS_BLOCK IoStatusBlock;
  638. Status = NtDeviceIoControlFile(
  639. TdiAddressObjectHandle,
  640. NULL, // HANDLE Event OPTIONAL
  641. NULL, // PIO_APC_ROUTINE ApcRoutine
  642. NULL, // PVOID ApcContext
  643. &IoStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
  644. IOCTL_IRDA_SET_OPTIONS, // ULONG IoControlCode
  645. (char *) &pSocket->Options, // PVOID InputBuffer
  646. sizeof(DWORD), // ULONG InputBufferLength
  647. NULL, // PVOID OutputBuffer
  648. 0); // ULONG OutputBufferLength
  649. DEBUGMSG(("IOCTL_IRDA_SET_OPTIONS rc %x\n", Status));
  650. }
  651. break;
  652. case WSH_NOTIFY_LISTEN:
  653. DEBUGMSG(("WSH_NOTIFY_LISTEN\n"));
  654. break;
  655. case WSH_NOTIFY_ACCEPT:
  656. DEBUGMSG(("WSH_NOTIFY_ACCEPT\n"));
  657. break;
  658. default:
  659. DEBUGMSG(("WSHNotify unknown event %d\n", NotifyEvent));
  660. }
  661. return NO_ERROR;
  662. }
  663. INT
  664. WSHEnumProtocols(
  665. IN LPINT lpiProtocols,
  666. IN LPWSTR lpTransportKeyName,
  667. IN OUT LPVOID lpProtocolBuffer,
  668. IN OUT LPDWORD lpdwBufferLength)
  669. {
  670. BOOL UseIrDA = FALSE;
  671. PPROTOCOL_INFO pIrDAProtocolInfo;
  672. DWORD BytesRequired;
  673. DWORD i;
  674. lpTransportKeyName; // Avoid compiler warnings.
  675. DEBUGMSG(("WSHEnumProtocols\n"));
  676. if (ARGUMENT_PRESENT(lpiProtocols))
  677. {
  678. for (i = 0; lpiProtocols[i] != 0; i++)
  679. {
  680. if (lpiProtocols[i] == IRDA_PROTO_SOCK_STREAM)
  681. {
  682. UseIrDA = TRUE;
  683. }
  684. }
  685. }
  686. else
  687. {
  688. UseIrDA = TRUE;
  689. }
  690. if (! UseIrDA)
  691. {
  692. *lpdwBufferLength = 0;
  693. return 0;
  694. }
  695. BytesRequired = sizeof(PROTOCOL_INFO) +
  696. ((wcslen(IRDA_NAME) + 1) * sizeof(WCHAR));
  697. if (BytesRequired > *lpdwBufferLength)
  698. {
  699. *lpdwBufferLength = BytesRequired;
  700. return -1;
  701. }
  702. pIrDAProtocolInfo = lpProtocolBuffer;
  703. pIrDAProtocolInfo->dwServiceFlags =
  704. XP_GUARANTEED_DELIVERY |
  705. XP_GUARANTEED_ORDER;
  706. pIrDAProtocolInfo->iAddressFamily = AF_IRDA;
  707. pIrDAProtocolInfo->iMaxSockAddr = MIN_SOCKADDR_LEN;
  708. pIrDAProtocolInfo->iMinSockAddr = MAX_SOCKADDR_LEN;
  709. pIrDAProtocolInfo->iSocketType = SOCK_STREAM;
  710. pIrDAProtocolInfo->iProtocol = IRDA_PROTO_SOCK_STREAM;
  711. pIrDAProtocolInfo->dwMessageSize = 0;
  712. pIrDAProtocolInfo->lpProtocol = (LPWSTR)
  713. ((PBYTE) lpProtocolBuffer + *lpdwBufferLength -
  714. ((wcslen(IRDA_NAME) + 1) * sizeof(WCHAR)));
  715. wcscpy(pIrDAProtocolInfo->lpProtocol, IRDA_NAME );
  716. *lpdwBufferLength = BytesRequired;
  717. return (1);
  718. }
  719. INT
  720. WINAPI
  721. WSHGetWSAProtocolInfo (
  722. IN LPWSTR ProviderName,
  723. OUT LPWSAPROTOCOL_INFOW * ProtocolInfo,
  724. OUT LPDWORD ProtocolInfoEntries
  725. )
  726. /*++
  727. Routine Description:
  728. Retrieves a pointer to the WSAPROTOCOL_INFOW structure(s) describing
  729. the protocol(s) supported by this helper.
  730. Arguments:
  731. ProviderName - Contains the name of the provider, such as "TcpIp".
  732. ProtocolInfo - Receives a pointer to the WSAPROTOCOL_INFOW array.
  733. ProtocolInfoEntries - Receives the number of entries in the array.
  734. Return Value:
  735. INT - 0 if successful, WinSock error code if not.
  736. --*/
  737. {
  738. DEBUGMSG(("WSHGetWSAProtocolInfo\n"));
  739. if( ProviderName == NULL ||
  740. ProtocolInfo == NULL ||
  741. ProtocolInfoEntries == NULL ) {
  742. return WSAEFAULT;
  743. }
  744. if( _wcsicmp( ProviderName, L"IrDA" ) == 0 ) {
  745. *ProtocolInfo = Winsock2Protocols;
  746. *ProtocolInfoEntries = 1;
  747. return NO_ERROR;
  748. }
  749. return WSAEINVAL;
  750. } // WSHGetWSAProtocolInfo
  751. INT
  752. WINAPI
  753. WSHGetProviderGuid (
  754. IN LPWSTR ProviderName,
  755. OUT LPGUID ProviderGuid
  756. )
  757. /*++
  758. Routine Description:
  759. Returns the GUID identifying the protocols supported by this helper.
  760. Arguments:
  761. ProviderName - Contains the name of the provider, such as "TcpIp".
  762. ProviderGuid - Points to a buffer that receives the provider's GUID.
  763. Return Value:
  764. INT - 0 if successful, WinSock error code if not.
  765. --*/
  766. {
  767. if( ProviderName == NULL ||
  768. ProviderGuid == NULL ) {
  769. return WSAEFAULT;
  770. }
  771. if( _wcsicmp( ProviderName, L"irda" ) == 0 ) {
  772. RtlCopyMemory(
  773. ProviderGuid,
  774. &IrdaProviderGuid,
  775. sizeof(GUID)
  776. );
  777. return NO_ERROR;
  778. }
  779. return WSAEINVAL;
  780. } // WSHGetProviderGuid
  781. VOID
  782. WINAPI
  783. IoctlCompletionRoutine (
  784. PVOID ApcContext,
  785. PIO_STATUS_BLOCK IoStatusBlock,
  786. DWORD Reserved
  787. )
  788. {
  789. LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine;
  790. LPWSAOVERLAPPED lpOverlapped;
  791. DWORD dwErrorCode = 0;
  792. DWORD dwNumberOfBytesTransfered;
  793. DWORD dwFlags = 0;
  794. DEBUGMSG(("IoctlCompletionRoutine\n"));
  795. if (NT_ERROR(IoStatusBlock->Status))
  796. {
  797. if (IoStatusBlock->Status != STATUS_CANCELLED)
  798. {
  799. dwErrorCode = IoStatusToWs(IoStatusBlock->Status);
  800. }
  801. else
  802. {
  803. dwErrorCode = WSA_OPERATION_ABORTED;
  804. }
  805. dwNumberOfBytesTransfered = 0;
  806. }
  807. else
  808. {
  809. dwErrorCode = 0;
  810. dwNumberOfBytesTransfered = (ULONG) IoStatusBlock->Information;
  811. }
  812. CompletionRoutine = (LPWSAOVERLAPPED_COMPLETION_ROUTINE)ApcContext;
  813. lpOverlapped = (LPWSAOVERLAPPED)CONTAINING_RECORD(IoStatusBlock,WSAOVERLAPPED,Internal);
  814. (CompletionRoutine)(
  815. dwErrorCode,
  816. dwNumberOfBytesTransfered,
  817. lpOverlapped,
  818. dwFlags);
  819. }
  820. INT
  821. WSHIoctl(
  822. IN PVOID HelperDllSocketContext,
  823. IN SOCKET SocketHandle,
  824. IN HANDLE TdiAddressObjectHandle,
  825. IN HANDLE TdiConnectionObjectHandle,
  826. IN DWORD IoControlCode,
  827. IN LPVOID InputBuffer,
  828. IN DWORD InputBufferLength,
  829. IN LPVOID OutputBuffer,
  830. IN DWORD OutputBufferLength,
  831. OUT LPDWORD NumberOfBytesReturned,
  832. IN LPWSAOVERLAPPED Overlapped,
  833. IN LPWSAOVERLAPPED_COMPLETION_ROUTINE CallerCompletionRoutine,
  834. OUT LPBOOL NeedsCompletion)
  835. {
  836. NTSTATUS Status;
  837. OBJECT_ATTRIBUTES ObjAttr;
  838. UNICODE_STRING DeviceName;
  839. HANDLE DeviceHandle;
  840. IO_STATUS_BLOCK IoStatusBlock;
  841. BOOL Result;
  842. PWSHIRDA_SOCKET_CONTEXT pSocket = HelperDllSocketContext;
  843. PIO_APC_ROUTINE apcRoutine;
  844. DEBUGMSG(("WSHIoctl: Sock %d, AddrObj %X, ConnObj %X\n", SocketHandle,
  845. TdiAddressObjectHandle, TdiConnectionObjectHandle));
  846. if (HelperDllSocketContext == NULL ||
  847. SocketHandle == INVALID_SOCKET ||
  848. NumberOfBytesReturned == NULL ||
  849. NeedsCompletion == NULL ||
  850. IoControlCode != SIO_LAZY_DISCOVERY ||
  851. (CallerCompletionRoutine != NULL && Overlapped == NULL) ||
  852. // I am using the Overlapped for the IoStatusBlock
  853. // for the completion routine so if a CallerCompletionRoutine
  854. // is specified, an Overlapped must be passed in as well
  855. OutputBufferLength < (sizeof(DWORD) + sizeof(IRDA_DEVICE_INFO)))
  856. {
  857. return WSAEINVAL;
  858. }
  859. *NeedsCompletion = FALSE;
  860. *NumberOfBytesReturned = OutputBufferLength;
  861. if (pSocket->LazyDscvDevHandle == NULL)
  862. {
  863. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  864. InitializeObjectAttributes(
  865. &ObjAttr,
  866. &DeviceName,
  867. OBJ_INHERIT | OBJ_CASE_INSENSITIVE,
  868. NULL,
  869. NULL);
  870. Status = NtCreateFile(
  871. &pSocket->LazyDscvDevHandle, // PHANDLE FileHandle
  872. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,//SYNCHRONIZE | GENERIC_EXECUTE, // ACCESS_MASK DesiredAccess
  873. &ObjAttr, // POBJECT_ATTRIBUTES ObjAttr
  874. &IoStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
  875. NULL, // PLARGE_INTEGER AllocationSize
  876. 0, // ULONG FileAttributes
  877. FILE_SHARE_READ |
  878. FILE_SHARE_WRITE, // ULONG ShareAccess
  879. FILE_OPEN_IF, // ULONG CreateDisposition
  880. 0, // ULONG CreateOptions
  881. NULL, // PVOID EaBuffer
  882. 0); // ULONG EaLength
  883. if (!NT_SUCCESS(Status))
  884. {
  885. return WSAEINVAL;
  886. }
  887. }
  888. Status = STATUS_SUCCESS;
  889. if (CallerCompletionRoutine == NULL)
  890. {
  891. // let Win32 do the dirty work
  892. DEBUGMSG(("No CallerCompletionRoutine, using DeviceIoControl()\n"));
  893. Result = DeviceIoControl(pSocket->LazyDscvDevHandle,
  894. IOCTL_IRDA_LAZY_DISCOVERY,
  895. NULL, 0, OutputBuffer, OutputBufferLength,
  896. NumberOfBytesReturned, Overlapped);
  897. if (Result == FALSE)
  898. {
  899. Status = GetLastError();
  900. if (Status == ERROR_IO_PENDING)
  901. {
  902. Status = STATUS_PENDING;
  903. }
  904. }
  905. }
  906. else
  907. {
  908. DEBUGMSG(("Using NtDeviceIoControlFile\n"));
  909. Status = NtDeviceIoControlFile(
  910. pSocket->LazyDscvDevHandle,
  911. NULL,
  912. IoctlCompletionRoutine,
  913. CallerCompletionRoutine,
  914. (PIO_STATUS_BLOCK)&Overlapped->Internal,
  915. IOCTL_IRDA_LAZY_DISCOVERY,
  916. NULL,
  917. 0,
  918. OutputBuffer,
  919. OutputBufferLength);
  920. if (Status == STATUS_SUCCESS)
  921. {
  922. *NumberOfBytesReturned = (DWORD) IoStatusBlock.Information;
  923. }
  924. }
  925. DEBUGMSG(("IoControlFile returned %x\n", Status));
  926. return IoStatusToWs(Status);
  927. }