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.

5528 lines
157 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. WshTcpip.c
  5. Abstract:
  6. This module contains necessary routines for the TCP/IP Windows Sockets
  7. Helper DLL. This DLL provides the transport-specific support necessary
  8. for the Windows Sockets DLL to use TCP/IP as a transport.
  9. Author:
  10. David Treadwell (davidtr) 19-Jul-1992
  11. Revision History:
  12. Keith Moore (keithmo) 02-May-1996
  13. Added WinSock 2 support.
  14. Dave Thaler (dthaler) 17-Jan-2000
  15. Added IGMPv3 support.
  16. --*/
  17. #define UNICODE
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <winsock2.h>
  22. #include <windows.h>
  23. #include <stdio.h>
  24. #include <ctype.h>
  25. #include <wchar.h>
  26. #include <tdi.h>
  27. #include <ws2tcpip.h>
  28. #include <wsahelp.h>
  29. #include <ipexport.h>
  30. #include <tdistat.h>
  31. #include <tdiinfo.h>
  32. #include <llinfo.h>
  33. #include <ipinfo.h>
  34. #include <ntddtcp.h>
  35. typedef unsigned long ulong;
  36. typedef unsigned short ushort;
  37. typedef unsigned int uint;
  38. typedef unsigned char uchar;
  39. #define TL_INSTANCE 0
  40. // private socket options to be accessed via WSAIoctl
  41. #include <mstcpip.h>
  42. #include <ntddtcp.h>
  43. #define NT // temporarily needed by tdiinfo.h...
  44. #include <ipexport.h>
  45. #include <tdiinfo.h>
  46. #include <tcpinfo.h>
  47. #include <ipinfo.h>
  48. #include <basetyps.h>
  49. #include <nspapi.h>
  50. #include <nspapip.h>
  51. #include <afd.h>
  52. #define TCP_NAME L"TCP/IP"
  53. #define UDP_NAME L"UDP/IP"
  54. #define IS_DGRAM_SOCK(type) (((type) == SOCK_DGRAM) || ((type) == SOCK_RAW))
  55. //
  56. // Define valid flags for WSHOpenSocket2().
  57. //
  58. #define VALID_TCP_FLAGS (WSA_FLAG_OVERLAPPED)
  59. #define VALID_UDP_FLAGS (WSA_FLAG_OVERLAPPED | \
  60. WSA_FLAG_MULTIPOINT_C_LEAF | \
  61. WSA_FLAG_MULTIPOINT_D_LEAF)
  62. //
  63. // Buffer management constants for GetTcpipInterfaceList().
  64. //
  65. #define MAX_FAST_ENTITY_BUFFER ( sizeof(TDIEntityID) * 10 )
  66. #define MAX_FAST_ADDRESS_BUFFER ( sizeof(IPAddrEntry) * 4 )
  67. //
  68. // Structure and variables to define the triples supported by TCP/IP. The
  69. // first entry of each array is considered the canonical triple for
  70. // that socket type; the other entries are synonyms for the first.
  71. //
  72. typedef struct _MAPPING_TRIPLE {
  73. INT AddressFamily;
  74. INT SocketType;
  75. INT Protocol;
  76. } MAPPING_TRIPLE, *PMAPPING_TRIPLE;
  77. MAPPING_TRIPLE TcpMappingTriples[] = { AF_INET, SOCK_STREAM, IPPROTO_TCP,
  78. AF_INET, SOCK_STREAM, 0,
  79. AF_INET, 0, IPPROTO_TCP,
  80. AF_UNSPEC, 0, IPPROTO_TCP,
  81. AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP };
  82. MAPPING_TRIPLE UdpMappingTriples[] = { AF_INET, SOCK_DGRAM, IPPROTO_UDP,
  83. AF_INET, SOCK_DGRAM, 0,
  84. AF_INET, 0, IPPROTO_UDP,
  85. AF_UNSPEC, 0, IPPROTO_UDP,
  86. AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP };
  87. MAPPING_TRIPLE RawMappingTriples[] = { AF_INET, SOCK_RAW, 0 };
  88. //
  89. // Winsock 2 WSAPROTOCOL_INFO structures for all supported protocols.
  90. //
  91. #define WINSOCK_SPI_VERSION 2
  92. #define UDP_MESSAGE_SIZE (65535-68)
  93. WSAPROTOCOL_INFOW Winsock2Protocols[] =
  94. {
  95. //
  96. // TCP
  97. //
  98. {
  99. XP1_GUARANTEED_DELIVERY // dwServiceFlags1
  100. | XP1_GUARANTEED_ORDER
  101. | XP1_GRACEFUL_CLOSE
  102. | XP1_EXPEDITED_DATA
  103. | XP1_IFS_HANDLES,
  104. 0, // dwServiceFlags2
  105. 0, // dwServiceFlags3
  106. 0, // dwServiceFlags4
  107. PFL_MATCHES_PROTOCOL_ZERO, // dwProviderFlags
  108. { // gProviderId
  109. 0, 0, 0,
  110. { 0, 0, 0, 0, 0, 0, 0, 0 }
  111. },
  112. 0, // dwCatalogEntryId
  113. { // ProtocolChain
  114. BASE_PROTOCOL, // ChainLen
  115. { 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
  116. },
  117. WINSOCK_SPI_VERSION, // iVersion
  118. AF_INET, // iAddressFamily
  119. sizeof(SOCKADDR_IN), // iMaxSockAddr
  120. sizeof(SOCKADDR_IN), // iMinSockAddr
  121. SOCK_STREAM, // iSocketType
  122. IPPROTO_TCP, // iProtocol
  123. 0, // iProtocolMaxOffset
  124. BIGENDIAN, // iNetworkByteOrder
  125. SECURITY_PROTOCOL_NONE, // iSecurityScheme
  126. 0, // dwMessageSize
  127. 0, // dwProviderReserved
  128. L"MSAFD Tcpip [TCP/IP]" // szProtocol
  129. },
  130. //
  131. // UDP
  132. //
  133. {
  134. XP1_CONNECTIONLESS // dwServiceFlags1
  135. | XP1_MESSAGE_ORIENTED
  136. | XP1_SUPPORT_BROADCAST
  137. | XP1_SUPPORT_MULTIPOINT
  138. | XP1_IFS_HANDLES,
  139. 0, // dwServiceFlags2
  140. 0, // dwServiceFlags3
  141. 0, // dwServiceFlags4
  142. PFL_MATCHES_PROTOCOL_ZERO, // dwProviderFlags
  143. { // gProviderId
  144. 0, 0, 0,
  145. { 0, 0, 0, 0, 0, 0, 0, 0 }
  146. },
  147. 0, // dwCatalogEntryId
  148. { // ProtocolChain
  149. BASE_PROTOCOL, // ChainLen
  150. { 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
  151. },
  152. WINSOCK_SPI_VERSION, // iVersion
  153. AF_INET, // iAddressFamily
  154. sizeof(SOCKADDR_IN), // iMaxSockAddr
  155. sizeof(SOCKADDR_IN), // iMinSockAddr
  156. SOCK_DGRAM, // iSocketType
  157. IPPROTO_UDP, // iProtocol
  158. 0, // iProtocolMaxOffset
  159. BIGENDIAN, // iNetworkByteOrder
  160. SECURITY_PROTOCOL_NONE, // iSecurityScheme
  161. UDP_MESSAGE_SIZE, // dwMessageSize
  162. 0, // dwProviderReserved
  163. L"MSAFD Tcpip [UDP/IP]" // szProtocol
  164. },
  165. //
  166. // RAW
  167. //
  168. {
  169. XP1_CONNECTIONLESS // dwServiceFlags1
  170. | XP1_MESSAGE_ORIENTED
  171. | XP1_SUPPORT_BROADCAST
  172. | XP1_SUPPORT_MULTIPOINT
  173. | XP1_IFS_HANDLES,
  174. 0, // dwServiceFlags2
  175. 0, // dwServiceFlags3
  176. 0, // dwServiceFlags4
  177. PFL_MATCHES_PROTOCOL_ZERO // dwProviderFlags
  178. | PFL_HIDDEN,
  179. { // gProviderId
  180. 0, 0, 0,
  181. { 0, 0, 0, 0, 0, 0, 0, 0 }
  182. },
  183. 0, // dwCatalogEntryId
  184. { // ProtocolChain
  185. BASE_PROTOCOL, // ChainLen
  186. { 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
  187. },
  188. WINSOCK_SPI_VERSION, // iVersion
  189. AF_INET, // iAddressFamily
  190. sizeof(SOCKADDR_IN), // iMaxSockAddr
  191. sizeof(SOCKADDR_IN), // iMinSockAddr
  192. SOCK_RAW, // iSocketType
  193. 0, // iProtocol
  194. 255, // iProtocolMaxOffset
  195. BIGENDIAN, // iNetworkByteOrder
  196. SECURITY_PROTOCOL_NONE, // iSecurityScheme
  197. UDP_MESSAGE_SIZE, // dwMessageSize
  198. 0, // dwProviderReserved
  199. L"MSAFD Tcpip [RAW/IP]" // szProtocol
  200. }
  201. };
  202. #define NUM_WINSOCK2_PROTOCOLS \
  203. ( sizeof(Winsock2Protocols) / sizeof(Winsock2Protocols[0]) )
  204. //
  205. // The GUID identifying this provider.
  206. //
  207. GUID TcpipProviderGuid = { /* e70f1aa0-ab8b-11cf-8ca3-00805f48a192 */
  208. 0xe70f1aa0,
  209. 0xab8b,
  210. 0x11cf,
  211. {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}
  212. };
  213. //
  214. // Forward declarations of internal routines.
  215. //
  216. VOID
  217. CompleteTdiActionApc (
  218. IN PVOID ApcContext,
  219. IN PIO_STATUS_BLOCK IoStatusBlock
  220. );
  221. INT
  222. GetTdiInformation (
  223. IN HANDLE TdiConnectionObjectHandle,
  224. IN ULONG Entity,
  225. IN ULONG Class,
  226. IN ULONG Type,
  227. IN ULONG Id,
  228. IN PVOID Value,
  229. IN ULONG InValueLength,
  230. IN ULONG OutValueLength
  231. );
  232. INT
  233. SetTdiInformation (
  234. IN HANDLE TdiConnectionObjectHandle,
  235. IN ULONG Entity,
  236. IN ULONG Class,
  237. IN ULONG Type,
  238. IN ULONG Id,
  239. IN PVOID Value,
  240. IN ULONG ValueLength,
  241. IN BOOLEAN WaitForCompletion
  242. );
  243. BOOLEAN
  244. IsTripleInList (
  245. IN PMAPPING_TRIPLE List,
  246. IN ULONG ListLength,
  247. IN INT AddressFamily,
  248. IN INT SocketType,
  249. IN INT Protocol
  250. );
  251. NTSTATUS
  252. GetTcpipInterfaceList(
  253. IN LPVOID OutputBuffer,
  254. IN DWORD OutputBufferLength,
  255. OUT LPDWORD NumberOfBytesReturned
  256. );
  257. INT
  258. NtStatusToSocketError (
  259. IN NTSTATUS Status
  260. );
  261. //
  262. // The socket context structure for this DLL. Each open TCP/IP socket
  263. // will have one of these context structures, which is used to maintain
  264. // information about the socket.
  265. //
  266. typedef struct _WSHTCPIP_SOCKET_CONTEXT {
  267. INT AddressFamily;
  268. INT SocketType;
  269. INT Protocol;
  270. INT ReceiveBufferSize;
  271. DWORD Flags;
  272. INT MulticastTtl;
  273. ULONG MulticastInterface;
  274. struct tcp_keepalive KeepAliveVals;
  275. IN_ADDR MultipointTarget;
  276. INT HdrInclude;
  277. BOOLEAN UcastIf;
  278. BOOLEAN MulticastLoopback;
  279. BOOLEAN KeepAlive;
  280. BOOLEAN DontRoute;
  281. BOOLEAN NoDelay;
  282. BOOLEAN BsdUrgent;
  283. BOOLEAN MultipointLeaf;
  284. BOOLEAN UdpNoChecksum;
  285. BOOLEAN ReceiveBroadcast;
  286. BOOLEAN HdrIncludeSet;
  287. BOOLEAN LimitBroadcasts;
  288. UCHAR IpPktInfo;
  289. UCHAR IpTtl;
  290. UCHAR IpTos;
  291. UCHAR IpDontFragment;
  292. UCHAR IpOptionsLength;
  293. UCHAR IpOptions[MAX_OPT_SIZE];
  294. } WSHTCPIP_SOCKET_CONTEXT, *PWSHTCPIP_SOCKET_CONTEXT;
  295. #define DEFAULT_RECEIVE_BUFFER_SIZE 8192
  296. #define DEFAULT_MULTICAST_TTL 1
  297. #define DEFAULT_MULTICAST_INTERFACE INADDR_ANY
  298. #define DEFAULT_MULTICAST_LOOPBACK TRUE
  299. #define DEFAULT_RECEIVE_BROADCAST TRUE
  300. #define DEFAULT_UCAST_IF FALSE
  301. //
  302. //
  303. #define DEFAULT_IP_TTL 32
  304. #define DEFAULT_IP_TOS 0
  305. BOOLEAN
  306. DllInitialize (
  307. IN PVOID DllHandle,
  308. IN ULONG Reason,
  309. IN PVOID Context OPTIONAL
  310. )
  311. {
  312. switch ( Reason ) {
  313. case DLL_PROCESS_ATTACH:
  314. //
  315. // We don't need to receive thread attach and detach
  316. // notifications, so disable them to help application
  317. // performance.
  318. //
  319. DisableThreadLibraryCalls( DllHandle );
  320. return TRUE;
  321. case DLL_THREAD_ATTACH:
  322. break;
  323. case DLL_PROCESS_DETACH:
  324. break;
  325. case DLL_THREAD_DETACH:
  326. break;
  327. }
  328. return TRUE;
  329. } // SockInitialize
  330. INT
  331. WSHGetSockaddrType (
  332. IN PSOCKADDR Sockaddr,
  333. IN DWORD SockaddrLength,
  334. OUT PSOCKADDR_INFO SockaddrInfo
  335. )
  336. /*++
  337. Routine Description:
  338. This routine parses a sockaddr to determine the type of the
  339. machine address and endpoint address portions of the sockaddr.
  340. This is called by the winsock DLL whenever it needs to interpret
  341. a sockaddr.
  342. Arguments:
  343. Sockaddr - a pointer to the sockaddr structure to evaluate.
  344. SockaddrLength - the number of bytes in the sockaddr structure.
  345. SockaddrInfo - a pointer to a structure that will receive information
  346. about the specified sockaddr.
  347. Return Value:
  348. INT - a winsock error code indicating the status of the operation, or
  349. NO_ERROR if the operation succeeded.
  350. --*/
  351. {
  352. UNALIGNED SOCKADDR_IN *sockaddr = (PSOCKADDR_IN)Sockaddr;
  353. ULONG i;
  354. //
  355. // Make sure that the length is correct.
  356. //
  357. if ( SockaddrLength < sizeof(SOCKADDR_IN) ) {
  358. return WSAEFAULT;
  359. }
  360. //
  361. // Make sure that the address family is correct.
  362. //
  363. if ( sockaddr->sin_family != AF_INET ) {
  364. return WSAEAFNOSUPPORT;
  365. }
  366. //
  367. // The address passed the tests, looks like a good address.
  368. // Determine the type of the address portion of the sockaddr.
  369. //
  370. if ( sockaddr->sin_addr.s_addr == INADDR_ANY ) {
  371. ASSERT (htonl(INADDR_ANY)==INADDR_ANY);
  372. SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
  373. } else if ( sockaddr->sin_addr.s_addr == INADDR_BROADCAST ) {
  374. ASSERT (htonl(INADDR_BROADCAST)==INADDR_BROADCAST);
  375. SockaddrInfo->AddressInfo = SockaddrAddressInfoBroadcast;
  376. } else if ( sockaddr->sin_addr.s_addr == htonl(INADDR_LOOPBACK) ) {
  377. SockaddrInfo->AddressInfo = SockaddrAddressInfoLoopback;
  378. } else {
  379. SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
  380. }
  381. //
  382. // Determine the type of the port (endpoint) in the sockaddr.
  383. //
  384. if ( sockaddr->sin_port == 0 ) {
  385. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
  386. } else if ( ntohs( sockaddr->sin_port ) < 1025 ) {
  387. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoReserved;
  388. } else {
  389. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoNormal;
  390. }
  391. //
  392. // Zero out the sin_zero part of the address. We silently allow
  393. // nonzero values in this field.
  394. //
  395. for ( i = 0; i < sizeof(sockaddr->sin_zero); i++ ) {
  396. sockaddr->sin_zero[i] = 0;
  397. }
  398. return NO_ERROR;
  399. } // WSHGetSockaddrType
  400. INT
  401. WSHGetSocketInformation (
  402. IN PVOID HelperDllSocketContext,
  403. IN SOCKET SocketHandle,
  404. IN HANDLE TdiAddressObjectHandle,
  405. IN HANDLE TdiConnectionObjectHandle,
  406. IN INT Level,
  407. IN INT OptionName,
  408. OUT PCHAR OptionValue,
  409. OUT PINT OptionLength
  410. )
  411. /*++
  412. Routine Description:
  413. This routine retrieves information about a socket for those socket
  414. options supported in this helper DLL. The options supported here
  415. are SO_KEEPALIVE, SO_DONTROUTE, and TCP_EXPEDITED_1122. This routine is
  416. called by the winsock DLL when a level/option name combination is
  417. passed to getsockopt() that the winsock DLL does not understand.
  418. Arguments:
  419. HelperDllSocketContext - the context pointer returned from
  420. WSHOpenSocket().
  421. SocketHandle - the handle of the socket for which we're getting
  422. information.
  423. TdiAddressObjectHandle - the TDI address object of the socket, if
  424. any. If the socket is not yet bound to an address, then
  425. it does not have a TDI address object and this parameter
  426. will be NULL.
  427. TdiConnectionObjectHandle - the TDI connection object of the socket,
  428. if any. If the socket is not yet connected, then it does not
  429. have a TDI connection object and this parameter will be NULL.
  430. Level - the level parameter passed to getsockopt().
  431. OptionName - the optname parameter passed to getsockopt().
  432. OptionValue - the optval parameter passed to getsockopt().
  433. OptionLength - the optlen parameter passed to getsockopt().
  434. Return Value:
  435. INT - a winsock error code indicating the status of the operation, or
  436. NO_ERROR if the operation succeeded.
  437. --*/
  438. {
  439. PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
  440. UNREFERENCED_PARAMETER( SocketHandle );
  441. UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
  442. UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
  443. //
  444. // Check if this is an internal request for context information.
  445. //
  446. if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
  447. //
  448. // The Windows Sockets DLL is requesting context information
  449. // from us. If an output buffer was not supplied, the Windows
  450. // Sockets DLL is just requesting the size of our context
  451. // information.
  452. //
  453. if ( OptionValue != NULL ) {
  454. //
  455. // Make sure that the buffer is sufficient to hold all the
  456. // context information.
  457. //
  458. if ( *OptionLength < sizeof(*context) ) {
  459. return WSAEFAULT;
  460. }
  461. //
  462. // Copy in the context information.
  463. //
  464. RtlCopyMemory( OptionValue, context, sizeof(*context) );
  465. }
  466. *OptionLength = sizeof(*context);
  467. return NO_ERROR;
  468. }
  469. //
  470. // The only other levels we support here are SOL_SOCKET,
  471. // IPPROTO_TCP, IPPROTO_UDP, and IPPROTO_IP.
  472. //
  473. if ( Level != SOL_SOCKET &&
  474. Level != IPPROTO_TCP &&
  475. Level != IPPROTO_UDP &&
  476. Level != IPPROTO_IP ) {
  477. return WSAEINVAL;
  478. }
  479. //
  480. // Make sure that the output buffer is sufficiently large.
  481. //
  482. if ( *OptionLength < sizeof(char)) {
  483. return WSAEFAULT;
  484. }
  485. __try {
  486. RtlZeroMemory( OptionValue, *OptionLength );
  487. }
  488. __except (EXCEPTION_EXECUTE_HANDLER) {
  489. return WSAEFAULT;
  490. }
  491. //
  492. // Handle TCP-level options.
  493. //
  494. if ( Level == IPPROTO_TCP ) {
  495. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  496. return WSAENOPROTOOPT;
  497. }
  498. switch ( OptionName ) {
  499. case TCP_NODELAY:
  500. *OptionValue = context->NoDelay;
  501. *OptionLength = *OptionLength<sizeof (int) ? sizeof (char) : sizeof(int);
  502. break;
  503. case TCP_EXPEDITED_1122:
  504. *OptionValue = !context->BsdUrgent;
  505. *OptionLength = *OptionLength<sizeof (int) ? sizeof (char) : sizeof(int);
  506. break;
  507. default:
  508. return WSAEINVAL;
  509. }
  510. return NO_ERROR;
  511. }
  512. //
  513. // Handle UDP-level options.
  514. //
  515. if ( Level == IPPROTO_UDP ) {
  516. switch ( OptionName ) {
  517. case UDP_NOCHECKSUM :
  518. //
  519. // This option is only valid for datagram sockets.
  520. //
  521. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  522. return WSAENOPROTOOPT;
  523. }
  524. *OptionValue = context->UdpNoChecksum;
  525. *OptionLength = *OptionLength<sizeof (int) ? sizeof (char) : sizeof(int);
  526. break;
  527. break;
  528. default :
  529. return WSAEINVAL;
  530. }
  531. return NO_ERROR;
  532. }
  533. //
  534. // Handle IP-level options.
  535. //
  536. if ( Level == IPPROTO_IP ) {
  537. //
  538. // Act based on the specific option.
  539. //
  540. switch ( OptionName ) {
  541. case IP_TTL:
  542. *OptionValue = (char) context->IpTtl;
  543. *OptionLength = *OptionLength<sizeof (int) ? sizeof (char) : sizeof(int);
  544. return NO_ERROR;
  545. case IP_TOS:
  546. *OptionValue = (char) context->IpTos;
  547. *OptionLength = *OptionLength<sizeof (int) ? sizeof (char) : sizeof(int);
  548. return NO_ERROR;
  549. case IP_DONTFRAGMENT:
  550. *OptionValue = (char) context->IpDontFragment;
  551. *OptionLength = *OptionLength<sizeof (int) ? sizeof (char) : sizeof(int);
  552. return NO_ERROR;
  553. case IP_OPTIONS:
  554. if ( *OptionLength < context->IpOptionsLength ) {
  555. return WSAEFAULT;
  556. }
  557. if (context->IpOptionsLength>0) {
  558. RtlMoveMemory(
  559. OptionValue,
  560. context->IpOptions,
  561. context->IpOptionsLength
  562. );
  563. }
  564. *OptionLength = context->IpOptionsLength;
  565. return NO_ERROR;
  566. default:
  567. //
  568. // No match, fall through.
  569. //
  570. break;
  571. }
  572. //
  573. // The following IP options are only valid on datagram sockets.
  574. //
  575. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  576. return WSAENOPROTOOPT;
  577. }
  578. //
  579. // Act based on the specific option.
  580. //
  581. switch ( OptionName ) {
  582. case IP_MULTICAST_TTL:
  583. *OptionValue = (char)context->MulticastTtl;
  584. *OptionLength = *OptionLength<sizeof (int) ? sizeof (char) : sizeof(int);
  585. return NO_ERROR;
  586. case IP_MULTICAST_IF:
  587. *(int *)OptionValue = context->MulticastInterface;
  588. *OptionLength = sizeof(int);
  589. return NO_ERROR;
  590. case IP_MULTICAST_LOOP:
  591. *OptionValue = context->MulticastLoopback;
  592. *OptionLength = *OptionLength<sizeof (int) ? sizeof (char) : sizeof(int);
  593. return NO_ERROR;
  594. case IP_HDRINCL:
  595. // User hdr include option
  596. //
  597. //
  598. if (*OptionLength<sizeof (int))
  599. return WSAEFAULT;
  600. if (context->HdrIncludeSet == TRUE) {
  601. *((PINT)OptionValue) = context->HdrInclude;
  602. }
  603. else {
  604. *((PINT)OptionValue) = 0;
  605. }
  606. *OptionLength = sizeof(int);
  607. return NO_ERROR;
  608. case IP_PKTINFO:
  609. *OptionValue = (char) context->IpPktInfo;
  610. *OptionLength = *OptionLength < sizeof (int) ? sizeof (char) : sizeof(int);
  611. return NO_ERROR;
  612. case IP_RECEIVE_BROADCAST:
  613. if (*OptionLength < sizeof(int))
  614. return WSAEFAULT;
  615. *((PINT)OptionValue) = context->ReceiveBroadcast;
  616. *OptionLength = sizeof(int);
  617. return NO_ERROR;
  618. default:
  619. return WSAENOPROTOOPT;
  620. }
  621. }
  622. //
  623. // Handle socket-level options.
  624. //
  625. switch ( OptionName ) {
  626. case SO_KEEPALIVE:
  627. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  628. return WSAENOPROTOOPT;
  629. }
  630. *OptionValue = context->KeepAlive;
  631. *OptionLength = *OptionLength<sizeof (int) ? sizeof (char) : sizeof(int);
  632. break;
  633. case SO_DONTROUTE:
  634. *OptionValue = context->DontRoute;
  635. *OptionLength = *OptionLength<sizeof (int) ? sizeof (char) : sizeof(int);
  636. break;
  637. default:
  638. return WSAENOPROTOOPT;
  639. }
  640. return NO_ERROR;
  641. } // WSHGetSocketInformation
  642. INT
  643. WSHGetWildcardSockaddr (
  644. IN PVOID HelperDllSocketContext,
  645. OUT PSOCKADDR Sockaddr,
  646. OUT PINT SockaddrLength
  647. )
  648. /*++
  649. Routine Description:
  650. This routine returns a wildcard socket address. A wildcard address
  651. is one which will bind the socket to an endpoint of the transport's
  652. choosing. For TCP/IP, a wildcard address has IP address ==
  653. 0.0.0.0 and port = 0.
  654. Arguments:
  655. HelperDllSocketContext - the context pointer returned from
  656. WSHOpenSocket() for the socket for which we need a wildcard
  657. address.
  658. Sockaddr - points to a buffer which will receive the wildcard socket
  659. address.
  660. SockaddrLength - receives the length of the wioldcard sockaddr.
  661. Return Value:
  662. INT - a winsock error code indicating the status of the operation, or
  663. NO_ERROR if the operation succeeded.
  664. --*/
  665. {
  666. if ( *SockaddrLength < sizeof(SOCKADDR_IN) ) {
  667. return WSAEFAULT;
  668. }
  669. *SockaddrLength = sizeof(SOCKADDR_IN);
  670. //
  671. // Just zero out the address and set the family to AF_INET--this is
  672. // a wildcard address for TCP/IP.
  673. //
  674. RtlZeroMemory( Sockaddr, sizeof(SOCKADDR_IN) );
  675. Sockaddr->sa_family = AF_INET;
  676. return NO_ERROR;
  677. } // WSAGetWildcardSockaddr
  678. DWORD
  679. WSHGetWinsockMapping (
  680. OUT PWINSOCK_MAPPING Mapping,
  681. IN DWORD MappingLength
  682. )
  683. /*++
  684. Routine Description:
  685. Returns the list of address family/socket type/protocol triples
  686. supported by this helper DLL.
  687. Arguments:
  688. Mapping - receives a pointer to a WINSOCK_MAPPING structure that
  689. describes the triples supported here.
  690. MappingLength - the length, in bytes, of the passed-in Mapping buffer.
  691. Return Value:
  692. DWORD - the length, in bytes, of a WINSOCK_MAPPING structure for this
  693. helper DLL. If the passed-in buffer is too small, the return
  694. value will indicate the size of a buffer needed to contain
  695. the WINSOCK_MAPPING structure.
  696. --*/
  697. {
  698. DWORD mappingLength;
  699. mappingLength = sizeof(WINSOCK_MAPPING) - sizeof(MAPPING_TRIPLE) +
  700. sizeof(TcpMappingTriples) + sizeof(UdpMappingTriples)
  701. + sizeof(RawMappingTriples);
  702. //
  703. // If the passed-in buffer is too small, return the length needed
  704. // now without writing to the buffer. The caller should allocate
  705. // enough memory and call this routine again.
  706. //
  707. if ( mappingLength > MappingLength ) {
  708. return mappingLength;
  709. }
  710. //
  711. // Fill in the output mapping buffer with the list of triples
  712. // supported in this helper DLL.
  713. //
  714. Mapping->Rows = sizeof(TcpMappingTriples) / sizeof(TcpMappingTriples[0])
  715. + sizeof(UdpMappingTriples) / sizeof(UdpMappingTriples[0])
  716. + sizeof(RawMappingTriples) / sizeof(RawMappingTriples[0]);
  717. Mapping->Columns = sizeof(MAPPING_TRIPLE) / sizeof(DWORD);
  718. RtlMoveMemory(
  719. Mapping->Mapping,
  720. TcpMappingTriples,
  721. sizeof(TcpMappingTriples)
  722. );
  723. RtlMoveMemory(
  724. (PCHAR)Mapping->Mapping + sizeof(TcpMappingTriples),
  725. UdpMappingTriples,
  726. sizeof(UdpMappingTriples)
  727. );
  728. RtlMoveMemory(
  729. (PCHAR)Mapping->Mapping + sizeof(TcpMappingTriples)
  730. + sizeof(UdpMappingTriples),
  731. RawMappingTriples,
  732. sizeof(RawMappingTriples)
  733. );
  734. //
  735. // Return the number of bytes we wrote.
  736. //
  737. return mappingLength;
  738. } // WSHGetWinsockMapping
  739. INT
  740. WSHOpenSocket (
  741. IN OUT PINT AddressFamily,
  742. IN OUT PINT SocketType,
  743. IN OUT PINT Protocol,
  744. OUT PUNICODE_STRING TransportDeviceName,
  745. OUT PVOID *HelperDllSocketContext,
  746. OUT PDWORD NotificationEvents
  747. )
  748. {
  749. return WSHOpenSocket2(
  750. AddressFamily,
  751. SocketType,
  752. Protocol,
  753. 0, // Group
  754. 0, // Flags
  755. TransportDeviceName,
  756. HelperDllSocketContext,
  757. NotificationEvents
  758. );
  759. } // WSHOpenSocket
  760. INT
  761. WSHOpenSocket2 (
  762. IN OUT PINT AddressFamily,
  763. IN OUT PINT SocketType,
  764. IN OUT PINT Protocol,
  765. IN GROUP Group,
  766. IN DWORD Flags,
  767. OUT PUNICODE_STRING TransportDeviceName,
  768. OUT PVOID *HelperDllSocketContext,
  769. OUT PDWORD NotificationEvents
  770. )
  771. /*++
  772. Routine Description:
  773. Does the necessary work for this helper DLL to open a socket and is
  774. called by the winsock DLL in the socket() routine. This routine
  775. verifies that the specified triple is valid, determines the NT
  776. device name of the TDI provider that will support that triple,
  777. allocates space to hold the socket's context block, and
  778. canonicalizes the triple.
  779. Arguments:
  780. AddressFamily - on input, the address family specified in the
  781. socket() call. On output, the canonicalized value for the
  782. address family.
  783. SocketType - on input, the socket type specified in the socket()
  784. call. On output, the canonicalized value for the socket type.
  785. Protocol - on input, the protocol specified in the socket() call.
  786. On output, the canonicalized value for the protocol.
  787. Group - Identifies the group for the new socket.
  788. Flags - Zero or more WSA_FLAG_* flags as passed into WSASocket().
  789. TransportDeviceName - receives the name of the TDI provider that
  790. will support the specified triple.
  791. HelperDllSocketContext - receives a context pointer that the winsock
  792. DLL will return to this helper DLL on future calls involving
  793. this socket.
  794. NotificationEvents - receives a bitmask of those state transitions
  795. this helper DLL should be notified on.
  796. Return Value:
  797. INT - a winsock error code indicating the status of the operation, or
  798. NO_ERROR if the operation succeeded.
  799. --*/
  800. {
  801. PWSHTCPIP_SOCKET_CONTEXT context;
  802. BOOLEAN FreeDeviceNameBuffer = FALSE;
  803. //
  804. // Determine whether this is to be a TCP, UDP, or RAW socket.
  805. //
  806. if ( IsTripleInList(
  807. TcpMappingTriples,
  808. sizeof(TcpMappingTriples) / sizeof(TcpMappingTriples[0]),
  809. *AddressFamily,
  810. *SocketType,
  811. *Protocol ) ) {
  812. //
  813. // It's a TCP socket. Check the flags.
  814. //
  815. if( ( Flags & ~VALID_TCP_FLAGS ) != 0 ) {
  816. return WSAEINVAL;
  817. }
  818. //
  819. // Return the canonical form of a TCP socket triple.
  820. //
  821. *AddressFamily = TcpMappingTriples[0].AddressFamily;
  822. *SocketType = TcpMappingTriples[0].SocketType;
  823. *Protocol = TcpMappingTriples[0].Protocol;
  824. //
  825. // Indicate the name of the TDI device that will service
  826. // SOCK_STREAM sockets in the internet address family.
  827. //
  828. RtlInitUnicodeString( TransportDeviceName, DD_TCP_DEVICE_NAME );
  829. } else if ( IsTripleInList(
  830. UdpMappingTriples,
  831. sizeof(UdpMappingTriples) / sizeof(UdpMappingTriples[0]),
  832. *AddressFamily,
  833. *SocketType,
  834. *Protocol ) ) {
  835. //
  836. // It's a UDP socket. Check the flags & group ID.
  837. //
  838. if( ( Flags & ~VALID_UDP_FLAGS ) != 0 ||
  839. Group == SG_CONSTRAINED_GROUP ) {
  840. return WSAEINVAL;
  841. }
  842. //
  843. // Return the canonical form of a UDP socket triple.
  844. //
  845. *AddressFamily = UdpMappingTriples[0].AddressFamily;
  846. *SocketType = UdpMappingTriples[0].SocketType;
  847. *Protocol = UdpMappingTriples[0].Protocol;
  848. //
  849. // Indicate the name of the TDI device that will service
  850. // SOCK_DGRAM sockets in the internet address family.
  851. //
  852. RtlInitUnicodeString( TransportDeviceName, DD_UDP_DEVICE_NAME );
  853. } else if ( IsTripleInList(
  854. RawMappingTriples,
  855. sizeof(RawMappingTriples) / sizeof(RawMappingTriples[0]),
  856. *AddressFamily,
  857. *SocketType,
  858. *Protocol ) )
  859. {
  860. UNICODE_STRING unicodeString;
  861. NTSTATUS status;
  862. //
  863. // There is no canonicalization to be done for SOCK_RAW.
  864. //
  865. if (*Protocol < 0 || *Protocol > 255) {
  866. return(WSAEINVAL);
  867. }
  868. //
  869. // Indicate the name of the TDI device that will service
  870. // SOCK_RAW sockets in the internet address family.
  871. //
  872. RtlInitUnicodeString(&unicodeString, DD_RAW_IP_DEVICE_NAME);
  873. RtlInitUnicodeString(TransportDeviceName, NULL);
  874. TransportDeviceName->MaximumLength = unicodeString.Length +
  875. (4 * sizeof(WCHAR) +
  876. sizeof(UNICODE_NULL));
  877. TransportDeviceName->Buffer = RtlAllocateHeap(
  878. RtlProcessHeap( ),
  879. 0,
  880. TransportDeviceName->MaximumLength
  881. );
  882. if (TransportDeviceName->Buffer == NULL) {
  883. return(WSAENOBUFS);
  884. }
  885. FreeDeviceNameBuffer = TRUE;
  886. //
  887. // Append the device name.
  888. //
  889. status = RtlAppendUnicodeStringToString(
  890. TransportDeviceName,
  891. &unicodeString
  892. );
  893. ASSERT(NT_SUCCESS(status));
  894. //
  895. // Append a separator.
  896. //
  897. TransportDeviceName->Buffer[TransportDeviceName->Length/sizeof(WCHAR)] =
  898. OBJ_NAME_PATH_SEPARATOR;
  899. TransportDeviceName->Length += sizeof(WCHAR);
  900. TransportDeviceName->Buffer[TransportDeviceName->Length/sizeof(WCHAR)] =
  901. UNICODE_NULL;
  902. //
  903. // Append the protocol number.
  904. //
  905. unicodeString.Buffer = TransportDeviceName->Buffer +
  906. (TransportDeviceName->Length / sizeof(WCHAR));
  907. unicodeString.Length = 0;
  908. unicodeString.MaximumLength = TransportDeviceName->MaximumLength -
  909. TransportDeviceName->Length;
  910. status = RtlIntegerToUnicodeString(
  911. (ULONG) *Protocol,
  912. 10,
  913. &unicodeString
  914. );
  915. TransportDeviceName->Length += unicodeString.Length;
  916. ASSERT(NT_SUCCESS(status));
  917. } else {
  918. //
  919. // This should never happen if the registry information about this
  920. // helper DLL is correct. If somehow this did happen, just return
  921. // an error.
  922. //
  923. return WSAEINVAL;
  924. }
  925. //
  926. // Allocate context for this socket. The Windows Sockets DLL will
  927. // return this value to us when it asks us to get/set socket options.
  928. //
  929. context = RtlAllocateHeap( RtlProcessHeap( ), 0, sizeof(*context) );
  930. if ( context == NULL ) {
  931. if ( FreeDeviceNameBuffer ) {
  932. RtlFreeHeap( RtlProcessHeap( ), 0, TransportDeviceName->Buffer );
  933. }
  934. TransportDeviceName->Buffer = NULL;
  935. return WSAENOBUFS;
  936. }
  937. //
  938. // Initialize the context for the socket.
  939. //
  940. context->AddressFamily = *AddressFamily;
  941. context->SocketType = *SocketType;
  942. context->Protocol = *Protocol;
  943. context->ReceiveBufferSize = DEFAULT_RECEIVE_BUFFER_SIZE;
  944. context->Flags = Flags;
  945. context->MulticastTtl = DEFAULT_MULTICAST_TTL;
  946. context->MulticastInterface = DEFAULT_MULTICAST_INTERFACE;
  947. context->MulticastLoopback = DEFAULT_MULTICAST_LOOPBACK;
  948. context->KeepAlive = FALSE;
  949. context->DontRoute = FALSE;
  950. context->NoDelay = FALSE;
  951. context->BsdUrgent = TRUE;
  952. context->IpDontFragment = FALSE;
  953. context->IpTtl = DEFAULT_IP_TTL;
  954. context->IpTos = DEFAULT_IP_TOS;
  955. context->IpOptionsLength = 0;
  956. context->MultipointLeaf = FALSE;
  957. context->UdpNoChecksum = FALSE;
  958. context->ReceiveBroadcast = DEFAULT_RECEIVE_BROADCAST;
  959. context->HdrIncludeSet = FALSE;
  960. context->KeepAliveVals.onoff = FALSE;
  961. context->UcastIf = DEFAULT_UCAST_IF;
  962. context->LimitBroadcasts = FALSE;
  963. context->IpPktInfo = FALSE;
  964. //
  965. // Tell the Windows Sockets DLL which state transitions we're
  966. // interested in being notified of. The only times we need to be
  967. // called is after a connect has completed so that we can turn on
  968. // the sending of keepalives if SO_KEEPALIVE was set before the
  969. // socket was connected, when the socket is closed so that we can
  970. // free context information, and when a connect fails so that we
  971. // can, if appropriate, dial in to the network that will support the
  972. // connect attempt.
  973. //
  974. if (*SocketType == SOCK_STREAM) {
  975. *NotificationEvents =
  976. WSH_NOTIFY_CONNECT | WSH_NOTIFY_CLOSE | WSH_NOTIFY_CONNECT_ERROR;
  977. }
  978. else { // *SocketType == SOCK_DGRAM || *SocketType == SOCK_RAW
  979. *NotificationEvents =
  980. WSH_NOTIFY_CONNECT | WSH_NOTIFY_CLOSE | WSH_NOTIFY_CONNECT_ERROR |
  981. WSH_NOTIFY_BIND;
  982. }
  983. //
  984. // Everything worked, return success.
  985. //
  986. *HelperDllSocketContext = context;
  987. return NO_ERROR;
  988. } // WSHOpenSocket
  989. INT
  990. WSHNotify (
  991. IN PVOID HelperDllSocketContext,
  992. IN SOCKET SocketHandle,
  993. IN HANDLE TdiAddressObjectHandle,
  994. IN HANDLE TdiConnectionObjectHandle,
  995. IN DWORD NotifyEvent
  996. )
  997. /*++
  998. Routine Description:
  999. This routine is called by the winsock DLL after a state transition
  1000. of the socket. Only state transitions returned in the
  1001. NotificationEvents parameter of WSHOpenSocket() are notified here.
  1002. This routine allows a winsock helper DLL to track the state of
  1003. socket and perform necessary actions corresponding to state
  1004. transitions.
  1005. Arguments:
  1006. HelperDllSocketContext - the context pointer given to the winsock
  1007. DLL by WSHOpenSocket().
  1008. SocketHandle - the handle for the socket.
  1009. TdiAddressObjectHandle - the TDI address object of the socket, if
  1010. any. If the socket is not yet bound to an address, then
  1011. it does not have a TDI address object and this parameter
  1012. will be NULL.
  1013. TdiConnectionObjectHandle - the TDI connection object of the socket,
  1014. if any. If the socket is not yet connected, then it does not
  1015. have a TDI connection object and this parameter will be NULL.
  1016. NotifyEvent - indicates the state transition for which we're being
  1017. called.
  1018. Return Value:
  1019. INT - a winsock error code indicating the status of the operation, or
  1020. NO_ERROR if the operation succeeded.
  1021. --*/
  1022. {
  1023. PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
  1024. INT err;
  1025. //
  1026. // We should only be called after a connect() completes or when the
  1027. // socket is being closed.
  1028. //
  1029. if ( NotifyEvent == WSH_NOTIFY_CONNECT ) {
  1030. ULONG true = TRUE;
  1031. ULONG false = FALSE;
  1032. //
  1033. // If a connection-object option was set on the socket before
  1034. // it was connected, set the option for real now.
  1035. //
  1036. if ( context->KeepAlive ) {
  1037. err = SetTdiInformation(
  1038. TdiConnectionObjectHandle,
  1039. CO_TL_ENTITY,
  1040. INFO_CLASS_PROTOCOL,
  1041. INFO_TYPE_CONNECTION,
  1042. TCP_SOCKET_KEEPALIVE,
  1043. &true,
  1044. sizeof(true),
  1045. TRUE
  1046. );
  1047. if ( err != NO_ERROR ) {
  1048. return err;
  1049. }
  1050. }
  1051. if ( context->KeepAliveVals.onoff ) {
  1052. err = SetTdiInformation(
  1053. TdiConnectionObjectHandle,
  1054. CO_TL_ENTITY,
  1055. INFO_CLASS_PROTOCOL,
  1056. INFO_TYPE_CONNECTION,
  1057. TCP_SOCKET_KEEPALIVE_VALS,
  1058. &context->KeepAliveVals,
  1059. sizeof(struct tcp_keepalive),
  1060. TRUE
  1061. );
  1062. if ( err != NO_ERROR ) {
  1063. return err;
  1064. }
  1065. }
  1066. if ( context->NoDelay ) {
  1067. err = SetTdiInformation(
  1068. TdiConnectionObjectHandle,
  1069. CO_TL_ENTITY,
  1070. INFO_CLASS_PROTOCOL,
  1071. INFO_TYPE_CONNECTION,
  1072. TCP_SOCKET_NODELAY,
  1073. &true,
  1074. sizeof(true),
  1075. TRUE
  1076. );
  1077. if ( err != NO_ERROR ) {
  1078. return err;
  1079. }
  1080. }
  1081. if ( !context->BsdUrgent ) {
  1082. err = SetTdiInformation(
  1083. TdiConnectionObjectHandle,
  1084. CO_TL_ENTITY,
  1085. INFO_CLASS_PROTOCOL,
  1086. INFO_TYPE_CONNECTION,
  1087. TCP_SOCKET_BSDURGENT,
  1088. &false,
  1089. sizeof(false),
  1090. TRUE
  1091. );
  1092. if ( err != NO_ERROR ) {
  1093. return err;
  1094. }
  1095. }
  1096. if ( context->IpTos != DEFAULT_IP_TOS ) {
  1097. int value = (int) context->IpTos;
  1098. err = SetTdiInformation(
  1099. TdiConnectionObjectHandle,
  1100. CO_TL_ENTITY,
  1101. INFO_CLASS_PROTOCOL,
  1102. INFO_TYPE_CONNECTION,
  1103. TCP_SOCKET_TOS,
  1104. &value,
  1105. sizeof(int),
  1106. TRUE
  1107. );
  1108. if ( err != NO_ERROR ) {
  1109. return err;
  1110. }
  1111. }
  1112. } else if ( NotifyEvent == WSH_NOTIFY_CLOSE ) {
  1113. //
  1114. // If this is a multipoint leaf, then remove the multipoint target
  1115. // from the session.
  1116. //
  1117. if( context->MultipointLeaf &&
  1118. TdiAddressObjectHandle != NULL ) {
  1119. struct ip_mreq req;
  1120. req.imr_multiaddr = context->MultipointTarget;
  1121. req.imr_interface.s_addr = 0;
  1122. SetTdiInformation(
  1123. TdiAddressObjectHandle,
  1124. CL_TL_ENTITY,
  1125. INFO_CLASS_PROTOCOL,
  1126. INFO_TYPE_ADDRESS_OBJECT,
  1127. AO_OPTION_DEL_MCAST,
  1128. &req,
  1129. sizeof(req),
  1130. TRUE
  1131. );
  1132. }
  1133. //
  1134. // Free the socket context.
  1135. //
  1136. RtlFreeHeap( RtlProcessHeap( ), 0, context );
  1137. } else if ( NotifyEvent == WSH_NOTIFY_CONNECT_ERROR ) {
  1138. //
  1139. // Return WSATRY_AGAIN to get wsock32 to attempt the connect
  1140. // again. Any other return code is ignored.
  1141. //
  1142. } else if ( NotifyEvent == WSH_NOTIFY_BIND ) {
  1143. ULONG true = TRUE;
  1144. if( context->UdpNoChecksum ) {
  1145. ULONG flag = FALSE;
  1146. err = SetTdiInformation(
  1147. TdiAddressObjectHandle,
  1148. CL_TL_ENTITY,
  1149. INFO_CLASS_PROTOCOL,
  1150. INFO_TYPE_ADDRESS_OBJECT,
  1151. AO_OPTION_XSUM,
  1152. &flag,
  1153. sizeof(flag),
  1154. TRUE
  1155. );
  1156. if( err != NO_ERROR ) {
  1157. return err;
  1158. }
  1159. }
  1160. if ( context->IpTtl != DEFAULT_IP_TTL ) {
  1161. int value = (int) context->IpTtl;
  1162. err = SetTdiInformation(
  1163. TdiAddressObjectHandle,
  1164. CO_TL_ENTITY,
  1165. INFO_CLASS_PROTOCOL,
  1166. INFO_TYPE_ADDRESS_OBJECT,
  1167. AO_OPTION_TTL,
  1168. &value,
  1169. sizeof(int),
  1170. TRUE
  1171. );
  1172. if ( err != NO_ERROR ) {
  1173. return err;
  1174. }
  1175. }
  1176. if ( context->IpTos != DEFAULT_IP_TOS ) {
  1177. int value = (int) context->IpTos;
  1178. err = SetTdiInformation(
  1179. TdiAddressObjectHandle,
  1180. CO_TL_ENTITY,
  1181. INFO_CLASS_PROTOCOL,
  1182. INFO_TYPE_ADDRESS_OBJECT,
  1183. AO_OPTION_TOS,
  1184. &value,
  1185. sizeof(int),
  1186. TRUE
  1187. );
  1188. if ( err != NO_ERROR ) {
  1189. return err;
  1190. }
  1191. }
  1192. if ( context->MulticastTtl != DEFAULT_MULTICAST_TTL ) {
  1193. int value = (int) context->MulticastTtl;
  1194. err = SetTdiInformation(
  1195. TdiAddressObjectHandle,
  1196. CO_TL_ENTITY,
  1197. INFO_CLASS_PROTOCOL,
  1198. INFO_TYPE_ADDRESS_OBJECT,
  1199. AO_OPTION_MCASTTTL,
  1200. &value,
  1201. sizeof(int),
  1202. TRUE
  1203. );
  1204. if ( err != NO_ERROR ) {
  1205. return err;
  1206. }
  1207. }
  1208. if ( context->MulticastInterface != DEFAULT_MULTICAST_INTERFACE ) {
  1209. int value = (int) context->MulticastInterface;
  1210. err = SetTdiInformation(
  1211. TdiAddressObjectHandle,
  1212. CO_TL_ENTITY,
  1213. INFO_CLASS_PROTOCOL,
  1214. INFO_TYPE_ADDRESS_OBJECT,
  1215. AO_OPTION_MCASTIF,
  1216. &value,
  1217. sizeof(int),
  1218. TRUE
  1219. );
  1220. if ( err != NO_ERROR ) {
  1221. return err;
  1222. }
  1223. }
  1224. if ( context->MulticastLoopback != DEFAULT_MULTICAST_LOOPBACK ) {
  1225. int value = (int) context->MulticastLoopback;
  1226. err = SetTdiInformation(
  1227. TdiAddressObjectHandle,
  1228. CO_TL_ENTITY,
  1229. INFO_CLASS_PROTOCOL,
  1230. INFO_TYPE_ADDRESS_OBJECT,
  1231. AO_OPTION_MCASTLOOP,
  1232. &value,
  1233. sizeof(int),
  1234. TRUE
  1235. );
  1236. if ( err != NO_ERROR ) {
  1237. return err;
  1238. }
  1239. }
  1240. if ( context->HdrIncludeSet ) {
  1241. err = SetTdiInformation(
  1242. TdiAddressObjectHandle,
  1243. CO_TL_ENTITY,
  1244. INFO_CLASS_PROTOCOL,
  1245. INFO_TYPE_ADDRESS_OBJECT,
  1246. AO_OPTION_IP_HDRINCL,
  1247. &context->HdrInclude,
  1248. sizeof (context->HdrInclude),
  1249. TRUE
  1250. );
  1251. if ( err != NO_ERROR ) {
  1252. return err;
  1253. }
  1254. }
  1255. if (context->IpOptionsLength > 0 ) {
  1256. err = SetTdiInformation(
  1257. TdiAddressObjectHandle,
  1258. CO_TL_ENTITY,
  1259. INFO_CLASS_PROTOCOL,
  1260. INFO_TYPE_ADDRESS_OBJECT,
  1261. AO_OPTION_IPOPTIONS,
  1262. context->IpOptions,
  1263. context->IpOptionsLength,
  1264. TRUE
  1265. );
  1266. if ( err != NO_ERROR ) {
  1267. return err;
  1268. }
  1269. }
  1270. if ( context->UcastIf != DEFAULT_UCAST_IF ) {
  1271. int value = (int) context->UcastIf;
  1272. err = SetTdiInformation(
  1273. TdiAddressObjectHandle,
  1274. CO_TL_ENTITY,
  1275. INFO_CLASS_PROTOCOL,
  1276. INFO_TYPE_ADDRESS_OBJECT,
  1277. AO_OPTION_IP_UCASTIF,
  1278. &value,
  1279. sizeof(int),
  1280. TRUE
  1281. );
  1282. if ( err != NO_ERROR ) {
  1283. return err;
  1284. }
  1285. }
  1286. if ( context->IpDontFragment ) {
  1287. err = SetTdiInformation(
  1288. TdiAddressObjectHandle,
  1289. CO_TL_ENTITY,
  1290. INFO_CLASS_PROTOCOL,
  1291. INFO_TYPE_ADDRESS_OBJECT,
  1292. AO_OPTION_IP_DONTFRAGMENT,
  1293. &true,
  1294. sizeof(true),
  1295. TRUE
  1296. );
  1297. if ( err != NO_ERROR ) {
  1298. return err;
  1299. }
  1300. }
  1301. if ( context->ReceiveBroadcast != DEFAULT_RECEIVE_BROADCAST ) {
  1302. int value = (int) context->ReceiveBroadcast;
  1303. err = SetTdiInformation(
  1304. TdiAddressObjectHandle,
  1305. CO_TL_ENTITY,
  1306. INFO_CLASS_PROTOCOL,
  1307. INFO_TYPE_ADDRESS_OBJECT,
  1308. AO_OPTION_BROADCAST,
  1309. &value,
  1310. sizeof(int),
  1311. TRUE
  1312. );
  1313. if ( err != NO_ERROR ) {
  1314. return err;
  1315. }
  1316. }
  1317. if ( context->LimitBroadcasts ) {
  1318. err = SetTdiInformation(
  1319. TdiAddressObjectHandle,
  1320. CO_TL_ENTITY,
  1321. INFO_CLASS_PROTOCOL,
  1322. INFO_TYPE_ADDRESS_OBJECT,
  1323. AO_OPTION_LIMIT_BCASTS,
  1324. &true,
  1325. sizeof(true),
  1326. TRUE
  1327. );
  1328. if ( err != NO_ERROR ) {
  1329. return err;
  1330. }
  1331. }
  1332. if ( context->IpPktInfo ) {
  1333. err = SetTdiInformation(
  1334. TdiAddressObjectHandle,
  1335. CO_TL_ENTITY,
  1336. INFO_CLASS_PROTOCOL,
  1337. INFO_TYPE_ADDRESS_OBJECT,
  1338. AO_OPTION_IP_PKTINFO,
  1339. &true,
  1340. sizeof (TRUE),
  1341. TRUE
  1342. );
  1343. if ( err != NO_ERROR ) {
  1344. return err;
  1345. }
  1346. }
  1347. if ( context->ReceiveBufferSize != DEFAULT_RECEIVE_BUFFER_SIZE ) {
  1348. int value = (int) context->ReceiveBufferSize;
  1349. err = SetTdiInformation(
  1350. TdiAddressObjectHandle,
  1351. CO_TL_ENTITY,
  1352. INFO_CLASS_PROTOCOL,
  1353. INFO_TYPE_ADDRESS_OBJECT,
  1354. AO_OPTION_WINDOW,
  1355. &value,
  1356. sizeof(int),
  1357. TRUE
  1358. );
  1359. if ( err != NO_ERROR ) {
  1360. return err;
  1361. }
  1362. }
  1363. } else {
  1364. return WSAEINVAL;
  1365. }
  1366. return NO_ERROR;
  1367. } // WSHNotify
  1368. INT
  1369. WSHSetSocketInformation (
  1370. IN PVOID HelperDllSocketContext,
  1371. IN SOCKET SocketHandle,
  1372. IN HANDLE TdiAddressObjectHandle,
  1373. IN HANDLE TdiConnectionObjectHandle,
  1374. IN INT Level,
  1375. IN INT OptionName,
  1376. IN PCHAR OptionValue,
  1377. IN INT OptionLength
  1378. )
  1379. /*++
  1380. Routine Description:
  1381. This routine sets information about a socket for those socket
  1382. options supported in this helper DLL. The options supported here
  1383. are SO_KEEPALIVE, SO_DONTROUTE, and TCP_EXPEDITED_1122. This routine is
  1384. called by the winsock DLL when a level/option name combination is
  1385. passed to setsockopt() that the winsock DLL does not understand.
  1386. Arguments:
  1387. HelperDllSocketContext - the context pointer returned from
  1388. WSHOpenSocket().
  1389. SocketHandle - the handle of the socket for which we're getting
  1390. information.
  1391. TdiAddressObjectHandle - the TDI address object of the socket, if
  1392. any. If the socket is not yet bound to an address, then
  1393. it does not have a TDI address object and this parameter
  1394. will be NULL.
  1395. TdiConnectionObjectHandle - the TDI connection object of the socket,
  1396. if any. If the socket is not yet connected, then it does not
  1397. have a TDI connection object and this parameter will be NULL.
  1398. Level - the level parameter passed to setsockopt().
  1399. OptionName - the optname parameter passed to setsockopt().
  1400. OptionValue - the optval parameter passed to setsockopt().
  1401. OptionLength - the optlen parameter passed to setsockopt().
  1402. Return Value:
  1403. INT - a winsock error code indicating the status of the operation, or
  1404. NO_ERROR if the operation succeeded.
  1405. --*/
  1406. {
  1407. PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
  1408. INT error;
  1409. INT optionValue;
  1410. //
  1411. // Check if this is an internal request for context information.
  1412. //
  1413. if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
  1414. //
  1415. // The Windows Sockets DLL is requesting that we set context
  1416. // information for a new socket. If the new socket was
  1417. // accept()'ed, then we have already been notified of the socket
  1418. // and HelperDllSocketContext will be valid. If the new socket
  1419. // was inherited or duped into this process, then this is our
  1420. // first notification of the socket and HelperDllSocketContext
  1421. // will be equal to NULL.
  1422. //
  1423. // Insure that the context information being passed to us is
  1424. // sufficiently large.
  1425. //
  1426. if ( OptionLength < sizeof(*context) || ( OptionValue == NULL)) {
  1427. return WSAEINVAL;
  1428. }
  1429. if ( HelperDllSocketContext == NULL ) {
  1430. //
  1431. // This is our notification that a socket handle was
  1432. // inherited or duped into this process. Allocate a context
  1433. // structure for the new socket.
  1434. //
  1435. context = RtlAllocateHeap( RtlProcessHeap( ), 0, sizeof(*context) );
  1436. if ( context == NULL ) {
  1437. return WSAENOBUFS;
  1438. }
  1439. //
  1440. // Copy over information into the context block.
  1441. //
  1442. RtlCopyMemory( context, OptionValue, sizeof(*context) );
  1443. //
  1444. // Tell the Windows Sockets DLL where our context information is
  1445. // stored so that it can return the context pointer in future
  1446. // calls.
  1447. //
  1448. *(PWSHTCPIP_SOCKET_CONTEXT *)OptionValue = context;
  1449. return NO_ERROR;
  1450. } else {
  1451. PWSHTCPIP_SOCKET_CONTEXT parentContext;
  1452. INT one = 1;
  1453. INT zero = 0;
  1454. //
  1455. // The socket was accept()'ed and it needs to have the same
  1456. // properties as it's parent. The OptionValue buffer
  1457. // contains the context information of this socket's parent.
  1458. //
  1459. parentContext = (PWSHTCPIP_SOCKET_CONTEXT)OptionValue;
  1460. ASSERT( context->AddressFamily == parentContext->AddressFamily );
  1461. ASSERT( context->SocketType == parentContext->SocketType );
  1462. ASSERT( context->Protocol == parentContext->Protocol );
  1463. //
  1464. // Turn on in the child any options that have been set in
  1465. // the parent. First restore the child context to default context.
  1466. // Ignore all the changes made by APP before acceptex complete.
  1467. //
  1468. context->KeepAlive = FALSE;
  1469. if ( parentContext->KeepAlive ) {
  1470. error = WSHSetSocketInformation(
  1471. HelperDllSocketContext,
  1472. SocketHandle,
  1473. TdiAddressObjectHandle,
  1474. TdiConnectionObjectHandle,
  1475. SOL_SOCKET,
  1476. SO_KEEPALIVE,
  1477. (PCHAR)&one,
  1478. sizeof(one)
  1479. );
  1480. if ( error != NO_ERROR ) {
  1481. return error;
  1482. }
  1483. }
  1484. context->KeepAliveVals.onoff = FALSE;
  1485. if ( parentContext->KeepAliveVals.onoff ) {
  1486. struct tcp_keepalive *optionval;
  1487. //
  1488. // Atempt to turn on or off keepalive sending, as necessary.
  1489. //
  1490. optionval = (struct tcp_keepalive *)&parentContext->KeepAliveVals;
  1491. if ( TdiConnectionObjectHandle != NULL ) {
  1492. error = SetTdiInformation(
  1493. TdiConnectionObjectHandle,
  1494. CO_TL_ENTITY,
  1495. INFO_CLASS_PROTOCOL,
  1496. INFO_TYPE_CONNECTION,
  1497. TCP_SOCKET_KEEPALIVE_VALS,
  1498. optionval,
  1499. sizeof(struct tcp_keepalive),
  1500. TRUE
  1501. );
  1502. if ( error != NO_ERROR ) {
  1503. return error;
  1504. }
  1505. }
  1506. //
  1507. // Remember that keepalives are enabled for this socket.
  1508. //
  1509. context->KeepAliveVals.onoff = TRUE;
  1510. context->KeepAliveVals.keepalivetime = optionval->keepalivetime;
  1511. context->KeepAliveVals.keepaliveinterval = optionval->keepaliveinterval;
  1512. }
  1513. context->DontRoute = FALSE;
  1514. if ( parentContext->DontRoute ) {
  1515. error = WSHSetSocketInformation(
  1516. HelperDllSocketContext,
  1517. SocketHandle,
  1518. TdiAddressObjectHandle,
  1519. TdiConnectionObjectHandle,
  1520. SOL_SOCKET,
  1521. SO_DONTROUTE,
  1522. (PCHAR)&one,
  1523. sizeof(one)
  1524. );
  1525. if ( error != NO_ERROR ) {
  1526. return error;
  1527. }
  1528. }
  1529. context->NoDelay = FALSE;
  1530. if ( parentContext->NoDelay ) {
  1531. error = WSHSetSocketInformation(
  1532. HelperDllSocketContext,
  1533. SocketHandle,
  1534. TdiAddressObjectHandle,
  1535. TdiConnectionObjectHandle,
  1536. IPPROTO_TCP,
  1537. TCP_NODELAY,
  1538. (PCHAR)&one,
  1539. sizeof(one)
  1540. );
  1541. if ( error != NO_ERROR ) {
  1542. return error;
  1543. }
  1544. }
  1545. context->ReceiveBufferSize = DEFAULT_RECEIVE_BUFFER_SIZE;
  1546. if ( parentContext->ReceiveBufferSize != DEFAULT_RECEIVE_BUFFER_SIZE ) {
  1547. error = WSHSetSocketInformation(
  1548. HelperDllSocketContext,
  1549. SocketHandle,
  1550. TdiAddressObjectHandle,
  1551. TdiConnectionObjectHandle,
  1552. SOL_SOCKET,
  1553. SO_RCVBUF,
  1554. (PCHAR)&parentContext->ReceiveBufferSize,
  1555. sizeof(parentContext->ReceiveBufferSize)
  1556. );
  1557. if ( error != NO_ERROR ) {
  1558. return error;
  1559. }
  1560. }
  1561. context->BsdUrgent = TRUE;
  1562. if ( !parentContext->BsdUrgent ) {
  1563. error = WSHSetSocketInformation(
  1564. HelperDllSocketContext,
  1565. SocketHandle,
  1566. TdiAddressObjectHandle,
  1567. TdiConnectionObjectHandle,
  1568. IPPROTO_TCP,
  1569. TCP_EXPEDITED_1122,
  1570. (PCHAR)&one,
  1571. sizeof(one)
  1572. );
  1573. if ( error != NO_ERROR ) {
  1574. return error;
  1575. }
  1576. }
  1577. context->IpTos = DEFAULT_IP_TOS;
  1578. if ( parentContext->IpTos != DEFAULT_IP_TOS ) {
  1579. int value = (int) parentContext->IpTos;
  1580. error = WSHSetSocketInformation(
  1581. HelperDllSocketContext,
  1582. SocketHandle,
  1583. TdiAddressObjectHandle,
  1584. TdiConnectionObjectHandle,
  1585. IPPROTO_IP,
  1586. IP_TOS,
  1587. (PCHAR)&value,
  1588. sizeof(value)
  1589. );
  1590. if ( error != NO_ERROR ) {
  1591. return error;
  1592. }
  1593. }
  1594. return NO_ERROR;
  1595. }
  1596. }
  1597. //
  1598. // The only other levels we support here are SOL_SOCKET,
  1599. // IPPROTO_TCP, IPPROTO_UDP, and IPPROTO_IP.
  1600. //
  1601. if ( Level != SOL_SOCKET &&
  1602. Level != IPPROTO_TCP &&
  1603. Level != IPPROTO_UDP &&
  1604. Level != IPPROTO_IP ) {
  1605. return WSAEINVAL;
  1606. }
  1607. //
  1608. // Make sure that the option length is sufficient.
  1609. //
  1610. if ( OptionLength < sizeof(char) || (OptionValue == NULL) ) {
  1611. return WSAEFAULT;
  1612. }
  1613. if ( OptionLength >= sizeof (int)) {
  1614. optionValue = *((INT UNALIGNED *)OptionValue);
  1615. }
  1616. else {
  1617. optionValue = (UCHAR)*OptionValue;
  1618. }
  1619. //
  1620. // Handle TCP-level options.
  1621. //
  1622. if ( Level == IPPROTO_TCP && OptionName == TCP_NODELAY ) {
  1623. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  1624. return WSAENOPROTOOPT;
  1625. }
  1626. //
  1627. // Atempt to turn on or off Nagle's algorithm, as necessary.
  1628. //
  1629. if ( !context->NoDelay && optionValue != 0 ) {
  1630. optionValue = TRUE;
  1631. //
  1632. // NoDelay is currently off and the application wants to
  1633. // turn it on. If the TDI connection object handle is NULL,
  1634. // then the socket is not yet connected. In this case we'll
  1635. // just remember that the no delay option was set and
  1636. // actually turn them on in WSHNotify() after a connect()
  1637. // has completed on the socket.
  1638. //
  1639. if ( TdiConnectionObjectHandle != NULL ) {
  1640. error = SetTdiInformation(
  1641. TdiConnectionObjectHandle,
  1642. CO_TL_ENTITY,
  1643. INFO_CLASS_PROTOCOL,
  1644. INFO_TYPE_CONNECTION,
  1645. TCP_SOCKET_NODELAY,
  1646. &optionValue,
  1647. sizeof(optionValue),
  1648. TRUE
  1649. );
  1650. if ( error != NO_ERROR ) {
  1651. return error;
  1652. }
  1653. }
  1654. //
  1655. // Remember that no delay is enabled for this socket.
  1656. //
  1657. context->NoDelay = TRUE;
  1658. } else if ( context->NoDelay && optionValue == 0 ) {
  1659. //
  1660. // No delay is currently enabled and the application wants
  1661. // to turn it off. If the TDI connection object is NULL,
  1662. // the socket is not yet connected. In this case we'll just
  1663. // remember that nodelay is disabled.
  1664. //
  1665. if ( TdiConnectionObjectHandle != NULL ) {
  1666. error = SetTdiInformation(
  1667. TdiConnectionObjectHandle,
  1668. CO_TL_ENTITY,
  1669. INFO_CLASS_PROTOCOL,
  1670. INFO_TYPE_CONNECTION,
  1671. TCP_SOCKET_NODELAY,
  1672. &optionValue,
  1673. sizeof(optionValue),
  1674. TRUE
  1675. );
  1676. if ( error != NO_ERROR ) {
  1677. return error;
  1678. }
  1679. }
  1680. //
  1681. // Remember that no delay is disabled for this socket.
  1682. //
  1683. context->NoDelay = FALSE;
  1684. }
  1685. return NO_ERROR;
  1686. }
  1687. if ( Level == IPPROTO_TCP && OptionName == TCP_EXPEDITED_1122 ) {
  1688. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  1689. return WSAENOPROTOOPT;
  1690. }
  1691. //
  1692. // Atempt to turn on or off BSD-style urgent data semantics as
  1693. // necessary.
  1694. //
  1695. if ( !context->BsdUrgent && optionValue == 0 ) {
  1696. optionValue = TRUE;
  1697. //
  1698. // BsdUrgent is currently off and the application wants to
  1699. // turn it on. If the TDI connection object handle is NULL,
  1700. // then the socket is not yet connected. In this case we'll
  1701. // just remember that the no delay option was set and
  1702. // actually turn them on in WSHNotify() after a connect()
  1703. // has completed on the socket.
  1704. //
  1705. if ( TdiConnectionObjectHandle != NULL ) {
  1706. error = SetTdiInformation(
  1707. TdiConnectionObjectHandle,
  1708. CO_TL_ENTITY,
  1709. INFO_CLASS_PROTOCOL,
  1710. INFO_TYPE_CONNECTION,
  1711. TCP_SOCKET_BSDURGENT,
  1712. &optionValue,
  1713. sizeof(optionValue),
  1714. TRUE
  1715. );
  1716. if ( error != NO_ERROR ) {
  1717. return error;
  1718. }
  1719. }
  1720. //
  1721. // Remember that BSD urgent is enabled for this socket.
  1722. //
  1723. context->BsdUrgent = TRUE;
  1724. } else if ( context->BsdUrgent && optionValue != 0 ) {
  1725. //
  1726. // No delay is currently enabled and the application wants
  1727. // to turn it off. If the TDI connection object is NULL,
  1728. // the socket is not yet connected. In this case we'll just
  1729. // remember that BsdUrgent is disabled.
  1730. //
  1731. if ( TdiConnectionObjectHandle != NULL ) {
  1732. error = SetTdiInformation(
  1733. TdiConnectionObjectHandle,
  1734. CO_TL_ENTITY,
  1735. INFO_CLASS_PROTOCOL,
  1736. INFO_TYPE_CONNECTION,
  1737. TCP_SOCKET_BSDURGENT,
  1738. &optionValue,
  1739. sizeof(optionValue),
  1740. TRUE
  1741. );
  1742. if ( error != NO_ERROR ) {
  1743. return error;
  1744. }
  1745. }
  1746. //
  1747. // Remember that BSD urgent is disabled for this socket.
  1748. //
  1749. context->BsdUrgent = FALSE;
  1750. }
  1751. return NO_ERROR;
  1752. }
  1753. //
  1754. // Handle UDP-level options.
  1755. //
  1756. if ( Level == IPPROTO_UDP ) {
  1757. switch ( OptionName ) {
  1758. case UDP_NOCHECKSUM :
  1759. //
  1760. // This option is only valid for datagram sockets.
  1761. //
  1762. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1763. return WSAENOPROTOOPT;
  1764. }
  1765. if( TdiAddressObjectHandle != NULL ) {
  1766. ULONG flag;
  1767. //
  1768. // Note that the incoming flag is TRUE if XSUM should
  1769. // be *disabled*, but the flag we pass to TDI is TRUE
  1770. // if it should be *enabled*, so we must negate the flag.
  1771. //
  1772. flag = (ULONG)!optionValue;
  1773. error = SetTdiInformation(
  1774. TdiAddressObjectHandle,
  1775. CL_TL_ENTITY,
  1776. INFO_CLASS_PROTOCOL,
  1777. INFO_TYPE_ADDRESS_OBJECT,
  1778. AO_OPTION_XSUM,
  1779. &flag,
  1780. sizeof(flag),
  1781. TRUE
  1782. );
  1783. if( error != NO_ERROR ) {
  1784. return error;
  1785. }
  1786. }
  1787. context->UdpNoChecksum = !!optionValue;
  1788. break;
  1789. default :
  1790. return WSAEINVAL;
  1791. }
  1792. return NO_ERROR;
  1793. }
  1794. //
  1795. // Handle IP-level options.
  1796. //
  1797. if ( Level == IPPROTO_IP ) {
  1798. //
  1799. // Act based on the specific option.
  1800. //
  1801. switch ( OptionName ) {
  1802. case IP_TTL:
  1803. //
  1804. // An attempt to change the unicast TTL sent on
  1805. // this socket. It is illegal to set this to a value
  1806. // greater than 255.
  1807. //
  1808. if ( optionValue > 255 || optionValue < 0 ) {
  1809. return WSAEINVAL;
  1810. }
  1811. //
  1812. // If we have a TDI address object, set this option to
  1813. // the address object. If we don't have a TDI address
  1814. // object then we'll have to wait until after the socket
  1815. // is bound.
  1816. //
  1817. if ( TdiAddressObjectHandle != NULL ) {
  1818. error = SetTdiInformation(
  1819. TdiAddressObjectHandle,
  1820. CL_TL_ENTITY,
  1821. INFO_CLASS_PROTOCOL,
  1822. INFO_TYPE_ADDRESS_OBJECT,
  1823. AO_OPTION_TTL,
  1824. &optionValue,
  1825. sizeof(optionValue),
  1826. TRUE
  1827. );
  1828. if ( error != NO_ERROR ) {
  1829. return error;
  1830. }
  1831. }
  1832. context->IpTtl = (uchar) optionValue;
  1833. return NO_ERROR;
  1834. case IP_TOS:
  1835. //
  1836. // An attempt to change the Type Of Service of packets sent on
  1837. // this socket. It is illegal to set this to a value
  1838. // greater than 255.
  1839. //
  1840. if ( optionValue > 255 || optionValue < 0 ) {
  1841. return WSAEINVAL;
  1842. }
  1843. //
  1844. // If we have a TDI address or connectionobject,
  1845. // set this option to it. If we don't have a TDI
  1846. // object then we'll have to wait until after the socket
  1847. // is bound or connected.
  1848. //
  1849. if ( TdiConnectionObjectHandle != NULL ) {
  1850. error = SetTdiInformation(
  1851. TdiConnectionObjectHandle,
  1852. CO_TL_ENTITY,
  1853. INFO_CLASS_PROTOCOL,
  1854. INFO_TYPE_CONNECTION,
  1855. TCP_SOCKET_TOS,
  1856. &optionValue,
  1857. sizeof(optionValue),
  1858. TRUE
  1859. );
  1860. if ( error != NO_ERROR ) {
  1861. return error;
  1862. }
  1863. }
  1864. else if ( TdiAddressObjectHandle != NULL ) {
  1865. error = SetTdiInformation(
  1866. TdiAddressObjectHandle,
  1867. CL_TL_ENTITY,
  1868. INFO_CLASS_PROTOCOL,
  1869. INFO_TYPE_ADDRESS_OBJECT,
  1870. AO_OPTION_TOS,
  1871. &optionValue,
  1872. sizeof(optionValue),
  1873. TRUE
  1874. );
  1875. if ( error != NO_ERROR ) {
  1876. return error;
  1877. }
  1878. }
  1879. context->IpTos = (uchar) optionValue;
  1880. return NO_ERROR;
  1881. case IP_MULTICAST_TTL:
  1882. //
  1883. // This option is only valid for datagram sockets.
  1884. //
  1885. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1886. return WSAENOPROTOOPT;
  1887. }
  1888. //
  1889. // An attempt to change the TTL on multicasts sent on
  1890. // this socket. It is illegal to set this to a value
  1891. // greater than 255.
  1892. //
  1893. if ( optionValue > 255 || optionValue < 0 ) {
  1894. return WSAEINVAL;
  1895. }
  1896. //
  1897. // If we have a TDI address object, set this option to
  1898. // the address object. If we don't have a TDI address
  1899. // object then we'll have to wait until after the socket
  1900. // is bound.
  1901. //
  1902. if ( TdiAddressObjectHandle != NULL ) {
  1903. error = SetTdiInformation(
  1904. TdiAddressObjectHandle,
  1905. CL_TL_ENTITY,
  1906. INFO_CLASS_PROTOCOL,
  1907. INFO_TYPE_ADDRESS_OBJECT,
  1908. AO_OPTION_MCASTTTL,
  1909. &optionValue,
  1910. sizeof(optionValue),
  1911. TRUE
  1912. );
  1913. if ( error != NO_ERROR ) {
  1914. return error;
  1915. }
  1916. }
  1917. context->MulticastTtl = optionValue;
  1918. return NO_ERROR;
  1919. case IP_MULTICAST_IF:
  1920. //
  1921. // This option is only valid for datagram sockets.
  1922. //
  1923. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1924. return WSAENOPROTOOPT;
  1925. }
  1926. //
  1927. // If we have a TDI address object, set this option to
  1928. // the address object. If we don't have a TDI address
  1929. // object then we'll have to wait until after the socket
  1930. // is bound.
  1931. //
  1932. if ( TdiAddressObjectHandle != NULL ) {
  1933. error = SetTdiInformation(
  1934. TdiAddressObjectHandle,
  1935. CL_TL_ENTITY,
  1936. INFO_CLASS_PROTOCOL,
  1937. INFO_TYPE_ADDRESS_OBJECT,
  1938. AO_OPTION_MCASTIF,
  1939. &optionValue,
  1940. sizeof(optionValue),
  1941. TRUE
  1942. );
  1943. if ( error != NO_ERROR ) {
  1944. return error;
  1945. }
  1946. }
  1947. context->MulticastInterface = optionValue;
  1948. return NO_ERROR;
  1949. case IP_MULTICAST_LOOP:
  1950. //
  1951. // This option is only valid for datagram sockets.
  1952. //
  1953. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1954. return WSAENOPROTOOPT;
  1955. }
  1956. if ( TdiAddressObjectHandle != NULL ) {
  1957. error = SetTdiInformation(
  1958. TdiAddressObjectHandle,
  1959. CL_TL_ENTITY,
  1960. INFO_CLASS_PROTOCOL,
  1961. INFO_TYPE_ADDRESS_OBJECT,
  1962. AO_OPTION_MCASTLOOP,
  1963. &optionValue,
  1964. sizeof(optionValue),
  1965. TRUE
  1966. );
  1967. if ( error != NO_ERROR ) {
  1968. return error;
  1969. }
  1970. }
  1971. context->MulticastLoopback = optionValue ? TRUE : FALSE;
  1972. return NO_ERROR;
  1973. case IP_ADD_MEMBERSHIP:
  1974. case IP_DROP_MEMBERSHIP:
  1975. //
  1976. // This option is only valid for datagram sockets.
  1977. //
  1978. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1979. return WSAENOPROTOOPT;
  1980. }
  1981. //
  1982. // Make sure that the option buffer is large enough.
  1983. //
  1984. if ( OptionLength < sizeof(struct ip_mreq) ) {
  1985. return WSAEFAULT;
  1986. }
  1987. //
  1988. // If we have a TDI address object, set this option to
  1989. // the address object. If we don't have a TDI address
  1990. // object then we'll have to wait until after the socket
  1991. // is bound.
  1992. //
  1993. if ( TdiAddressObjectHandle != NULL ) {
  1994. error = SetTdiInformation(
  1995. TdiAddressObjectHandle,
  1996. CL_TL_ENTITY,
  1997. INFO_CLASS_PROTOCOL,
  1998. INFO_TYPE_ADDRESS_OBJECT,
  1999. OptionName == IP_ADD_MEMBERSHIP ?
  2000. AO_OPTION_ADD_MCAST : AO_OPTION_DEL_MCAST,
  2001. OptionValue,
  2002. OptionLength,
  2003. TRUE
  2004. );
  2005. if ( error != NO_ERROR ) {
  2006. return error;
  2007. }
  2008. } else {
  2009. return WSAEINVAL;
  2010. }
  2011. return NO_ERROR;
  2012. case IP_BLOCK_SOURCE:
  2013. case IP_UNBLOCK_SOURCE:
  2014. //
  2015. // This option is only valid for datagram sockets.
  2016. //
  2017. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  2018. return WSAENOPROTOOPT;
  2019. }
  2020. //
  2021. // Make sure that the option buffer is large enough.
  2022. //
  2023. if ( OptionLength < sizeof(struct ip_mreq_source) ) {
  2024. return WSAEFAULT;
  2025. }
  2026. //
  2027. // If we have a TDI address object, set this option to
  2028. // the address object. If we don't have a TDI address
  2029. // object then we'll have to wait until after the socket
  2030. // is bound.
  2031. //
  2032. if ( TdiAddressObjectHandle != NULL ) {
  2033. error = SetTdiInformation(
  2034. TdiAddressObjectHandle,
  2035. CL_TL_ENTITY,
  2036. INFO_CLASS_PROTOCOL,
  2037. INFO_TYPE_ADDRESS_OBJECT,
  2038. OptionName == IP_BLOCK_SOURCE ?
  2039. AO_OPTION_BLOCK_MCAST_SRC :
  2040. AO_OPTION_UNBLOCK_MCAST_SRC,
  2041. OptionValue,
  2042. OptionLength,
  2043. TRUE
  2044. );
  2045. if ( error != NO_ERROR ) {
  2046. return error;
  2047. }
  2048. } else {
  2049. return WSAEINVAL;
  2050. }
  2051. return NO_ERROR;
  2052. case IP_ADD_SOURCE_MEMBERSHIP:
  2053. case IP_DROP_SOURCE_MEMBERSHIP:
  2054. //
  2055. // This option is only valid for datagram sockets.
  2056. //
  2057. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  2058. return WSAENOPROTOOPT;
  2059. }
  2060. //
  2061. // Make sure that the option buffer is large enough.
  2062. //
  2063. if ( OptionLength < sizeof(struct ip_mreq_source) ) {
  2064. return WSAEFAULT;
  2065. }
  2066. //
  2067. // If we have a TDI address object, set this option to
  2068. // the address object. If we don't have a TDI address
  2069. // object then we'll have to wait until after the socket
  2070. // is bound.
  2071. //
  2072. if ( TdiAddressObjectHandle != NULL ) {
  2073. error = SetTdiInformation(
  2074. TdiAddressObjectHandle,
  2075. CL_TL_ENTITY,
  2076. INFO_CLASS_PROTOCOL,
  2077. INFO_TYPE_ADDRESS_OBJECT,
  2078. OptionName == IP_ADD_SOURCE_MEMBERSHIP ?
  2079. AO_OPTION_ADD_MCAST_SRC :
  2080. AO_OPTION_DEL_MCAST_SRC,
  2081. OptionValue,
  2082. OptionLength,
  2083. TRUE
  2084. );
  2085. if ( error != NO_ERROR ) {
  2086. return error;
  2087. }
  2088. } else {
  2089. return WSAEINVAL;
  2090. }
  2091. return NO_ERROR;
  2092. case IP_HDRINCL:
  2093. // User hdr include option
  2094. //
  2095. //
  2096. if ( OptionLength != 4) {
  2097. return WSAEINVAL;
  2098. }
  2099. if ( TdiAddressObjectHandle != NULL ) {
  2100. error = SetTdiInformation(
  2101. TdiAddressObjectHandle,
  2102. CL_TL_ENTITY,
  2103. INFO_CLASS_PROTOCOL,
  2104. INFO_TYPE_ADDRESS_OBJECT,
  2105. AO_OPTION_IP_HDRINCL,
  2106. &optionValue,
  2107. OptionLength,
  2108. TRUE
  2109. );
  2110. if ( error != NO_ERROR ) {
  2111. return error;
  2112. }
  2113. }
  2114. context->HdrIncludeSet = TRUE;
  2115. context->HdrInclude = optionValue;
  2116. return NO_ERROR;
  2117. case IP_PKTINFO:
  2118. //
  2119. // This option is only valid for datagram sockets.
  2120. //
  2121. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  2122. return WSAENOPROTOOPT;
  2123. }
  2124. if ( TdiAddressObjectHandle != NULL ) {
  2125. error = SetTdiInformation(
  2126. TdiAddressObjectHandle,
  2127. CL_TL_ENTITY,
  2128. INFO_CLASS_PROTOCOL,
  2129. INFO_TYPE_ADDRESS_OBJECT,
  2130. AO_OPTION_IP_PKTINFO,
  2131. &optionValue,
  2132. sizeof(optionValue),
  2133. TRUE
  2134. );
  2135. if ( error != NO_ERROR ) {
  2136. return error;
  2137. }
  2138. }
  2139. context->IpPktInfo = optionValue ? TRUE : FALSE;
  2140. return NO_ERROR;
  2141. case IP_RECEIVE_BROADCAST:
  2142. //
  2143. // This option is only valid for datagram sockets.
  2144. //
  2145. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  2146. return WSAENOPROTOOPT;
  2147. }
  2148. if ( OptionLength != sizeof(uint)) {
  2149. return WSAEINVAL;
  2150. }
  2151. if ( TdiAddressObjectHandle != NULL ) {
  2152. error = SetTdiInformation(
  2153. TdiAddressObjectHandle,
  2154. CL_TL_ENTITY,
  2155. INFO_CLASS_PROTOCOL,
  2156. INFO_TYPE_ADDRESS_OBJECT,
  2157. AO_OPTION_BROADCAST,
  2158. &optionValue,
  2159. sizeof(optionValue),
  2160. TRUE
  2161. );
  2162. if ( error != NO_ERROR ) {
  2163. return error;
  2164. }
  2165. }
  2166. context->ReceiveBroadcast = optionValue ? TRUE : FALSE;
  2167. return NO_ERROR;
  2168. default:
  2169. //
  2170. // No match, fall through.
  2171. //
  2172. break;
  2173. }
  2174. if ( OptionName == IP_OPTIONS ) {
  2175. //
  2176. // Setting IP options.
  2177. //
  2178. if (OptionLength < 0 || OptionLength > MAX_OPT_SIZE ||
  2179. ( OptionValue == NULL) ) {
  2180. return WSAEINVAL;
  2181. }
  2182. //
  2183. // Try to set these options. If the TDI address object handle
  2184. // is NULL, then the socket is not yet bound. In this case we'll
  2185. // just remember options and actually set them in WSHNotify()
  2186. // after a bind has completed on the socket.
  2187. //
  2188. if ( TdiAddressObjectHandle != NULL ) {
  2189. error = SetTdiInformation(
  2190. TdiAddressObjectHandle,
  2191. CO_TL_ENTITY,
  2192. INFO_CLASS_PROTOCOL,
  2193. INFO_TYPE_ADDRESS_OBJECT,
  2194. AO_OPTION_IPOPTIONS,
  2195. OptionValue,
  2196. OptionLength,
  2197. TRUE
  2198. );
  2199. if ( error != NO_ERROR ) {
  2200. return error;
  2201. }
  2202. }
  2203. //
  2204. // They were successfully set. Copy them.
  2205. //
  2206. RtlMoveMemory(context->IpOptions, OptionValue, OptionLength);
  2207. context->IpOptionsLength = (UCHAR)OptionLength;
  2208. return NO_ERROR;
  2209. }
  2210. if ( OptionName == IP_DONTFRAGMENT ) {
  2211. //
  2212. // Attempt to turn on or off the DF bit in the IP header.
  2213. //
  2214. if ( !context->IpDontFragment && optionValue != 0 ) {
  2215. optionValue = TRUE;
  2216. //
  2217. // DF is currently off and the application wants to
  2218. // turn it on. If the TDI address object handle is NULL,
  2219. // then the socket is not yet bound. In this case we'll
  2220. // just remember that the header inclusion option was set and
  2221. // actually turn it on in WSHNotify() after a bind
  2222. // has completed on the socket.
  2223. //
  2224. if ( TdiAddressObjectHandle != NULL ) {
  2225. error = SetTdiInformation(
  2226. TdiAddressObjectHandle,
  2227. CO_TL_ENTITY,
  2228. INFO_CLASS_PROTOCOL,
  2229. INFO_TYPE_ADDRESS_OBJECT,
  2230. AO_OPTION_IP_DONTFRAGMENT,
  2231. &optionValue,
  2232. sizeof(optionValue),
  2233. TRUE
  2234. );
  2235. if ( error != NO_ERROR ) {
  2236. return error;
  2237. }
  2238. }
  2239. //
  2240. // Remember that header inclusion is enabled for this socket.
  2241. //
  2242. context->IpDontFragment = TRUE;
  2243. } else if ( context->IpDontFragment && optionValue == 0 ) {
  2244. //
  2245. // The DF flag is currently set and the application wants
  2246. // to turn it off. If the TDI address object is NULL,
  2247. // the socket is not yet bound. In this case we'll just
  2248. // remember that the flag is turned off.
  2249. //
  2250. if ( TdiAddressObjectHandle != NULL ) {
  2251. error = SetTdiInformation(
  2252. TdiAddressObjectHandle,
  2253. CO_TL_ENTITY,
  2254. INFO_CLASS_PROTOCOL,
  2255. INFO_TYPE_ADDRESS_OBJECT,
  2256. AO_OPTION_IP_DONTFRAGMENT,
  2257. &optionValue,
  2258. sizeof(optionValue),
  2259. TRUE
  2260. );
  2261. if ( error != NO_ERROR ) {
  2262. return error;
  2263. }
  2264. }
  2265. //
  2266. // Remember that DF flag is not set for this socket.
  2267. //
  2268. context->IpDontFragment = FALSE;
  2269. }
  2270. return NO_ERROR;
  2271. }
  2272. //
  2273. // We don't support this option.
  2274. //
  2275. return WSAENOPROTOOPT;
  2276. }
  2277. //
  2278. // Handle socket-level options.
  2279. //
  2280. switch ( OptionName ) {
  2281. case SO_KEEPALIVE:
  2282. //
  2283. // Atempt to turn on or off keepalive sending, as necessary.
  2284. //
  2285. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  2286. return WSAENOPROTOOPT;
  2287. }
  2288. if ( !context->KeepAlive && optionValue != 0 ) {
  2289. optionValue = TRUE;
  2290. //
  2291. // Keepalives are currently off and the application wants to
  2292. // turn them on. If the TDI connection object handle is
  2293. // NULL, then the socket is not yet connected. In this case
  2294. // we'll just remember that the keepalive option was set and
  2295. // actually turn them on in WSHNotify() after a connect()
  2296. // has completed on the socket.
  2297. //
  2298. if ( TdiConnectionObjectHandle != NULL ) {
  2299. error = SetTdiInformation(
  2300. TdiConnectionObjectHandle,
  2301. CO_TL_ENTITY,
  2302. INFO_CLASS_PROTOCOL,
  2303. INFO_TYPE_CONNECTION,
  2304. TCP_SOCKET_KEEPALIVE,
  2305. &optionValue,
  2306. sizeof(optionValue),
  2307. TRUE
  2308. );
  2309. if ( error != NO_ERROR ) {
  2310. return error;
  2311. }
  2312. }
  2313. //
  2314. // Remember that keepalives are enabled for this socket.
  2315. //
  2316. context->KeepAlive = TRUE;
  2317. } else if ( context->KeepAlive && optionValue == 0 ) {
  2318. //
  2319. // Keepalives are currently enabled and the application
  2320. // wants to turn them off. If the TDI connection object is
  2321. // NULL, the socket is not yet connected. In this case
  2322. // we'll just remember that keepalives are disabled.
  2323. //
  2324. if ( TdiConnectionObjectHandle != NULL ) {
  2325. error = SetTdiInformation(
  2326. TdiConnectionObjectHandle,
  2327. CO_TL_ENTITY,
  2328. INFO_CLASS_PROTOCOL,
  2329. INFO_TYPE_CONNECTION,
  2330. TCP_SOCKET_KEEPALIVE,
  2331. &optionValue,
  2332. sizeof(optionValue),
  2333. TRUE
  2334. );
  2335. if ( error != NO_ERROR ) {
  2336. return error;
  2337. }
  2338. }
  2339. //
  2340. // Remember that keepalives are disabled for this socket.
  2341. //
  2342. context->KeepAlive = FALSE;
  2343. }
  2344. break;
  2345. case SO_DONTROUTE:
  2346. //
  2347. // We don't really support SO_DONTROUTE. Just remember that the
  2348. // option was set or unset.
  2349. //
  2350. if ( optionValue != 0 ) {
  2351. context->DontRoute = TRUE;
  2352. } else if ( optionValue == 0 ) {
  2353. context->DontRoute = FALSE;
  2354. }
  2355. break;
  2356. case SO_RCVBUF:
  2357. //
  2358. // If the receive buffer size is being changed, tell TCP about
  2359. // it. Do nothing if this is a datagram.
  2360. //
  2361. if ( context->ReceiveBufferSize == optionValue ||
  2362. IS_DGRAM_SOCK(context->SocketType)
  2363. ) {
  2364. break;
  2365. }
  2366. if ( TdiConnectionObjectHandle != NULL ) {
  2367. error = SetTdiInformation(
  2368. TdiConnectionObjectHandle,
  2369. CO_TL_ENTITY,
  2370. INFO_CLASS_PROTOCOL,
  2371. INFO_TYPE_CONNECTION,
  2372. TCP_SOCKET_WINDOW,
  2373. &optionValue,
  2374. sizeof(optionValue),
  2375. TRUE
  2376. );
  2377. if ( error != NO_ERROR ) {
  2378. return error;
  2379. }
  2380. } else if ( TdiAddressObjectHandle != NULL ) {
  2381. error = SetTdiInformation(
  2382. TdiAddressObjectHandle,
  2383. CO_TL_ENTITY,
  2384. INFO_CLASS_PROTOCOL,
  2385. INFO_TYPE_ADDRESS_OBJECT,
  2386. AO_OPTION_WINDOW,
  2387. &optionValue,
  2388. sizeof(optionValue),
  2389. TRUE
  2390. );
  2391. if ( error != NO_ERROR ) {
  2392. return error;
  2393. }
  2394. }
  2395. context->ReceiveBufferSize = optionValue;
  2396. break;
  2397. default:
  2398. return WSAENOPROTOOPT;
  2399. }
  2400. return NO_ERROR;
  2401. } // WSHSetSocketInformation
  2402. INT
  2403. WSHEnumProtocols (
  2404. IN LPINT lpiProtocols,
  2405. IN LPWSTR lpTransportKeyName,
  2406. IN OUT LPVOID lpProtocolBuffer,
  2407. IN OUT LPDWORD lpdwBufferLength
  2408. )
  2409. /*++
  2410. Routine Description:
  2411. Enumerates the protocols supported by this helper.
  2412. Arguments:
  2413. lpiProtocols - Pointer to a NULL-terminated array of protocol
  2414. identifiers. Only protocols specified in this array will
  2415. be returned by this function. If this pointer is NULL,
  2416. all protocols are returned.
  2417. lpTransportKeyName -
  2418. lpProtocolBuffer - Pointer to a buffer to fill with PROTOCOL_INFO
  2419. structures.
  2420. lpdwBufferLength - Pointer to a variable that, on input, contains
  2421. the size of lpProtocolBuffer. On output, this value will be
  2422. updated with the size of the data actually written to the buffer.
  2423. Return Value:
  2424. INT - The number of protocols returned if successful, -1 if not.
  2425. --*/
  2426. {
  2427. DWORD bytesRequired;
  2428. PPROTOCOL_INFO tcpProtocolInfo;
  2429. PPROTOCOL_INFO udpProtocolInfo;
  2430. BOOL useTcp = FALSE;
  2431. BOOL useUdp = FALSE;
  2432. DWORD i;
  2433. lpTransportKeyName; // Avoid compiler warnings.
  2434. //
  2435. // Make sure that the caller cares about TCP and/or UDP.
  2436. //
  2437. if ( ARGUMENT_PRESENT( lpiProtocols ) ) {
  2438. for ( i = 0; lpiProtocols[i] != 0; i++ ) {
  2439. if ( lpiProtocols[i] == IPPROTO_TCP ) {
  2440. useTcp = TRUE;
  2441. }
  2442. if ( lpiProtocols[i] == IPPROTO_UDP ) {
  2443. useUdp = TRUE;
  2444. }
  2445. }
  2446. } else {
  2447. useTcp = TRUE;
  2448. useUdp = TRUE;
  2449. }
  2450. if ( !useTcp && !useUdp ) {
  2451. *lpdwBufferLength = 0;
  2452. return 0;
  2453. }
  2454. //
  2455. // Make sure that the caller has specified a sufficiently large
  2456. // buffer.
  2457. //
  2458. bytesRequired = (DWORD)((sizeof(PROTOCOL_INFO) * 2) +
  2459. ( (wcslen( TCP_NAME ) + 1) * sizeof(WCHAR)) +
  2460. ( (wcslen( UDP_NAME ) + 1) * sizeof(WCHAR)));
  2461. if ( bytesRequired > *lpdwBufferLength ) {
  2462. *lpdwBufferLength = bytesRequired;
  2463. return -1;
  2464. }
  2465. //
  2466. // Fill in TCP info, if requested.
  2467. //
  2468. if ( useTcp ) {
  2469. tcpProtocolInfo = lpProtocolBuffer;
  2470. tcpProtocolInfo->dwServiceFlags = XP_GUARANTEED_DELIVERY |
  2471. XP_GUARANTEED_ORDER |
  2472. XP_GRACEFUL_CLOSE |
  2473. XP_EXPEDITED_DATA |
  2474. XP_FRAGMENTATION;
  2475. tcpProtocolInfo->iAddressFamily = AF_INET;
  2476. tcpProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_IN);
  2477. tcpProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_IN);
  2478. tcpProtocolInfo->iSocketType = SOCK_STREAM;
  2479. tcpProtocolInfo->iProtocol = IPPROTO_TCP;
  2480. tcpProtocolInfo->dwMessageSize = 0;
  2481. tcpProtocolInfo->lpProtocol = (LPWSTR)
  2482. ( (PBYTE)lpProtocolBuffer + *lpdwBufferLength -
  2483. ( (wcslen( TCP_NAME ) + 1) * sizeof(WCHAR) ) );
  2484. wcscpy( tcpProtocolInfo->lpProtocol, TCP_NAME );
  2485. udpProtocolInfo = tcpProtocolInfo + 1;
  2486. udpProtocolInfo->lpProtocol = (LPWSTR)
  2487. ( (PBYTE)tcpProtocolInfo->lpProtocol -
  2488. ( (wcslen( UDP_NAME ) + 1) * sizeof(WCHAR) ) );
  2489. } else {
  2490. udpProtocolInfo = lpProtocolBuffer;
  2491. udpProtocolInfo->lpProtocol = (LPWSTR)
  2492. ( (PBYTE)lpProtocolBuffer + *lpdwBufferLength -
  2493. ( (wcslen( UDP_NAME ) + 1) * sizeof(WCHAR) ) );
  2494. }
  2495. //
  2496. // Fill in UDP info, if requested.
  2497. //
  2498. if ( useUdp ) {
  2499. udpProtocolInfo->dwServiceFlags = XP_CONNECTIONLESS |
  2500. XP_MESSAGE_ORIENTED |
  2501. XP_SUPPORTS_BROADCAST |
  2502. XP_SUPPORTS_MULTICAST |
  2503. XP_FRAGMENTATION;
  2504. udpProtocolInfo->iAddressFamily = AF_INET;
  2505. udpProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_IN);
  2506. udpProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_IN);
  2507. udpProtocolInfo->iSocketType = SOCK_DGRAM;
  2508. udpProtocolInfo->iProtocol = IPPROTO_UDP;
  2509. udpProtocolInfo->dwMessageSize = UDP_MESSAGE_SIZE;
  2510. wcscpy( udpProtocolInfo->lpProtocol, UDP_NAME );
  2511. }
  2512. *lpdwBufferLength = bytesRequired;
  2513. return (useTcp && useUdp) ? 2 : 1;
  2514. } // WSHEnumProtocols
  2515. BOOLEAN
  2516. IsTripleInList (
  2517. IN PMAPPING_TRIPLE List,
  2518. IN ULONG ListLength,
  2519. IN INT AddressFamily,
  2520. IN INT SocketType,
  2521. IN INT Protocol
  2522. )
  2523. /*++
  2524. Routine Description:
  2525. Determines whether the specified triple has an exact match in the
  2526. list of triples.
  2527. Arguments:
  2528. List - a list of triples (address family/socket type/protocol) to
  2529. search.
  2530. ListLength - the number of triples in the list.
  2531. AddressFamily - the address family to look for in the list.
  2532. SocketType - the socket type to look for in the list.
  2533. Protocol - the protocol to look for in the list.
  2534. Return Value:
  2535. BOOLEAN - TRUE if the triple was found in the list, false if not.
  2536. --*/
  2537. {
  2538. ULONG i;
  2539. //
  2540. // Walk through the list searching for an exact match.
  2541. //
  2542. for ( i = 0; i < ListLength; i++ ) {
  2543. //
  2544. // If all three elements of the triple match, return indicating
  2545. // that the triple did exist in the list.
  2546. //
  2547. if ( AddressFamily == List[i].AddressFamily &&
  2548. SocketType == List[i].SocketType &&
  2549. ( (Protocol == List[i].Protocol) || (SocketType == SOCK_RAW) )
  2550. ) {
  2551. return TRUE;
  2552. }
  2553. }
  2554. //
  2555. // The triple was not found in the list.
  2556. //
  2557. return FALSE;
  2558. } // IsTripleInList
  2559. INT
  2560. GetTdiInformation (
  2561. IN HANDLE TdiConnectionObjectHandle,
  2562. IN ULONG Entity,
  2563. IN ULONG Class,
  2564. IN ULONG Type,
  2565. IN ULONG Id,
  2566. IN PVOID Value,
  2567. IN ULONG InValueLength,
  2568. IN ULONG OutValueLength
  2569. )
  2570. {
  2571. NTSTATUS status;
  2572. TCP_REQUEST_QUERY_INFORMATION_EX tcpRequest;
  2573. IO_STATUS_BLOCK ioStatusBlock;
  2574. ASSERT(InValueLength <= CONTEXT_SIZE);
  2575. //
  2576. // Initialize the TDI information buffers.
  2577. //
  2578. RtlZeroMemory( &tcpRequest, sizeof(tcpRequest) );
  2579. tcpRequest.ID.toi_entity.tei_entity = Entity;
  2580. tcpRequest.ID.toi_entity.tei_instance = TL_INSTANCE;
  2581. tcpRequest.ID.toi_class = Class;
  2582. tcpRequest.ID.toi_type = Type;
  2583. tcpRequest.ID.toi_id = Id;
  2584. RtlCopyMemory(tcpRequest.Context, Value, InValueLength);
  2585. //
  2586. // Make the actual TDI action call. The Streams TDI mapper will
  2587. // translate this into a TPI option management request for us and
  2588. // give it to TCP/IP.
  2589. //
  2590. status = NtDeviceIoControlFile(
  2591. TdiConnectionObjectHandle,
  2592. NULL,
  2593. NULL, // ApcRoutine
  2594. NULL, // ApcContext
  2595. &ioStatusBlock,
  2596. IOCTL_TCP_QUERY_INFORMATION_EX,
  2597. &tcpRequest,
  2598. sizeof(tcpRequest),
  2599. Value,
  2600. OutValueLength
  2601. );
  2602. if (NT_SUCCESS (status)) {
  2603. return NO_ERROR;
  2604. } else {
  2605. return NtStatusToSocketError (status);
  2606. }
  2607. }
  2608. INT
  2609. SetTdiInformation (
  2610. IN HANDLE TdiConnectionObjectHandle,
  2611. IN ULONG Entity,
  2612. IN ULONG Class,
  2613. IN ULONG Type,
  2614. IN ULONG Id,
  2615. IN PVOID Value,
  2616. IN ULONG ValueLength,
  2617. IN BOOLEAN WaitForCompletion
  2618. )
  2619. /*++
  2620. Routine Description:
  2621. Performs a TDI action to the TCP/IP driver. A TDI action translates
  2622. into a streams T_OPTMGMT_REQ.
  2623. Arguments:
  2624. TdiConnectionObjectHandle - a TDI connection object on which to perform
  2625. the TDI action.
  2626. Entity - value to put in the tei_entity field of the TDIObjectID
  2627. structure.
  2628. Class - value to put in the toi_class field of the TDIObjectID
  2629. structure.
  2630. Type - value to put in the toi_type field of the TDIObjectID
  2631. structure.
  2632. Id - value to put in the toi_id field of the TDIObjectID structure.
  2633. Value - a pointer to a buffer to set as the information.
  2634. ValueLength - the length of the buffer.
  2635. WaitForCompletion - TRUE if we should wait for the TDI action to
  2636. complete, FALSE if we're at APC level and cannot do a wait.
  2637. Return Value:
  2638. INT - NO_ERROR, or a Windows Sockets error code.
  2639. --*/
  2640. {
  2641. NTSTATUS status;
  2642. PTCP_REQUEST_SET_INFORMATION_EX setInfoEx;
  2643. PIO_STATUS_BLOCK ioStatusBlock;
  2644. PVOID completionApc;
  2645. PVOID apcContext;
  2646. CHAR localBuffer[sizeof (IO_STATUS_BLOCK) +
  2647. sizeof (TCP_REQUEST_SET_INFORMATION_EX) +
  2648. 32];
  2649. if (WaitForCompletion || ValueLength>32) {
  2650. //
  2651. // Allocate space to hold the TDI set information buffers and the IO
  2652. // status block. These cannot be stack variables in case we must
  2653. // return before the operation is complete.
  2654. //
  2655. ioStatusBlock = RtlAllocateHeap(
  2656. RtlProcessHeap( ),
  2657. 0,
  2658. sizeof(*ioStatusBlock) + sizeof(*setInfoEx) +
  2659. ValueLength
  2660. );
  2661. if ( ioStatusBlock == NULL ) {
  2662. return WSAENOBUFS;
  2663. }
  2664. }
  2665. else {
  2666. ioStatusBlock = (PIO_STATUS_BLOCK)&localBuffer;
  2667. }
  2668. //
  2669. // Initialize the TDI information buffers.
  2670. //
  2671. setInfoEx = (PTCP_REQUEST_SET_INFORMATION_EX)(ioStatusBlock + 1);
  2672. setInfoEx->ID.toi_entity.tei_entity = Entity;
  2673. setInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
  2674. setInfoEx->ID.toi_class = Class;
  2675. setInfoEx->ID.toi_type = Type;
  2676. setInfoEx->ID.toi_id = Id;
  2677. RtlCopyMemory( setInfoEx->Buffer, Value, ValueLength );
  2678. setInfoEx->BufferSize = ValueLength;
  2679. //
  2680. // If we need to wait for completion of the operation, create an
  2681. // event to wait on. If we can't wait for completion because we
  2682. // are being called at APC level, we'll use an APC routine to
  2683. // free the heap we allocated above.
  2684. //
  2685. if ( WaitForCompletion ) {
  2686. completionApc = NULL;
  2687. apcContext = NULL;
  2688. } else {
  2689. completionApc = CompleteTdiActionApc;
  2690. apcContext = ioStatusBlock;
  2691. }
  2692. //
  2693. // Make the actual TDI action call. The Streams TDI mapper will
  2694. // translate this into a TPI option management request for us and
  2695. // give it to TCP/IP.
  2696. //
  2697. ioStatusBlock->Status = STATUS_PENDING;
  2698. status = NtDeviceIoControlFile(
  2699. TdiConnectionObjectHandle,
  2700. NULL,
  2701. completionApc,
  2702. apcContext,
  2703. ioStatusBlock,
  2704. IOCTL_TCP_WSH_SET_INFORMATION_EX,
  2705. setInfoEx,
  2706. sizeof(*setInfoEx) + ValueLength,
  2707. NULL,
  2708. 0
  2709. );
  2710. //
  2711. // If the call pended and we were supposed to wait for completion,
  2712. // then wait.
  2713. //
  2714. if ( status == STATUS_PENDING && WaitForCompletion ) {
  2715. #if DBG
  2716. INT count=0;
  2717. #endif
  2718. while (ioStatusBlock->Status==STATUS_PENDING) {
  2719. LARGE_INTEGER timeout;
  2720. //
  2721. // Wait one millisecond
  2722. //
  2723. timeout.QuadPart = -1i64*1000i64*10i64;
  2724. NtDelayExecution (FALSE, &timeout);
  2725. #if DBG
  2726. if (count++>10*1000) {
  2727. DbgPrint ("WSHTCPIP: Waiting for TCP/IP IOCTL completion for more than 10 seconds!!!!\n");
  2728. DbgBreakPoint ();
  2729. }
  2730. #endif
  2731. }
  2732. status = ioStatusBlock->Status;
  2733. }
  2734. if ( (ioStatusBlock != (PIO_STATUS_BLOCK)&localBuffer) &&
  2735. (WaitForCompletion || !NT_SUCCESS(status)) ){
  2736. RtlFreeHeap( RtlProcessHeap( ), 0, ioStatusBlock );
  2737. }
  2738. if (NT_SUCCESS (status)) {
  2739. return NO_ERROR;
  2740. }
  2741. else {
  2742. return NtStatusToSocketError (status);
  2743. }
  2744. } // SetTdiInformation
  2745. VOID
  2746. CompleteTdiActionApc (
  2747. IN PVOID ApcContext,
  2748. IN PIO_STATUS_BLOCK IoStatusBlock
  2749. )
  2750. {
  2751. //
  2752. // Just free the heap we allocated to hold the IO status block and
  2753. // the TDI action buffer. There is nothing we can do if the call
  2754. // failed.
  2755. //
  2756. RtlFreeHeap( RtlProcessHeap( ), 0, ApcContext );
  2757. } // CompleteTdiActionApc
  2758. INT
  2759. WINAPI
  2760. WSHJoinLeaf (
  2761. IN PVOID HelperDllSocketContext,
  2762. IN SOCKET SocketHandle,
  2763. IN HANDLE TdiAddressObjectHandle,
  2764. IN HANDLE TdiConnectionObjectHandle,
  2765. IN PVOID LeafHelperDllSocketContext,
  2766. IN SOCKET LeafSocketHandle,
  2767. IN PSOCKADDR Sockaddr,
  2768. IN DWORD SockaddrLength,
  2769. IN LPWSABUF CallerData,
  2770. IN LPWSABUF CalleeData,
  2771. IN LPQOS SocketQOS,
  2772. IN LPQOS GroupQOS,
  2773. IN DWORD Flags
  2774. )
  2775. /*++
  2776. Routine Description:
  2777. Performs the protocol-dependent portion of creating a multicast
  2778. socket.
  2779. Arguments:
  2780. The following four parameters correspond to the socket passed into
  2781. the WSAJoinLeaf() API:
  2782. HelperDllSocketContext - The context pointer returned from
  2783. WSHOpenSocket().
  2784. SocketHandle - The handle of the socket used to establish the
  2785. multicast "session".
  2786. TdiAddressObjectHandle - The TDI address object of the socket, if
  2787. any. If the socket is not yet bound to an address, then
  2788. it does not have a TDI address object and this parameter
  2789. will be NULL.
  2790. TdiConnectionObjectHandle - The TDI connection object of the socket,
  2791. if any. If the socket is not yet connected, then it does not
  2792. have a TDI connection object and this parameter will be NULL.
  2793. The next two parameters correspond to the newly created socket that
  2794. identifies the multicast "session":
  2795. LeafHelperDllSocketContext - The context pointer returned from
  2796. WSHOpenSocket().
  2797. LeafSocketHandle - The handle of the socket that identifies the
  2798. multicast "session".
  2799. Sockaddr - The name of the peer to which the socket is to be joined.
  2800. SockaddrLength - The length of Sockaddr.
  2801. CallerData - Pointer to user data to be transferred to the peer
  2802. during multipoint session establishment.
  2803. CalleeData - Pointer to user data to be transferred back from
  2804. the peer during multipoint session establishment.
  2805. SocketQOS - Pointer to the flowspecs for SocketHandle, one in each
  2806. direction.
  2807. GroupQOS - Pointer to the flowspecs for the socket group, if any.
  2808. Flags - Flags to indicate if the socket is acting as sender,
  2809. receiver, or both.
  2810. Return Value:
  2811. INT - 0 if successful, a WinSock error code if not.
  2812. --*/
  2813. {
  2814. struct ip_mreq req;
  2815. INT err;
  2816. BOOL bSet_IP_MULTICAST_IF = FALSE;
  2817. PWSHTCPIP_SOCKET_CONTEXT context;
  2818. //
  2819. // Note: at this time we only support non-rooted control schemes,
  2820. // and therefore no leaf socket is created
  2821. //
  2822. //
  2823. // Quick sanity checks.
  2824. //
  2825. if( HelperDllSocketContext == NULL ||
  2826. SocketHandle == INVALID_SOCKET ||
  2827. TdiAddressObjectHandle == NULL ||
  2828. LeafHelperDllSocketContext != NULL ||
  2829. LeafSocketHandle != INVALID_SOCKET ||
  2830. Sockaddr == NULL ||
  2831. SockaddrLength < sizeof(SOCKADDR_IN) ||
  2832. Sockaddr->sa_family != AF_INET ||
  2833. ( CallerData != NULL && CallerData->len > 0 ) ||
  2834. ( CalleeData != NULL && CalleeData->len > 0 ) ||
  2835. SocketQOS != NULL ||
  2836. GroupQOS != NULL ) {
  2837. return WSAEINVAL;
  2838. }
  2839. context = HelperDllSocketContext;
  2840. //
  2841. // The multicast group to join...
  2842. //
  2843. req.imr_multiaddr = ((LPSOCKADDR_IN)Sockaddr)->sin_addr;
  2844. //
  2845. // Now figure out the local interface. Note that the local interface
  2846. // specified in IP_ADD_MEMBERSHIP applies to that on which you wish
  2847. // to receive datagrams, while the local interface specified in
  2848. // IP_MULTICAST_IF applies to that from which to send multicast
  2849. // packets. If there is >1 local interface then we want to be
  2850. // consistent regarding the send/recv interfaces.
  2851. //
  2852. if (context->MulticastInterface == DEFAULT_MULTICAST_INTERFACE) {
  2853. TDI_REQUEST_QUERY_INFORMATION query;
  2854. char tdiAddressInfo[FIELD_OFFSET (TDI_ADDRESS_INFO, Address)
  2855. + sizeof (TA_IP_ADDRESS)];
  2856. NTSTATUS status;
  2857. IO_STATUS_BLOCK ioStatusBlock;
  2858. //
  2859. // App hasn't set IP_MULTICAST_IF, so retrieve the bound
  2860. // address and use that for the send & recv interfaces
  2861. //
  2862. //
  2863. RtlZeroMemory (&query, sizeof (query));
  2864. query.QueryType = TDI_QUERY_ADDRESS_INFO;
  2865. status = NtDeviceIoControlFile(
  2866. TdiAddressObjectHandle,
  2867. NULL,
  2868. NULL,
  2869. NULL,
  2870. &ioStatusBlock,
  2871. IOCTL_TDI_QUERY_INFORMATION,
  2872. &query,
  2873. sizeof (query),
  2874. tdiAddressInfo,
  2875. sizeof(tdiAddressInfo)
  2876. );
  2877. if( NT_SUCCESS(status) ) {
  2878. PTA_IP_ADDRESS pIpAddress =
  2879. (PTA_IP_ADDRESS)(tdiAddressInfo+FIELD_OFFSET (TDI_ADDRESS_INFO, Address));
  2880. req.imr_interface.s_addr = pIpAddress->Address[0].Address[0].in_addr;
  2881. if (req.imr_interface.s_addr != DEFAULT_MULTICAST_INTERFACE) {
  2882. bSet_IP_MULTICAST_IF = TRUE;
  2883. context->MulticastInterface = req.imr_interface.s_addr;
  2884. }
  2885. } else {
  2886. req.imr_interface.s_addr = DEFAULT_MULTICAST_INTERFACE;
  2887. }
  2888. } else {
  2889. req.imr_interface.s_addr = context->MulticastInterface;
  2890. }
  2891. //
  2892. // If the Flags param indicates that caller is a sender only,
  2893. // then there's no point in actually joining the group (anyone
  2894. // can send to a multicast group, but it's only members of the
  2895. // group who recv the packets). So, just check to see if it
  2896. // is necessary to set the IP_MULTICAST_IF to remain consistent
  2897. // ith the bound address.
  2898. //
  2899. // Otherwise, caller is a receiver (possibly a sender too), so
  2900. // we really do want to join the group.
  2901. //
  2902. if (Flags == JL_SENDER_ONLY) {
  2903. if (bSet_IP_MULTICAST_IF) {
  2904. WSHSetSocketInformation (
  2905. HelperDllSocketContext,
  2906. SocketHandle,
  2907. TdiAddressObjectHandle,
  2908. TdiConnectionObjectHandle,
  2909. IPPROTO_IP,
  2910. IP_MULTICAST_IF,
  2911. (char *) &req.imr_interface.s_addr,
  2912. sizeof (req.imr_interface.s_addr)
  2913. );
  2914. }
  2915. err = NO_ERROR;
  2916. } else {
  2917. err = SetTdiInformation(
  2918. TdiAddressObjectHandle,
  2919. CL_TL_ENTITY,
  2920. INFO_CLASS_PROTOCOL,
  2921. INFO_TYPE_ADDRESS_OBJECT,
  2922. AO_OPTION_ADD_MCAST,
  2923. &req,
  2924. sizeof(req),
  2925. TRUE
  2926. );
  2927. if( err == NO_ERROR ) {
  2928. //
  2929. // Record this fact in the leaf socket so we can drop membership
  2930. // when the leaf socket is closed.
  2931. //
  2932. context->MultipointLeaf = TRUE;
  2933. context->MultipointTarget = req.imr_multiaddr;
  2934. //
  2935. // Stay consistent, i.e. send interface should match recv interface
  2936. //
  2937. if (bSet_IP_MULTICAST_IF && (Flags != JL_RECEIVER_ONLY)) {
  2938. WSHSetSocketInformation (
  2939. HelperDllSocketContext,
  2940. SocketHandle,
  2941. TdiAddressObjectHandle,
  2942. TdiConnectionObjectHandle,
  2943. IPPROTO_IP,
  2944. IP_MULTICAST_IF,
  2945. (char *) &req.imr_interface.s_addr,
  2946. sizeof (req.imr_interface.s_addr)
  2947. );
  2948. }
  2949. }
  2950. }
  2951. return err;
  2952. } // WSHJoinLeaf
  2953. INT
  2954. WINAPI
  2955. WSHGetBroadcastSockaddr (
  2956. IN PVOID HelperDllSocketContext,
  2957. OUT PSOCKADDR Sockaddr,
  2958. OUT PINT SockaddrLength
  2959. )
  2960. /*++
  2961. Routine Description:
  2962. This routine returns a broadcast socket address. A broadcast address
  2963. may be used as a destination for the sendto() API to send a datagram
  2964. to all interested clients.
  2965. Arguments:
  2966. HelperDllSocketContext - the context pointer returned from
  2967. WSHOpenSocket() for the socket for which we need a broadcast
  2968. address.
  2969. Sockaddr - points to a buffer which will receive the broadcast socket
  2970. address.
  2971. SockaddrLength - receives the length of the broadcast sockaddr.
  2972. Return Value:
  2973. INT - a winsock error code indicating the status of the operation, or
  2974. NO_ERROR if the operation succeeded.
  2975. --*/
  2976. {
  2977. LPSOCKADDR_IN addr;
  2978. if( *SockaddrLength < sizeof(SOCKADDR_IN) || (Sockaddr == NULL) ) {
  2979. return WSAEFAULT;
  2980. }
  2981. *SockaddrLength = sizeof(SOCKADDR_IN);
  2982. //
  2983. // Build the broadcast address.
  2984. //
  2985. addr = (LPSOCKADDR_IN)Sockaddr;
  2986. RtlZeroMemory(
  2987. addr,
  2988. sizeof(*addr)
  2989. );
  2990. addr->sin_family = AF_INET;
  2991. ASSERT (htonl(INADDR_BROADCAST)==INADDR_BROADCAST);
  2992. addr->sin_addr.s_addr = INADDR_BROADCAST;
  2993. return NO_ERROR;
  2994. } // WSAGetBroadcastSockaddr
  2995. INT
  2996. WINAPI
  2997. WSHGetWSAProtocolInfo (
  2998. IN LPWSTR ProviderName,
  2999. OUT LPWSAPROTOCOL_INFOW * ProtocolInfo,
  3000. OUT LPDWORD ProtocolInfoEntries
  3001. )
  3002. /*++
  3003. Routine Description:
  3004. Retrieves a pointer to the WSAPROTOCOL_INFOW structure(s) describing
  3005. the protocol(s) supported by this helper.
  3006. Arguments:
  3007. ProviderName - Contains the name of the provider, such as "TcpIp".
  3008. ProtocolInfo - Receives a pointer to the WSAPROTOCOL_INFOW array.
  3009. ProtocolInfoEntries - Receives the number of entries in the array.
  3010. Return Value:
  3011. INT - 0 if successful, WinSock error code if not.
  3012. --*/
  3013. {
  3014. if( ProviderName == NULL ||
  3015. ProtocolInfo == NULL ||
  3016. ProtocolInfoEntries == NULL ) {
  3017. return WSAEFAULT;
  3018. }
  3019. if( _wcsicmp( ProviderName, L"TcpIp" ) == 0 ) {
  3020. *ProtocolInfo = Winsock2Protocols;
  3021. *ProtocolInfoEntries = NUM_WINSOCK2_PROTOCOLS;
  3022. return NO_ERROR;
  3023. }
  3024. return WSAEINVAL;
  3025. } // WSHGetWSAProtocolInfo
  3026. INT
  3027. WINAPI
  3028. WSHAddressToString (
  3029. IN LPSOCKADDR Address,
  3030. IN INT AddressLength,
  3031. IN LPWSAPROTOCOL_INFOW ProtocolInfo,
  3032. OUT LPWSTR AddressString,
  3033. IN OUT LPDWORD AddressStringLength
  3034. )
  3035. /*++
  3036. Routine Description:
  3037. Converts a SOCKADDR to a human-readable form.
  3038. Arguments:
  3039. Address - The SOCKADDR to convert.
  3040. AddressLength - The length of Address.
  3041. ProtocolInfo - The WSAPROTOCOL_INFOW for a particular provider.
  3042. AddressString - Receives the formatted address string.
  3043. AddressStringLength - On input, contains the length of AddressString.
  3044. On output, contains the number of characters actually written
  3045. to AddressString.
  3046. Return Value:
  3047. INT - 0 if successful, WinSock error code if not.
  3048. --*/
  3049. {
  3050. LPSOCKADDR_IN addr;
  3051. INT err = NO_ERROR;
  3052. NTSTATUS Status;
  3053. //
  3054. // Quick sanity checks.
  3055. //
  3056. if( AddressLength < sizeof(SOCKADDR_IN)) {
  3057. return WSAEFAULT;
  3058. }
  3059. __try {
  3060. addr = (LPSOCKADDR_IN)Address;
  3061. if (addr->sin_family != AF_INET) {
  3062. return WSAEFAULT;
  3063. }
  3064. //
  3065. // Now calling rtl functions to do the address conversion
  3066. //
  3067. Status = RtlIpv4AddressToStringExW(&addr->sin_addr,
  3068. addr->sin_port,
  3069. AddressString,
  3070. AddressStringLength
  3071. );
  3072. if (!NT_SUCCESS(Status)) {
  3073. err = WSAEFAULT;
  3074. }
  3075. }
  3076. __except (EXCEPTION_EXECUTE_HANDLER) {
  3077. err = WSAEFAULT;
  3078. }
  3079. return err;
  3080. } // WSHAddressToString
  3081. INT
  3082. WINAPI
  3083. WSHStringToAddress (
  3084. IN LPWSTR AddressString,
  3085. IN DWORD AddressFamily,
  3086. IN LPWSAPROTOCOL_INFOW ProtocolInfo,
  3087. OUT LPSOCKADDR Address,
  3088. IN OUT LPINT AddressLength
  3089. )
  3090. /*++
  3091. Routine Description:
  3092. Fills in a SOCKADDR structure by parsing a human-readable string.
  3093. Arguments:
  3094. AddressString - Points to the zero-terminated human-readable string.
  3095. AddressFamily - The address family to which the string belongs.
  3096. ProtocolInfo - The WSAPROTOCOL_INFOW for a particular provider.
  3097. Address - Receives the SOCKADDR structure.
  3098. AddressLength - On input, contains the length of Address. On output,
  3099. contains the number of bytes actually written to Address.
  3100. Return Value:
  3101. INT - 0 if successful, WinSock error code if not.
  3102. --*/
  3103. {
  3104. LPWSTR terminator;
  3105. ULONG ipAddress;
  3106. USHORT port;
  3107. LPSOCKADDR_IN addr;
  3108. NTSTATUS Status;
  3109. __try {
  3110. if (*AddressLength < sizeof(SOCKADDR_IN) ) {
  3111. *AddressLength = sizeof(SOCKADDR_IN);
  3112. return WSAEFAULT;
  3113. }
  3114. if (AddressFamily != AF_INET) {
  3115. return WSAEINVAL;
  3116. }
  3117. addr = (LPSOCKADDR_IN)Address;
  3118. RtlZeroMemory(addr, sizeof(SOCKADDR_IN));
  3119. //
  3120. // Now calling Rtl routine to do the address conversion
  3121. //
  3122. Status = RtlIpv4StringToAddressExW(AddressString,
  3123. FALSE,
  3124. &addr->sin_addr,
  3125. &addr->sin_port
  3126. );
  3127. if (!NT_SUCCESS(Status)) {
  3128. return WSAEINVAL;
  3129. }
  3130. }
  3131. __except (EXCEPTION_EXECUTE_HANDLER) {
  3132. return WSAEFAULT;
  3133. }
  3134. *AddressLength = sizeof(SOCKADDR_IN);
  3135. addr->sin_family = AF_INET;
  3136. return NO_ERROR;
  3137. } // WSHStringToAddress
  3138. INT
  3139. WINAPI
  3140. WSHGetProviderGuid (
  3141. IN LPWSTR ProviderName,
  3142. OUT LPGUID ProviderGuid
  3143. )
  3144. /*++
  3145. Routine Description:
  3146. Returns the GUID identifying the protocols supported by this helper.
  3147. Arguments:
  3148. ProviderName - Contains the name of the provider, such as "TcpIp".
  3149. ProviderGuid - Points to a buffer that receives the provider's GUID.
  3150. Return Value:
  3151. INT - 0 if successful, WinSock error code if not.
  3152. --*/
  3153. {
  3154. if( ProviderName == NULL ||
  3155. ProviderGuid == NULL ) {
  3156. return WSAEFAULT;
  3157. }
  3158. if( _wcsicmp( ProviderName, L"TcpIp" ) == 0 ) {
  3159. RtlCopyMemory(
  3160. ProviderGuid,
  3161. &TcpipProviderGuid,
  3162. sizeof(GUID)
  3163. );
  3164. return NO_ERROR;
  3165. }
  3166. return WSAEINVAL;
  3167. } // WSHGetProviderGuid
  3168. INT
  3169. WINAPI
  3170. WSHIoctl (
  3171. IN PVOID HelperDllSocketContext,
  3172. IN SOCKET SocketHandle,
  3173. IN HANDLE TdiAddressObjectHandle,
  3174. IN HANDLE TdiConnectionObjectHandle,
  3175. IN DWORD IoControlCode,
  3176. IN LPVOID InputBuffer,
  3177. IN DWORD InputBufferLength,
  3178. IN LPVOID OutputBuffer,
  3179. IN DWORD OutputBufferLength,
  3180. OUT LPDWORD NumberOfBytesReturned,
  3181. IN LPWSAOVERLAPPED Overlapped,
  3182. IN LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine,
  3183. OUT LPBOOL NeedsCompletion
  3184. )
  3185. /*++
  3186. Routine Description:
  3187. Performs queries & controls on the socket. This is basically an
  3188. "escape hatch" for IOCTLs not supported by MSAFD.DLL. Any unknown
  3189. IOCTLs are routed to the socket's helper DLL for protocol-specific
  3190. processing.
  3191. Arguments:
  3192. HelperDllSocketContext - the context pointer returned from
  3193. WSHOpenSocket().
  3194. SocketHandle - the handle of the socket for which we're controlling.
  3195. TdiAddressObjectHandle - the TDI address object of the socket, if
  3196. any. If the socket is not yet bound to an address, then
  3197. it does not have a TDI address object and this parameter
  3198. will be NULL.
  3199. TdiConnectionObjectHandle - the TDI connection object of the socket,
  3200. if any. If the socket is not yet connected, then it does not
  3201. have a TDI connection object and this parameter will be NULL.
  3202. IoControlCode - Control code of the operation to perform.
  3203. InputBuffer - Address of the input buffer.
  3204. InputBufferLength - The length of InputBuffer.
  3205. OutputBuffer - Address of the output buffer.
  3206. OutputBufferLength - The length of OutputBuffer.
  3207. NumberOfBytesReturned - Receives the number of bytes actually written
  3208. to the output buffer.
  3209. Overlapped - Pointer to a WSAOVERLAPPED structure for overlapped
  3210. operations.
  3211. CompletionRoutine - Pointer to a completion routine to call when
  3212. the operation is completed.
  3213. NeedsCompletion - WSAIoctl() can be overlapped, with all the gory
  3214. details that involves, such as setting events, queuing completion
  3215. routines, and posting to IO completion ports. Since the majority
  3216. of the IOCTL codes can be completed quickly "in-line", MSAFD.DLL
  3217. can optionally perform the overlapped completion of the operation.
  3218. Setting *NeedsCompletion to TRUE (the default) causes MSAFD.DLL
  3219. to handle all of the IO completion details iff this is an
  3220. overlapped operation on an overlapped socket.
  3221. Setting *NeedsCompletion to FALSE tells MSAFD.DLL to take no
  3222. further action because the helper DLL will perform any necessary
  3223. IO completion.
  3224. Note that if a helper performs its own IO completion, the helper
  3225. is responsible for maintaining the "overlapped" mode of the socket
  3226. at socket creation time and NOT performing overlapped IO completion
  3227. on non-overlapped sockets.
  3228. Return Value:
  3229. INT - 0 if successful, WinSock error code if not.
  3230. --*/
  3231. {
  3232. INT err;
  3233. NTSTATUS status;
  3234. PWSHTCPIP_SOCKET_CONTEXT context;
  3235. //
  3236. // Quick sanity checks.
  3237. //
  3238. if( HelperDllSocketContext == NULL ||
  3239. SocketHandle == INVALID_SOCKET ||
  3240. NumberOfBytesReturned == NULL ||
  3241. NeedsCompletion == NULL ) {
  3242. return WSAEINVAL;
  3243. }
  3244. *NeedsCompletion = TRUE;
  3245. context = (PWSHTCPIP_SOCKET_CONTEXT) HelperDllSocketContext;
  3246. switch( IoControlCode ) {
  3247. case SIO_MULTIPOINT_LOOPBACK :
  3248. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  3249. err = WSAENOPROTOOPT;
  3250. break;
  3251. }
  3252. err = WSHSetSocketInformation(
  3253. HelperDllSocketContext,
  3254. SocketHandle,
  3255. TdiAddressObjectHandle,
  3256. TdiConnectionObjectHandle,
  3257. IPPROTO_IP,
  3258. IP_MULTICAST_LOOP,
  3259. (PCHAR)InputBuffer,
  3260. (INT)InputBufferLength
  3261. );
  3262. break;
  3263. case SIO_MULTICAST_SCOPE :
  3264. err = WSHSetSocketInformation(
  3265. HelperDllSocketContext,
  3266. SocketHandle,
  3267. TdiAddressObjectHandle,
  3268. TdiConnectionObjectHandle,
  3269. IPPROTO_IP,
  3270. IP_MULTICAST_TTL,
  3271. (PCHAR)InputBuffer,
  3272. (INT)InputBufferLength
  3273. );
  3274. break;
  3275. case SIO_GET_MULTICAST_FILTER :
  3276. if ( OutputBufferLength < IP_MSFILTER_SIZE(0) ||
  3277. (OutputBuffer == NULL) ) {
  3278. err = WSAEFAULT;
  3279. break;
  3280. }
  3281. if ( TdiAddressObjectHandle == NULL ) {
  3282. err = WSAEINVAL;
  3283. break;
  3284. }
  3285. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  3286. err = WSAENOPROTOOPT;
  3287. break;
  3288. }
  3289. err = GetTdiInformation(
  3290. TdiAddressObjectHandle,
  3291. CL_TL_ENTITY,
  3292. INFO_CLASS_PROTOCOL,
  3293. INFO_TYPE_ADDRESS_OBJECT,
  3294. AO_OPTION_MCAST_FILTER,
  3295. OutputBuffer,
  3296. FIELD_OFFSET(UDPMCastFilter, umf_fmode),
  3297. OutputBufferLength
  3298. );
  3299. break;
  3300. case SIO_SET_MULTICAST_FILTER :
  3301. {
  3302. PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
  3303. //
  3304. // This option is only valid for datagram sockets.
  3305. //
  3306. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  3307. err = WSAENOPROTOOPT;
  3308. break;
  3309. }
  3310. //
  3311. // Make sure that the option buffer is large enough.
  3312. //
  3313. if ( InputBufferLength < IP_MSFILTER_SIZE(0) ) {
  3314. err = WSAEFAULT;
  3315. break;
  3316. }
  3317. //
  3318. // If we have a TDI address object, set this option to
  3319. // the address object. If we don't have a TDI address
  3320. // object then we'll have to wait until after the socket
  3321. // is bound.
  3322. //
  3323. if ( TdiAddressObjectHandle != NULL ) {
  3324. err = SetTdiInformation(
  3325. TdiAddressObjectHandle,
  3326. CL_TL_ENTITY,
  3327. INFO_CLASS_PROTOCOL,
  3328. INFO_TYPE_ADDRESS_OBJECT,
  3329. AO_OPTION_MCAST_FILTER,
  3330. InputBuffer,
  3331. InputBufferLength,
  3332. TRUE
  3333. );
  3334. if ( err != NO_ERROR ) {
  3335. break;
  3336. }
  3337. }
  3338. err = NO_ERROR;
  3339. break;
  3340. }
  3341. case SIO_GET_INTERFACE_LIST :
  3342. if ( OutputBuffer == NULL ) {
  3343. err = WSAEFAULT;
  3344. break;
  3345. }
  3346. status = GetTcpipInterfaceList(
  3347. OutputBuffer,
  3348. OutputBufferLength,
  3349. NumberOfBytesReturned
  3350. );
  3351. if( NT_SUCCESS(status) ) {
  3352. err = NO_ERROR;
  3353. } else {
  3354. err = NtStatusToSocketError (status);
  3355. }
  3356. break;
  3357. case SIO_RCVALL:
  3358. //
  3359. // This option is only valid for raw sockets.
  3360. //
  3361. if (((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->SocketType != SOCK_RAW) {
  3362. return WSAENOPROTOOPT;
  3363. }
  3364. if ( InputBufferLength != sizeof(uint)) {
  3365. return WSAEINVAL;
  3366. }
  3367. if ( TdiAddressObjectHandle != NULL ) {
  3368. err = SetTdiInformation(
  3369. TdiAddressObjectHandle,
  3370. CL_TL_ENTITY,
  3371. INFO_CLASS_PROTOCOL,
  3372. INFO_TYPE_ADDRESS_OBJECT,
  3373. AO_OPTION_RCVALL,
  3374. InputBuffer,
  3375. InputBufferLength,
  3376. TRUE
  3377. );
  3378. if ( err != NO_ERROR ) {
  3379. return err;
  3380. }
  3381. } else {
  3382. return WSAEINVAL;
  3383. }
  3384. return NO_ERROR;
  3385. case SIO_RCVALL_MCAST:
  3386. //
  3387. // This option is only valid for raw sockets.
  3388. //
  3389. if (((PWSHTCPIP_SOCKET_CONTEXT) HelperDllSocketContext)->SocketType != SOCK_RAW) {
  3390. return WSAENOPROTOOPT;
  3391. }
  3392. if ( InputBufferLength != sizeof(uint)) {
  3393. return WSAEINVAL;
  3394. }
  3395. if ( TdiAddressObjectHandle != NULL ) {
  3396. err = SetTdiInformation(
  3397. TdiAddressObjectHandle,
  3398. CL_TL_ENTITY,
  3399. INFO_CLASS_PROTOCOL,
  3400. INFO_TYPE_ADDRESS_OBJECT,
  3401. AO_OPTION_RCVALL_MCAST,
  3402. InputBuffer,
  3403. InputBufferLength,
  3404. TRUE
  3405. );
  3406. if ( err != NO_ERROR ) {
  3407. return err;
  3408. }
  3409. } else {
  3410. return WSAEINVAL;
  3411. }
  3412. return NO_ERROR;
  3413. case SIO_RCVALL_IGMPMCAST:
  3414. //
  3415. // This option is only valid for raw sockets.
  3416. //
  3417. if (((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->SocketType != SOCK_RAW) {
  3418. return WSAENOPROTOOPT;
  3419. }
  3420. if ( InputBufferLength != sizeof(uint)) {
  3421. return WSAEINVAL;
  3422. }
  3423. if ( TdiAddressObjectHandle != NULL ) {
  3424. err = SetTdiInformation(
  3425. TdiAddressObjectHandle,
  3426. CL_TL_ENTITY,
  3427. INFO_CLASS_PROTOCOL,
  3428. INFO_TYPE_ADDRESS_OBJECT,
  3429. AO_OPTION_RCVALL_IGMPMCAST,
  3430. InputBuffer,
  3431. InputBufferLength,
  3432. TRUE
  3433. );
  3434. if ( err != NO_ERROR ) {
  3435. return err;
  3436. }
  3437. } else {
  3438. return WSAEINVAL;
  3439. }
  3440. return NO_ERROR;
  3441. case SIO_ABSORB_RTRALERT:
  3442. //
  3443. // This option is only valid for raw sockets.
  3444. //
  3445. if (((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->SocketType != SOCK_RAW) {
  3446. return WSAENOPROTOOPT;
  3447. }
  3448. if ( InputBufferLength != sizeof(uint)) {
  3449. return WSAEINVAL;
  3450. }
  3451. if ( TdiAddressObjectHandle != NULL ) {
  3452. err = SetTdiInformation(
  3453. TdiAddressObjectHandle,
  3454. CL_TL_ENTITY,
  3455. INFO_CLASS_PROTOCOL,
  3456. INFO_TYPE_ADDRESS_OBJECT,
  3457. AO_OPTION_ABSORB_RTRALERT,
  3458. InputBuffer,
  3459. InputBufferLength,
  3460. TRUE
  3461. );
  3462. if ( err != NO_ERROR ) {
  3463. return err;
  3464. }
  3465. } else {
  3466. return WSAEINVAL;
  3467. }
  3468. return NO_ERROR;
  3469. case SIO_UCAST_IF:
  3470. {
  3471. uint OptionValue;
  3472. //
  3473. // This option is only valid for raw sockets.
  3474. //
  3475. if (((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->SocketType != SOCK_RAW) {
  3476. return WSAENOPROTOOPT;
  3477. }
  3478. // this option is valid only if hdr include option is set
  3479. if ( !(((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->HdrIncludeSet && ((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->HdrInclude) ) {
  3480. return WSAEINVAL;
  3481. }
  3482. if ( InputBufferLength != sizeof(uint)) {
  3483. return WSAEINVAL;
  3484. }
  3485. if ( TdiAddressObjectHandle != NULL ) {
  3486. err = SetTdiInformation(
  3487. TdiAddressObjectHandle,
  3488. CL_TL_ENTITY,
  3489. INFO_CLASS_PROTOCOL,
  3490. INFO_TYPE_ADDRESS_OBJECT,
  3491. AO_OPTION_IP_UCASTIF,
  3492. InputBuffer,
  3493. InputBufferLength,
  3494. TRUE
  3495. );
  3496. if ( err != NO_ERROR ) {
  3497. return err;
  3498. }
  3499. }
  3500. OptionValue = *((uint UNALIGNED *)InputBuffer);
  3501. ((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->UcastIf = OptionValue ? TRUE : FALSE;
  3502. return NO_ERROR;
  3503. }
  3504. case SIO_LIMIT_BROADCASTS:
  3505. {
  3506. uint OptionValue;
  3507. //
  3508. // This option is only valid for UDP sockets.
  3509. //
  3510. if ( !IS_DGRAM_SOCK(
  3511. ((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->SocketType
  3512. )) {
  3513. return WSAENOPROTOOPT;
  3514. }
  3515. if ( InputBufferLength != sizeof(uint)) {
  3516. return WSAEINVAL;
  3517. }
  3518. if ( TdiAddressObjectHandle != NULL ) {
  3519. err = SetTdiInformation(
  3520. TdiAddressObjectHandle,
  3521. CL_TL_ENTITY,
  3522. INFO_CLASS_PROTOCOL,
  3523. INFO_TYPE_ADDRESS_OBJECT,
  3524. AO_OPTION_LIMIT_BCASTS,
  3525. InputBuffer,
  3526. InputBufferLength,
  3527. TRUE
  3528. );
  3529. if ( err != NO_ERROR ) {
  3530. return err;
  3531. }
  3532. }
  3533. OptionValue = *((uint UNALIGNED *)InputBuffer);
  3534. ((PWSHTCPIP_SOCKET_CONTEXT)
  3535. HelperDllSocketContext)->LimitBroadcasts =
  3536. OptionValue ? TRUE : FALSE;
  3537. return NO_ERROR;
  3538. }
  3539. case SIO_INDEX_BIND:
  3540. //
  3541. // This option is only valid for raw sockets.
  3542. //
  3543. if (((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->SocketType != SOCK_RAW) {
  3544. return WSAENOPROTOOPT;
  3545. }
  3546. if ( TdiAddressObjectHandle != NULL ) {
  3547. err = SetTdiInformation(
  3548. TdiAddressObjectHandle,
  3549. CL_TL_ENTITY,
  3550. INFO_CLASS_PROTOCOL,
  3551. INFO_TYPE_ADDRESS_OBJECT,
  3552. AO_OPTION_INDEX_BIND,
  3553. InputBuffer,
  3554. InputBufferLength,
  3555. TRUE
  3556. );
  3557. if ( err != NO_ERROR ) {
  3558. return err;
  3559. }
  3560. } else {
  3561. return WSAEINVAL;
  3562. }
  3563. return NO_ERROR;
  3564. case SIO_INDEX_MCASTIF:
  3565. //
  3566. // This option is only valid for raw sockets.
  3567. //
  3568. if (((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->SocketType != SOCK_RAW) {
  3569. return WSAENOPROTOOPT;
  3570. }
  3571. if ( TdiAddressObjectHandle != NULL ) {
  3572. err = SetTdiInformation(
  3573. TdiAddressObjectHandle,
  3574. CL_TL_ENTITY,
  3575. INFO_CLASS_PROTOCOL,
  3576. INFO_TYPE_ADDRESS_OBJECT,
  3577. AO_OPTION_INDEX_MCASTIF,
  3578. InputBuffer,
  3579. InputBufferLength,
  3580. TRUE
  3581. );
  3582. if ( err != NO_ERROR ) {
  3583. return err;
  3584. }
  3585. } else {
  3586. return WSAEINVAL;
  3587. }
  3588. return NO_ERROR;
  3589. case SIO_INDEX_ADD_MCAST:
  3590. //
  3591. // This option is only valid for raw sockets.
  3592. //
  3593. if (((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->SocketType != SOCK_RAW) {
  3594. return WSAENOPROTOOPT;
  3595. }
  3596. if ( TdiAddressObjectHandle != NULL ) {
  3597. err = SetTdiInformation(
  3598. TdiAddressObjectHandle,
  3599. CL_TL_ENTITY,
  3600. INFO_CLASS_PROTOCOL,
  3601. INFO_TYPE_ADDRESS_OBJECT,
  3602. AO_OPTION_INDEX_ADD_MCAST,
  3603. InputBuffer,
  3604. InputBufferLength,
  3605. TRUE
  3606. );
  3607. if ( err != NO_ERROR ) {
  3608. return err;
  3609. }
  3610. } else {
  3611. return WSAEINVAL;
  3612. }
  3613. return NO_ERROR;
  3614. case SIO_INDEX_DEL_MCAST:
  3615. //
  3616. // This option is only valid for raw sockets.
  3617. //
  3618. if (((PWSHTCPIP_SOCKET_CONTEXT)HelperDllSocketContext)->SocketType != SOCK_RAW) {
  3619. return WSAENOPROTOOPT;
  3620. }
  3621. if ( TdiAddressObjectHandle != NULL ) {
  3622. err = SetTdiInformation(
  3623. TdiAddressObjectHandle,
  3624. CL_TL_ENTITY,
  3625. INFO_CLASS_PROTOCOL,
  3626. INFO_TYPE_ADDRESS_OBJECT,
  3627. AO_OPTION_INDEX_DEL_MCAST,
  3628. InputBuffer,
  3629. InputBufferLength,
  3630. TRUE
  3631. );
  3632. if ( err != NO_ERROR ) {
  3633. return err;
  3634. }
  3635. } else {
  3636. return WSAEINVAL;
  3637. }
  3638. return NO_ERROR;
  3639. case SIO_KEEPALIVE_VALS:
  3640. {
  3641. struct tcp_keepalive *optionval;
  3642. PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
  3643. //
  3644. // Atempt to turn on or off keepalive sending, as necessary.
  3645. //
  3646. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  3647. return WSAENOPROTOOPT;
  3648. }
  3649. if ( InputBufferLength != sizeof(struct tcp_keepalive) ) {
  3650. return WSAEINVAL;
  3651. }
  3652. optionval = (struct tcp_keepalive *)InputBuffer;
  3653. if (optionval->onoff != 0 ) {
  3654. // Application wants to turn the keepalive on and also give the
  3655. // relevant parameters for it. If the TDI connection object handle is
  3656. // NULL, then the socket is not yet connected. In this case
  3657. // we'll just remember that the keepalive option was set and
  3658. // actually turn them on in WSHNotify() after a connect()
  3659. // has completed on the socket.
  3660. //
  3661. if ( TdiConnectionObjectHandle != NULL ) {
  3662. err = SetTdiInformation(
  3663. TdiConnectionObjectHandle,
  3664. CO_TL_ENTITY,
  3665. INFO_CLASS_PROTOCOL,
  3666. INFO_TYPE_CONNECTION,
  3667. TCP_SOCKET_KEEPALIVE_VALS,
  3668. optionval,
  3669. InputBufferLength,
  3670. TRUE
  3671. );
  3672. if ( err != NO_ERROR ) {
  3673. return err;
  3674. }
  3675. }
  3676. //
  3677. // Remember that keepalives are enabled for this socket.
  3678. //
  3679. context->KeepAliveVals.onoff = TRUE;
  3680. context->KeepAliveVals.keepalivetime = optionval->keepalivetime;
  3681. context->KeepAliveVals.keepaliveinterval = optionval->keepaliveinterval;
  3682. } else if ( optionval->onoff == 0 ) {
  3683. //
  3684. // Application wants to turn keepalive off. If the TDI
  3685. // connection object is NULL, the socket is not yet
  3686. // connected. In this case we'll just remember that
  3687. // keepalives are disabled.
  3688. if ( TdiConnectionObjectHandle != NULL ) {
  3689. err = SetTdiInformation(
  3690. TdiConnectionObjectHandle,
  3691. CO_TL_ENTITY,
  3692. INFO_CLASS_PROTOCOL,
  3693. INFO_TYPE_CONNECTION,
  3694. TCP_SOCKET_KEEPALIVE_VALS,
  3695. optionval,
  3696. InputBufferLength,
  3697. TRUE
  3698. );
  3699. if ( err != NO_ERROR ) {
  3700. return err;
  3701. }
  3702. }
  3703. //
  3704. // Remember that keepalives are disabled for this socket.
  3705. //
  3706. context->KeepAliveVals.onoff = FALSE;
  3707. }
  3708. // break;
  3709. return NO_ERROR;
  3710. }
  3711. default :
  3712. err = WSAEINVAL;
  3713. break;
  3714. }
  3715. return err;
  3716. } // WSHIoctl
  3717. NTSTATUS
  3718. GetTcpipInterfaceList(
  3719. IN LPVOID OutputBuffer,
  3720. IN DWORD OutputBufferLength,
  3721. OUT LPDWORD NumberOfBytesReturned
  3722. )
  3723. /*++
  3724. Routine Description:
  3725. This routine queries the INTERFACE_INFO array for all supported
  3726. IP interfaces in the system. This is a helper routine for handling
  3727. the SIO_GET_INTERFACE_LIST IOCTL.
  3728. Arguments:
  3729. OutputBuffer - Points to a buffer that will receive the INTERFACE_INFO
  3730. array.
  3731. OutputBufferLength - The length of OutputBuffer.
  3732. NumberOfBytesReturned - Receives the number of bytes actually written
  3733. to OutputBuffer.
  3734. Return Value:
  3735. NTSTATUS - The completion status.
  3736. --*/
  3737. {
  3738. OBJECT_ATTRIBUTES objectAttributes;
  3739. UNICODE_STRING deviceName;
  3740. NTSTATUS status;
  3741. IO_STATUS_BLOCK ioStatusBlock;
  3742. HANDLE deviceHandle;
  3743. TCP_REQUEST_QUERY_INFORMATION_EX tcpRequest;
  3744. TDIObjectID objectId;
  3745. IPSNMPInfo snmpInfo;
  3746. IPInterfaceInfo * interfaceInfo;
  3747. IFEntry * ifentry;
  3748. IPAddrEntry * addressBuffer;
  3749. IPAddrEntry * addressScan;
  3750. TDIEntityID * entityBuffer;
  3751. TDIEntityID * entityScan;
  3752. ULONG i, j;
  3753. ULONG entityCount;
  3754. ULONG entityBufferLength;
  3755. ULONG entityType;
  3756. ULONG addressBufferLength;
  3757. LPINTERFACE_INFO outputInterfaceInfo;
  3758. DWORD outputBytesRemaining;
  3759. LPSOCKADDR_IN sockaddr;
  3760. CHAR fastAddressBuffer[MAX_FAST_ADDRESS_BUFFER];
  3761. CHAR fastEntityBuffer[MAX_FAST_ENTITY_BUFFER];
  3762. CHAR ifentryBuffer[sizeof(IFEntry) + MAX_IFDESCR_LEN];
  3763. CHAR interfaceInfoBuffer[sizeof(IPInterfaceInfo) + MAX_PHYSADDR_SIZE];
  3764. //
  3765. // Setup locals so we know how to cleanup on exit.
  3766. //
  3767. deviceHandle = NULL;
  3768. addressBuffer = NULL;
  3769. entityBuffer = (PVOID)fastEntityBuffer;
  3770. entityBufferLength = sizeof(fastEntityBuffer);
  3771. interfaceInfo = NULL;
  3772. outputInterfaceInfo = OutputBuffer;
  3773. outputBytesRemaining = OutputBufferLength;
  3774. //
  3775. // Open a handle to the TCP/IP device.
  3776. //
  3777. RtlInitUnicodeString(
  3778. &deviceName,
  3779. DD_TCP_DEVICE_NAME
  3780. );
  3781. InitializeObjectAttributes(
  3782. &objectAttributes,
  3783. &deviceName,
  3784. OBJ_CASE_INSENSITIVE,
  3785. NULL,
  3786. NULL
  3787. );
  3788. status = NtCreateFile(
  3789. &deviceHandle,
  3790. SYNCHRONIZE | GENERIC_EXECUTE,
  3791. &objectAttributes,
  3792. &ioStatusBlock,
  3793. NULL,
  3794. FILE_ATTRIBUTE_NORMAL,
  3795. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3796. FILE_OPEN_IF,
  3797. FILE_SYNCHRONOUS_IO_NONALERT,
  3798. NULL,
  3799. 0
  3800. );
  3801. if( !NT_SUCCESS(status) ) {
  3802. goto exit;
  3803. }
  3804. //
  3805. // Get the entities supported by the TCP device.
  3806. //
  3807. RtlZeroMemory(
  3808. &tcpRequest,
  3809. sizeof(tcpRequest)
  3810. );
  3811. tcpRequest.ID.toi_entity.tei_entity = GENERIC_ENTITY;
  3812. tcpRequest.ID.toi_entity.tei_instance = 0;
  3813. tcpRequest.ID.toi_class = INFO_CLASS_GENERIC;
  3814. tcpRequest.ID.toi_type = INFO_TYPE_PROVIDER;
  3815. tcpRequest.ID.toi_id = ENTITY_LIST_ID;
  3816. for( ; ; ) {
  3817. status = NtDeviceIoControlFile(
  3818. deviceHandle,
  3819. NULL, // Event
  3820. NULL, // ApcRoutine
  3821. NULL, // ApcContext
  3822. &ioStatusBlock,
  3823. IOCTL_TCP_QUERY_INFORMATION_EX,
  3824. &tcpRequest,
  3825. sizeof(tcpRequest),
  3826. entityBuffer,
  3827. entityBufferLength
  3828. );
  3829. if( NT_SUCCESS(status) ) {
  3830. break;
  3831. }
  3832. if( status != STATUS_BUFFER_TOO_SMALL ) {
  3833. goto exit;
  3834. }
  3835. if( entityBuffer != (PVOID)fastEntityBuffer ) {
  3836. RtlFreeHeap(
  3837. RtlProcessHeap(),
  3838. 0,
  3839. entityBuffer
  3840. );
  3841. }
  3842. entityBufferLength += sizeof(TDIEntityID);
  3843. entityBuffer = RtlAllocateHeap(
  3844. RtlProcessHeap(),
  3845. 0,
  3846. entityBufferLength
  3847. );
  3848. if( entityBuffer == NULL ) {
  3849. status = STATUS_INSUFFICIENT_RESOURCES;
  3850. goto exit;
  3851. }
  3852. }
  3853. entityCount = ((ULONG) ioStatusBlock.Information) / sizeof(*entityBuffer);
  3854. //
  3855. // Scan the entities looking for IP.
  3856. //
  3857. for( i = 0, entityScan = entityBuffer ;
  3858. i < entityCount ;
  3859. i++, entityScan++ ) {
  3860. if( entityScan->tei_entity != CL_NL_ENTITY ) {
  3861. continue;
  3862. }
  3863. RtlZeroMemory(
  3864. &tcpRequest,
  3865. sizeof(tcpRequest)
  3866. );
  3867. objectId.toi_entity = *entityScan;
  3868. objectId.toi_class = INFO_CLASS_GENERIC;
  3869. objectId.toi_type = INFO_TYPE_PROVIDER;
  3870. objectId.toi_id = ENTITY_TYPE_ID;
  3871. tcpRequest.ID = objectId;
  3872. status = NtDeviceIoControlFile(
  3873. deviceHandle,
  3874. NULL, // Event
  3875. NULL, // ApcRoutine
  3876. NULL, // ApcContext
  3877. &ioStatusBlock,
  3878. IOCTL_TCP_QUERY_INFORMATION_EX,
  3879. &tcpRequest,
  3880. sizeof(tcpRequest),
  3881. &entityType,
  3882. sizeof(entityType)
  3883. );
  3884. if( !NT_SUCCESS(status) ) {
  3885. goto exit;
  3886. }
  3887. if( entityType != CL_NL_IP ) {
  3888. continue;
  3889. }
  3890. //
  3891. // OK, we found an IP entity. Now lookup its addresses.
  3892. // Start by querying the number of addresses supported by
  3893. // this interface.
  3894. //
  3895. RtlZeroMemory(
  3896. &tcpRequest,
  3897. sizeof(tcpRequest)
  3898. );
  3899. objectId.toi_class = INFO_CLASS_PROTOCOL;
  3900. objectId.toi_id = IP_MIB_STATS_ID;
  3901. tcpRequest.ID = objectId;
  3902. status = NtDeviceIoControlFile(
  3903. deviceHandle,
  3904. NULL, // Event
  3905. NULL, // ApcRoutine
  3906. NULL, // ApcContext
  3907. &ioStatusBlock,
  3908. IOCTL_TCP_QUERY_INFORMATION_EX,
  3909. &tcpRequest,
  3910. sizeof(tcpRequest),
  3911. &snmpInfo,
  3912. sizeof(snmpInfo)
  3913. );
  3914. if( !NT_SUCCESS(status) ) {
  3915. goto exit;
  3916. }
  3917. if( snmpInfo.ipsi_numaddr <= 0 ) {
  3918. continue;
  3919. }
  3920. //
  3921. // This interface has addresses. Cool. Allocate a temporary
  3922. // buffer so we can query them.
  3923. //
  3924. addressBufferLength = snmpInfo.ipsi_numaddr * sizeof(*addressBuffer);
  3925. if( addressBufferLength <= sizeof(fastAddressBuffer) ) {
  3926. addressBuffer = (PVOID)fastAddressBuffer;
  3927. } else {
  3928. addressBuffer = RtlAllocateHeap(
  3929. RtlProcessHeap(),
  3930. 0,
  3931. addressBufferLength
  3932. );
  3933. if( addressBuffer == NULL ) {
  3934. status = STATUS_INSUFFICIENT_RESOURCES;
  3935. goto exit;
  3936. }
  3937. }
  3938. RtlZeroMemory(
  3939. &tcpRequest,
  3940. sizeof(tcpRequest)
  3941. );
  3942. objectId.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  3943. tcpRequest.ID = objectId;
  3944. status = NtDeviceIoControlFile(
  3945. deviceHandle,
  3946. NULL, // Event
  3947. NULL, // ApcRoutine
  3948. NULL, // ApcContext
  3949. &ioStatusBlock,
  3950. IOCTL_TCP_QUERY_INFORMATION_EX,
  3951. &tcpRequest,
  3952. sizeof(tcpRequest),
  3953. addressBuffer,
  3954. addressBufferLength
  3955. );
  3956. if( !NT_SUCCESS(status) ) {
  3957. goto exit;
  3958. }
  3959. addressBufferLength = (ULONG)ioStatusBlock.Information;
  3960. snmpInfo.ipsi_numaddr = addressBufferLength /
  3961. sizeof(*addressBuffer);
  3962. //
  3963. // Try to get the IFEntry info so we can tell if the interface
  3964. // is "up".
  3965. //
  3966. ifentry = (PVOID)ifentryBuffer;
  3967. RtlZeroMemory(
  3968. ifentryBuffer,
  3969. sizeof(ifentryBuffer)
  3970. );
  3971. RtlZeroMemory(
  3972. &tcpRequest,
  3973. sizeof(tcpRequest)
  3974. );
  3975. addressScan = (IPAddrEntry *) addressBuffer;
  3976. RtlCopyMemory(
  3977. &tcpRequest.Context,
  3978. &addressScan->iae_addr,
  3979. sizeof(addressScan->iae_addr)
  3980. );
  3981. objectId.toi_id = IF_MIB_STATS_ID;
  3982. tcpRequest.ID = objectId;
  3983. tcpRequest.ID.toi_entity.tei_entity = IF_ENTITY;
  3984. status = NtDeviceIoControlFile(
  3985. deviceHandle,
  3986. NULL, // Event
  3987. NULL, // ApcRoutine
  3988. NULL, // ApcContext
  3989. &ioStatusBlock,
  3990. IOCTL_TCP_QUERY_INFORMATION_EX,
  3991. &tcpRequest,
  3992. sizeof(tcpRequest),
  3993. ifentry,
  3994. sizeof(ifentryBuffer)
  3995. );
  3996. if( !NT_SUCCESS(status ) ) {
  3997. ifentry->if_adminstatus = 0;
  3998. }
  3999. //
  4000. // Now scan the list
  4001. //
  4002. for( j = 0, addressScan = addressBuffer ;
  4003. j < snmpInfo.ipsi_numaddr ;
  4004. j++, addressScan++ ) {
  4005. //
  4006. // Skip any entries that don't have IP addresses yet.
  4007. //
  4008. if( addressScan->iae_addr == 0 ) {
  4009. continue;
  4010. }
  4011. //
  4012. // If the output buffer is full, fail the request now.
  4013. //
  4014. if( outputBytesRemaining <= sizeof(*outputInterfaceInfo) ) {
  4015. status = STATUS_BUFFER_TOO_SMALL;
  4016. goto exit;
  4017. }
  4018. //
  4019. // Setup the output structure.
  4020. //
  4021. RtlZeroMemory(
  4022. outputInterfaceInfo,
  4023. sizeof(*outputInterfaceInfo)
  4024. );
  4025. outputInterfaceInfo->iiFlags = IFF_MULTICAST;
  4026. sockaddr = &outputInterfaceInfo->iiAddress.AddressIn;
  4027. sockaddr->sin_family = AF_INET;
  4028. sockaddr->sin_addr.s_addr = addressScan->iae_addr;
  4029. if( sockaddr->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) ) {
  4030. outputInterfaceInfo->iiFlags |= IFF_LOOPBACK;
  4031. }
  4032. sockaddr = &outputInterfaceInfo->iiNetmask.AddressIn;
  4033. sockaddr->sin_family = AF_INET;
  4034. sockaddr->sin_addr.s_addr = addressScan->iae_mask;
  4035. if( addressScan->iae_bcastaddr != 0 ) {
  4036. outputInterfaceInfo->iiFlags |= IFF_BROADCAST;
  4037. sockaddr = &outputInterfaceInfo->iiBroadcastAddress.AddressIn;
  4038. sockaddr->sin_family = AF_INET;
  4039. ASSERT (htonl(INADDR_BROADCAST)==INADDR_BROADCAST);
  4040. sockaddr->sin_addr.s_addr = INADDR_BROADCAST;
  4041. }
  4042. //
  4043. // Grrr...
  4044. //
  4045. // I know how to enumerate the entities supported by the
  4046. // driver (those are stored in entityBuffer).
  4047. //
  4048. // I know how to find the IP entities in that buffer.
  4049. //
  4050. // I know how to enumerate the IP addresses supported
  4051. // by a given IP entity (those are stored in addressBuffer).
  4052. //
  4053. // I also know (but haven't done yet) how to find the IF
  4054. // entities (interfaces; basically NICs) and determine if
  4055. // a given IF is "up" or "down".
  4056. //
  4057. // What I don't know how to do is associate the addresses
  4058. // in addressBuffer with specific IF entities. Without
  4059. // this information, I cannot determine if a given *address*
  4060. // is "up" or "down", so for now I'll just assume they're
  4061. // all "up".
  4062. //
  4063. // if( ifentry->if_adminstatus == IF_STATUS_UP )
  4064. {
  4065. outputInterfaceInfo->iiFlags |= IFF_UP;
  4066. }
  4067. //
  4068. // Get the IP interface info for this interface so we can
  4069. // determine if it's "point-to-point".
  4070. //
  4071. interfaceInfo = (PVOID)interfaceInfoBuffer;
  4072. RtlZeroMemory(
  4073. interfaceInfoBuffer,
  4074. sizeof(interfaceInfoBuffer)
  4075. );
  4076. RtlZeroMemory(
  4077. &tcpRequest,
  4078. sizeof(tcpRequest)
  4079. );
  4080. RtlCopyMemory(
  4081. &tcpRequest.Context,
  4082. &addressScan->iae_addr,
  4083. sizeof(addressScan->iae_addr)
  4084. );
  4085. objectId.toi_id = IP_INTFC_INFO_ID;
  4086. tcpRequest.ID = objectId;
  4087. status = NtDeviceIoControlFile(
  4088. deviceHandle,
  4089. NULL, // Event
  4090. NULL, // ApcRoutine
  4091. NULL, // ApcContext
  4092. &ioStatusBlock,
  4093. IOCTL_TCP_QUERY_INFORMATION_EX,
  4094. &tcpRequest,
  4095. sizeof(tcpRequest),
  4096. interfaceInfo,
  4097. sizeof(interfaceInfoBuffer)
  4098. );
  4099. if( NT_SUCCESS(status) ) {
  4100. if( interfaceInfo->iii_flags & IP_INTFC_FLAG_P2P ) {
  4101. outputInterfaceInfo->iiFlags |= IFF_POINTTOPOINT;
  4102. }
  4103. } else {
  4104. //
  4105. // Print something informative here, then press on.
  4106. //
  4107. }
  4108. //
  4109. // Advance to the next output structure.
  4110. //
  4111. outputInterfaceInfo++;
  4112. outputBytesRemaining -= sizeof(*outputInterfaceInfo);
  4113. }
  4114. //
  4115. // Free the temporary buffer.
  4116. //
  4117. if( addressBuffer != (PVOID)fastAddressBuffer ) {
  4118. RtlFreeHeap(
  4119. RtlProcessHeap(),
  4120. 0,
  4121. addressBuffer
  4122. );
  4123. }
  4124. addressBuffer = NULL;
  4125. }
  4126. //
  4127. // Success!
  4128. //
  4129. *NumberOfBytesReturned = OutputBufferLength - outputBytesRemaining;
  4130. status = STATUS_SUCCESS;
  4131. exit:
  4132. if( addressBuffer != (PVOID)fastAddressBuffer &&
  4133. addressBuffer != NULL ) {
  4134. RtlFreeHeap(
  4135. RtlProcessHeap(),
  4136. 0,
  4137. addressBuffer
  4138. );
  4139. }
  4140. if( entityBuffer != (PVOID)fastEntityBuffer &&
  4141. entityBuffer != NULL ) {
  4142. RtlFreeHeap(
  4143. RtlProcessHeap(),
  4144. 0,
  4145. entityBuffer
  4146. );
  4147. }
  4148. if( deviceHandle != NULL ) {
  4149. NtClose( deviceHandle );
  4150. }
  4151. return status;
  4152. } // GetTcpipInterfaceList
  4153. INT
  4154. NtStatusToSocketError (
  4155. IN NTSTATUS Status
  4156. )
  4157. {
  4158. switch ( Status ) {
  4159. case STATUS_PENDING:
  4160. ASSERT (FALSE);
  4161. return WSASYSCALLFAILURE;
  4162. case STATUS_INVALID_HANDLE:
  4163. case STATUS_OBJECT_TYPE_MISMATCH:
  4164. return WSAENOTSOCK;
  4165. case STATUS_INSUFFICIENT_RESOURCES:
  4166. case STATUS_PAGEFILE_QUOTA:
  4167. case STATUS_COMMITMENT_LIMIT:
  4168. case STATUS_WORKING_SET_QUOTA:
  4169. case STATUS_NO_MEMORY:
  4170. case STATUS_CONFLICTING_ADDRESSES:
  4171. case STATUS_QUOTA_EXCEEDED:
  4172. case STATUS_TOO_MANY_PAGING_FILES:
  4173. case STATUS_REMOTE_RESOURCES:
  4174. case STATUS_TOO_MANY_ADDRESSES:
  4175. return WSAENOBUFS;
  4176. case STATUS_SHARING_VIOLATION:
  4177. case STATUS_ADDRESS_ALREADY_EXISTS:
  4178. return WSAEADDRINUSE;
  4179. case STATUS_LINK_TIMEOUT:
  4180. case STATUS_IO_TIMEOUT:
  4181. case STATUS_TIMEOUT:
  4182. return WSAETIMEDOUT;
  4183. case STATUS_GRACEFUL_DISCONNECT:
  4184. return WSAEDISCON;
  4185. case STATUS_REMOTE_DISCONNECT:
  4186. case STATUS_CONNECTION_RESET:
  4187. case STATUS_LINK_FAILED:
  4188. case STATUS_CONNECTION_DISCONNECTED:
  4189. case STATUS_PORT_UNREACHABLE:
  4190. return WSAECONNRESET;
  4191. case STATUS_LOCAL_DISCONNECT:
  4192. case STATUS_TRANSACTION_ABORTED:
  4193. case STATUS_CONNECTION_ABORTED:
  4194. return WSAECONNABORTED;
  4195. case STATUS_BAD_NETWORK_PATH:
  4196. case STATUS_NETWORK_UNREACHABLE:
  4197. case STATUS_PROTOCOL_UNREACHABLE:
  4198. return WSAENETUNREACH;
  4199. case STATUS_HOST_UNREACHABLE:
  4200. return WSAEHOSTUNREACH;
  4201. case STATUS_CANCELLED:
  4202. case STATUS_REQUEST_ABORTED:
  4203. return WSAEINTR;
  4204. case STATUS_BUFFER_OVERFLOW:
  4205. case STATUS_INVALID_BUFFER_SIZE:
  4206. return WSAEMSGSIZE;
  4207. case STATUS_BUFFER_TOO_SMALL:
  4208. case STATUS_ACCESS_VIOLATION:
  4209. return WSAEFAULT;
  4210. case STATUS_DEVICE_NOT_READY:
  4211. case STATUS_REQUEST_NOT_ACCEPTED:
  4212. return WSAEWOULDBLOCK;
  4213. case STATUS_INVALID_NETWORK_RESPONSE:
  4214. case STATUS_NETWORK_BUSY:
  4215. case STATUS_NO_SUCH_DEVICE:
  4216. case STATUS_NO_SUCH_FILE:
  4217. case STATUS_OBJECT_PATH_NOT_FOUND:
  4218. case STATUS_OBJECT_NAME_NOT_FOUND:
  4219. case STATUS_UNEXPECTED_NETWORK_ERROR:
  4220. return WSAENETDOWN;
  4221. case STATUS_INVALID_CONNECTION:
  4222. return WSAENOTCONN;
  4223. case STATUS_REMOTE_NOT_LISTENING:
  4224. case STATUS_CONNECTION_REFUSED:
  4225. return WSAECONNREFUSED;
  4226. case STATUS_PIPE_DISCONNECTED:
  4227. return WSAESHUTDOWN;
  4228. case STATUS_INVALID_ADDRESS:
  4229. case STATUS_INVALID_ADDRESS_COMPONENT:
  4230. return WSAEADDRNOTAVAIL;
  4231. case STATUS_NOT_SUPPORTED:
  4232. case STATUS_NOT_IMPLEMENTED:
  4233. return WSAEOPNOTSUPP;
  4234. case STATUS_ACCESS_DENIED:
  4235. return WSAEACCES;
  4236. default:
  4237. if ( NT_SUCCESS(Status) ) {
  4238. #if DBG
  4239. DbgPrint ("SockNtStatusToSocketError: success status %lx "
  4240. "not mapped\n", Status );
  4241. #endif
  4242. return NO_ERROR;
  4243. }
  4244. #if DBG
  4245. DbgPrint ("SockNtStatusToSocketError: unable to map 0x%lX, returning\n", Status );
  4246. #endif
  4247. return WSAENOBUFS;
  4248. case STATUS_UNSUCCESSFUL:
  4249. case STATUS_INVALID_PARAMETER:
  4250. case STATUS_ADDRESS_CLOSED:
  4251. case STATUS_CONNECTION_INVALID:
  4252. case STATUS_ADDRESS_ALREADY_ASSOCIATED:
  4253. case STATUS_ADDRESS_NOT_ASSOCIATED:
  4254. case STATUS_CONNECTION_ACTIVE:
  4255. case STATUS_INVALID_DEVICE_STATE:
  4256. case STATUS_INVALID_DEVICE_REQUEST:
  4257. return WSAEINVAL;
  4258. }
  4259. } // NtStatusToSocketError