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.

3893 lines
112 KiB

  1. // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
  2. //
  3. // Copyright (c) 1985-2000 Microsoft Corporation
  4. //
  5. // This file is part of the Microsoft Research IPv6 Network Protocol Stack.
  6. // You should have received a copy of the Microsoft End-User License Agreement
  7. // for this software along with this release; see the file "license.txt".
  8. // If not, please see http://www.research.microsoft.com/msripv6/license.htm,
  9. // or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
  10. //
  11. // Abstract:
  12. //
  13. // This module contains necessary routines for the Windows Sockets
  14. // Helper DLL. This DLL provides the transport-specific support necessary
  15. // for the Windows Sockets DLL to use IPv6 as a transport.
  16. //
  17. // Revision History:
  18. //
  19. // Ported from wshsmple.c in the DDK.
  20. //
  21. #pragma warning(disable:4152) // function/data pointer conversion in expression
  22. #define UNICODE
  23. #include <nt.h>
  24. #include <ntrtl.h>
  25. #include <nturtl.h>
  26. #include <windows.h>
  27. #define UDP_HEADER_SIZE 8
  28. #include <wchar.h>
  29. #include <winsock2.h>
  30. #include <ws2tcpip.h>
  31. #include <ws2ip6.h>
  32. #include <ip6.h> // IPv6 protocol definitions.
  33. #include <wsahelp.h>
  34. // private socket options to be accessed via WSAIoctl
  35. #include <mstcpip.h>
  36. #include <ntddip6.h>
  37. #include <ntddtcp.h>
  38. #include <tdiinfo.h>
  39. #include <smpletcp.h>
  40. #include <nspapi.h>
  41. //
  42. // Define alignment macros to align structure sizes and pointers up and down.
  43. //
  44. #define ALIGN_DOWN(length, type) \
  45. ((ULONG)(length) & ~(sizeof(type) - 1))
  46. #define ALIGN_UP(length, type) \
  47. (ALIGN_DOWN(((ULONG)(length) + sizeof(type) - 1), type))
  48. #define ALIGN_DOWN_POINTER(address, type) \
  49. ((PVOID)((ULONG_PTR)(address) & ~((ULONG_PTR)sizeof(type) - 1)))
  50. #define ALIGN_UP_POINTER(address, type) \
  51. (ALIGN_DOWN_POINTER(((ULONG_PTR)(address) + sizeof(type) - 1), type))
  52. ///////////////////////////////////////////////////
  53. #define TCP_NAME L"TCP/IPv6"
  54. #define UDP_NAME L"UDP/IPv6"
  55. #define RAW_NAME L"RAW/IPv6"
  56. #define IS_DGRAM_SOCK(type) (((type) == SOCK_DGRAM) || ((type) == SOCK_RAW))
  57. //
  58. // Define valid flags for WSHOpenSocket2().
  59. //
  60. #define VALID_TCP_FLAGS (WSA_FLAG_OVERLAPPED)
  61. #define VALID_UDP_FLAGS (WSA_FLAG_OVERLAPPED | \
  62. WSA_FLAG_MULTIPOINT_C_LEAF | \
  63. WSA_FLAG_MULTIPOINT_D_LEAF)
  64. //
  65. // Structure and variables to define the triples supported by TCP/IP. The
  66. // first entry of each array is considered the canonical triple for
  67. // that socket type; the other entries are synonyms for the first.
  68. //
  69. typedef struct _MAPPING_TRIPLE {
  70. INT AddressFamily;
  71. INT SocketType;
  72. INT Protocol;
  73. } MAPPING_TRIPLE, *PMAPPING_TRIPLE;
  74. MAPPING_TRIPLE TcpMappingTriples[] = { AF_INET6, SOCK_STREAM, IPPROTO_TCP,
  75. AF_INET6, SOCK_STREAM, 0,
  76. AF_INET6, 0, IPPROTO_TCP };
  77. MAPPING_TRIPLE UdpMappingTriples[] = { AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
  78. AF_INET6, SOCK_DGRAM, 0,
  79. AF_INET6, 0, IPPROTO_UDP };
  80. MAPPING_TRIPLE RawMappingTriples[] = { AF_INET6, SOCK_RAW, 0 };
  81. //
  82. // Winsock 2 WSAPROTOCOL_INFO structures for all supported protocols.
  83. //
  84. #define WINSOCK_SPI_VERSION 2
  85. // sizeof(UDPHeader) == 8
  86. #define UDP_MESSAGE_SIZE (MAX_IPv6_PAYLOAD - 8)
  87. WSAPROTOCOL_INFOW Winsock2Protocols[] =
  88. {
  89. //
  90. // TCP
  91. //
  92. {
  93. XP1_GUARANTEED_DELIVERY // dwServiceFlags1
  94. | XP1_GUARANTEED_ORDER
  95. | XP1_GRACEFUL_CLOSE
  96. | XP1_EXPEDITED_DATA
  97. | XP1_IFS_HANDLES,
  98. 0, // dwServiceFlags2
  99. 0, // dwServiceFlags3
  100. 0, // dwServiceFlags4
  101. PFL_MATCHES_PROTOCOL_ZERO, // dwProviderFlags
  102. { // gProviderId
  103. 0, 0, 0,
  104. { 0, 0, 0, 0, 0, 0, 0, 0 }
  105. },
  106. 0, // dwCatalogEntryId
  107. { // ProtocolChain
  108. BASE_PROTOCOL, // ChainLen
  109. { 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
  110. },
  111. WINSOCK_SPI_VERSION, // iVersion
  112. AF_INET6, // iAddressFamily
  113. sizeof(SOCKADDR_IN6), // iMaxSockAddr
  114. sizeof(SOCKADDR_IN6), // iMinSockAddr
  115. SOCK_STREAM, // iSocketType
  116. IPPROTO_TCP, // iProtocol
  117. 0, // iProtocolMaxOffset
  118. BIGENDIAN, // iNetworkByteOrder
  119. SECURITY_PROTOCOL_NONE, // iSecurityScheme
  120. 0, // dwMessageSize
  121. 0, // dwProviderReserved
  122. L"MSAFD Tcpip [" TCP_NAME L"]" // szProtocol
  123. },
  124. //
  125. // UDP
  126. //
  127. {
  128. XP1_CONNECTIONLESS // dwServiceFlags1
  129. | XP1_MESSAGE_ORIENTED
  130. | XP1_SUPPORT_BROADCAST
  131. | XP1_SUPPORT_MULTIPOINT
  132. | XP1_IFS_HANDLES,
  133. 0, // dwServiceFlags2
  134. 0, // dwServiceFlags3
  135. 0, // dwServiceFlags4
  136. PFL_MATCHES_PROTOCOL_ZERO, // dwProviderFlags
  137. { // gProviderId
  138. 0, 0, 0,
  139. { 0, 0, 0, 0, 0, 0, 0, 0 }
  140. },
  141. 0, // dwCatalogEntryId
  142. { // ProtocolChain
  143. BASE_PROTOCOL, // ChainLen
  144. { 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
  145. },
  146. WINSOCK_SPI_VERSION, // iVersion
  147. AF_INET6, // iAddressFamily
  148. sizeof(SOCKADDR_IN6), // iMaxSockAddr
  149. sizeof(SOCKADDR_IN6), // iMinSockAddr
  150. SOCK_DGRAM, // iSocketType
  151. IPPROTO_UDP, // iProtocol
  152. 0, // iProtocolMaxOffset
  153. BIGENDIAN, // iNetworkByteOrder
  154. SECURITY_PROTOCOL_NONE, // iSecurityScheme
  155. UDP_MESSAGE_SIZE, // dwMessageSize
  156. 0, // dwProviderReserved
  157. L"MSAFD Tcpip [" UDP_NAME L"]" // szProtocol
  158. },
  159. //
  160. // RAW
  161. //
  162. {
  163. XP1_CONNECTIONLESS // dwServiceFlags1
  164. | XP1_MESSAGE_ORIENTED
  165. | XP1_SUPPORT_BROADCAST
  166. | XP1_SUPPORT_MULTIPOINT
  167. | XP1_IFS_HANDLES,
  168. 0, // dwServiceFlags2
  169. 0, // dwServiceFlags3
  170. 0, // dwServiceFlags4
  171. PFL_MATCHES_PROTOCOL_ZERO // dwProviderFlags
  172. | PFL_HIDDEN,
  173. { // gProviderId
  174. 0, 0, 0,
  175. { 0, 0, 0, 0, 0, 0, 0, 0 }
  176. },
  177. 0, // dwCatalogEntryId
  178. { // ProtocolChain
  179. BASE_PROTOCOL, // ChainLen
  180. { 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
  181. },
  182. WINSOCK_SPI_VERSION, // iVersion
  183. AF_INET6, // iAddressFamily
  184. sizeof(SOCKADDR_IN6), // iMaxSockAddr
  185. sizeof(SOCKADDR_IN6), // iMinSockAddr
  186. SOCK_RAW, // iSocketType
  187. 0, // iProtocol
  188. 255, // iProtocolMaxOffset
  189. BIGENDIAN, // iNetworkByteOrder
  190. SECURITY_PROTOCOL_NONE, // iSecurityScheme
  191. UDP_MESSAGE_SIZE, // dwMessageSize
  192. 0, // dwProviderReserved
  193. L"MSAFD Tcpip [" RAW_NAME L"]" // szProtocol
  194. }
  195. };
  196. #define NUM_WINSOCK2_PROTOCOLS \
  197. ( sizeof(Winsock2Protocols) / sizeof(Winsock2Protocols[0]) )
  198. //
  199. // The GUID identifying this provider.
  200. //
  201. GUID IPv6ProviderGuid = { /* f9eab0c0-26d4-11d0-bbbf-00aa006c34e4 */
  202. 0xf9eab0c0,
  203. 0x26d4,
  204. 0x11d0,
  205. {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}
  206. };
  207. #define TL_INSTANCE 0
  208. //
  209. // Forward declarations of internal routines.
  210. //
  211. VOID
  212. CompleteTdiActionApc (
  213. IN PVOID ApcContext,
  214. IN PIO_STATUS_BLOCK IoStatusBlock
  215. );
  216. INT
  217. SetTdiInformation (
  218. IN HANDLE TdiConnectionObjectHandle,
  219. IN ULONG Entity,
  220. IN ULONG Class,
  221. IN ULONG Type,
  222. IN ULONG Id,
  223. IN PVOID Value,
  224. IN ULONG ValueLength,
  225. IN BOOLEAN WaitForCompletion
  226. );
  227. BOOLEAN
  228. IsTripleInList (
  229. IN PMAPPING_TRIPLE List,
  230. IN ULONG ListLength,
  231. IN INT AddressFamily,
  232. IN INT SocketType,
  233. IN INT Protocol
  234. );
  235. //
  236. // The socket context structure for this DLL. Each open TCP/IP socket
  237. // will have one of these context structures, which is used to maintain
  238. // information about the socket.
  239. //
  240. typedef struct _WSHTCPIP_SOCKET_CONTEXT {
  241. INT AddressFamily;
  242. INT SocketType;
  243. INT Protocol;
  244. INT ReceiveBufferSize;
  245. DWORD Flags;
  246. INT MulticastHops;
  247. INT UnicastHops;
  248. ULONG MulticastInterface;
  249. INT MulticastLoopback;
  250. BOOLEAN KeepAlive;
  251. BOOLEAN NoDelay;
  252. BOOLEAN BsdUrgent;
  253. BOOLEAN MultipointLeaf;
  254. BOOLEAN Reserved3;
  255. IN6_ADDR MultipointTarget;
  256. HANDLE MultipointRootTdiAddressHandle;
  257. USHORT UdpChecksumCoverage;
  258. struct tcp_keepalive KeepAliveVals;
  259. INT Ipv6PktInfo;
  260. INT Ipv6HopLimit;
  261. INT HeaderInclude;
  262. INT ProtectionLevel;
  263. } WSHTCPIP_SOCKET_CONTEXT, *PWSHTCPIP_SOCKET_CONTEXT;
  264. #define DEFAULT_RECEIVE_BUFFER_SIZE 8192
  265. #define DEFAULT_MULTICAST_HOPS -1
  266. #define DEFAULT_MULTICAST_INTERFACE 0
  267. #define DEFAULT_MULTICAST_LOOPBACK TRUE
  268. #define DEFAULT_UDP_CHECKSUM_COVERAGE 0
  269. #define DEFAULT_UNICAST_HOPS -1
  270. #define DEFAULT_HEADER_INCLUDE FALSE
  271. BOOLEAN
  272. DllInitialize (
  273. IN PVOID DllHandle,
  274. IN ULONG Reason,
  275. IN PVOID Context OPTIONAL
  276. )
  277. {
  278. UNREFERENCED_PARAMETER(Context);
  279. switch ( Reason ) {
  280. case DLL_PROCESS_ATTACH:
  281. //
  282. // We don't need to receive thread attach and detach
  283. // notifications, so disable them to help application
  284. // performance.
  285. //
  286. DisableThreadLibraryCalls( DllHandle );
  287. return TRUE;
  288. case DLL_THREAD_ATTACH:
  289. break;
  290. case DLL_PROCESS_DETACH:
  291. break;
  292. case DLL_THREAD_DETACH:
  293. break;
  294. }
  295. return TRUE;
  296. } // SockInitialize
  297. INT
  298. WSHGetSockaddrType (
  299. IN PSOCKADDR Sockaddr,
  300. IN DWORD SockaddrLength,
  301. OUT PSOCKADDR_INFO SockaddrInfo
  302. )
  303. /*++
  304. Routine Description:
  305. This routine parses a sockaddr to determine the type of the
  306. machine address and endpoint address portions of the sockaddr.
  307. This is called by the winsock DLL whenever it needs to interpret
  308. a sockaddr.
  309. Arguments:
  310. Sockaddr - a pointer to the sockaddr structure to evaluate.
  311. SockaddrLength - the number of bytes in the sockaddr structure.
  312. SockaddrInfo - a pointer to a structure that will receive information
  313. about the specified sockaddr.
  314. Return Value:
  315. INT - a winsock error code indicating the status of the operation, or
  316. NO_ERROR if the operation succeeded.
  317. --*/
  318. {
  319. SOCKADDR_IN6 *sockaddr = (PSOCKADDR_IN6)Sockaddr;
  320. //
  321. // Make sure that the length is correct.
  322. //
  323. if ( SockaddrLength < sizeof(SOCKADDR_IN6) ) {
  324. return WSAEFAULT;
  325. }
  326. //
  327. // Make sure that the address family is correct.
  328. //
  329. if ( sockaddr->sin6_family != AF_INET6 ) {
  330. return WSAEAFNOSUPPORT;
  331. }
  332. //
  333. // The address passed the tests, looks like a good address.
  334. // Determine the type of the address portion of the sockaddr.
  335. // Note that IPv6 does not have a broadcast address.
  336. //
  337. if (IN6_IS_ADDR_UNSPECIFIED(&sockaddr->sin6_addr))
  338. SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
  339. else if (IN6_IS_ADDR_LOOPBACK(&sockaddr->sin6_addr))
  340. SockaddrInfo->AddressInfo = SockaddrAddressInfoLoopback;
  341. else
  342. SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
  343. //
  344. // Determine the type of the port (endpoint) in the sockaddr.
  345. //
  346. if ( sockaddr->sin6_port == 0 ) {
  347. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
  348. } else if ( ntohs( sockaddr->sin6_port ) < 2000 ) {
  349. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoReserved;
  350. } else {
  351. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoNormal;
  352. }
  353. return NO_ERROR;
  354. } // WSHGetSockaddrType
  355. INT
  356. WSHGetSocketInformation (
  357. IN PVOID HelperDllSocketContext,
  358. IN SOCKET SocketHandle,
  359. IN HANDLE TdiAddressObjectHandle,
  360. IN HANDLE TdiConnectionObjectHandle,
  361. IN INT Level,
  362. IN INT OptionName,
  363. OUT PCHAR OptionValue,
  364. OUT PINT OptionLength
  365. )
  366. /*++
  367. Routine Description:
  368. This routine retrieves information about a socket for those socket
  369. options supported in this helper DLL. The options supported here
  370. are SO_KEEPALIVE, SO_DONTROUTE, and TCP_EXPEDITED_1122. This routine is
  371. called by the winsock DLL when a level/option name combination is
  372. passed to getsockopt() that the winsock DLL does not understand.
  373. Arguments:
  374. HelperDllSocketContext - the context pointer returned from
  375. WSHOpenSocket().
  376. SocketHandle - the handle of the socket for which we're getting
  377. information.
  378. TdiAddressObjectHandle - the TDI address object of the socket, if
  379. any. If the socket is not yet bound to an address, then
  380. it does not have a TDI address object and this parameter
  381. will be NULL.
  382. TdiConnectionObjectHandle - the TDI connection object of the socket,
  383. if any. If the socket is not yet connected, then it does not
  384. have a TDI connection object and this parameter will be NULL.
  385. Level - the level parameter passed to getsockopt().
  386. OptionName - the optname parameter passed to getsockopt().
  387. OptionValue - the optval parameter passed to getsockopt().
  388. OptionLength - the optlen parameter passed to getsockopt().
  389. Return Value:
  390. INT - a winsock error code indicating the status of the operation, or
  391. NO_ERROR if the operation succeeded.
  392. --*/
  393. {
  394. PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
  395. UNREFERENCED_PARAMETER( SocketHandle );
  396. UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
  397. UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
  398. //
  399. // Check if this is an internal request for context information.
  400. //
  401. if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
  402. //
  403. // The Windows Sockets DLL is requesting context information
  404. // from us. If an output buffer was not supplied, the Windows
  405. // Sockets DLL is just requesting the size of our context
  406. // information.
  407. //
  408. if ( OptionValue != NULL ) {
  409. //
  410. // Make sure that the buffer is sufficient to hold all the
  411. // context information.
  412. //
  413. if ( *OptionLength < sizeof(*context) ) {
  414. return WSAEFAULT;
  415. }
  416. //
  417. // Copy in the context information.
  418. //
  419. CopyMemory( OptionValue, context, sizeof(*context) );
  420. }
  421. *OptionLength = sizeof(*context);
  422. return NO_ERROR;
  423. }
  424. //
  425. // The only other levels we support here are SOL_SOCKET,
  426. // IPPROTO_TCP, IPPROTO_UDP, and IPPROTO_IPV6.
  427. //
  428. if ( Level != SOL_SOCKET &&
  429. Level != IPPROTO_TCP &&
  430. Level != IPPROTO_UDP &&
  431. Level != IPPROTO_IPV6 ) {
  432. return WSAEINVAL;
  433. }
  434. //
  435. // Make sure that the output buffer is sufficiently large.
  436. //
  437. if ( *OptionLength < sizeof(int) ) {
  438. return WSAEFAULT;
  439. }
  440. //
  441. // Handle TCP-level options.
  442. //
  443. if ( Level == IPPROTO_TCP ) {
  444. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  445. return WSAENOPROTOOPT;
  446. }
  447. switch ( OptionName ) {
  448. case TCP_NODELAY:
  449. ZeroMemory( OptionValue, *OptionLength );
  450. *OptionValue = context->NoDelay;
  451. *OptionLength = sizeof(int);
  452. break;
  453. case TCP_EXPEDITED_1122:
  454. ZeroMemory( OptionValue, *OptionLength );
  455. *OptionValue = !context->BsdUrgent;
  456. *OptionLength = sizeof(int);
  457. break;
  458. default:
  459. return WSAEINVAL;
  460. }
  461. return NO_ERROR;
  462. }
  463. //
  464. // Handle UDP-level options.
  465. //
  466. if ( Level == IPPROTO_UDP ) {
  467. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  468. return WSAENOPROTOOPT;
  469. }
  470. //
  471. // Note that UDP_NOCHECKSUM is not supported for IPv6.
  472. //
  473. switch ( OptionName ) {
  474. case UDP_CHECKSUM_COVERAGE:
  475. *(PULONG)OptionValue = context->UdpChecksumCoverage;
  476. *OptionLength = sizeof(int);
  477. break;
  478. default:
  479. return WSAEINVAL;
  480. }
  481. return NO_ERROR;
  482. }
  483. //
  484. // Handle IP-level options.
  485. //
  486. if ( Level == IPPROTO_IPV6 ) {
  487. //
  488. // Act based on the specific option.
  489. //
  490. switch ( OptionName ) {
  491. case IPV6_UNICAST_HOPS:
  492. *(PINT)OptionValue = context->UnicastHops;
  493. *OptionLength = sizeof(int);
  494. return NO_ERROR;
  495. case IPV6_PROTECTION_LEVEL:
  496. *(PINT)OptionValue = context->ProtectionLevel;
  497. *OptionLength = sizeof(int);
  498. return NO_ERROR;
  499. default:
  500. //
  501. // No match, fall through.
  502. //
  503. break;
  504. }
  505. //
  506. // The following IP options are only valid on datagram sockets.
  507. //
  508. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  509. return WSAENOPROTOOPT;
  510. }
  511. //
  512. // Act based on the specific option.
  513. //
  514. switch ( OptionName ) {
  515. case IPV6_MULTICAST_HOPS:
  516. *(PINT)OptionValue = context->MulticastHops;
  517. *OptionLength = sizeof(int);
  518. return NO_ERROR;
  519. case IPV6_MULTICAST_IF:
  520. *(PULONG)OptionValue = context->MulticastInterface;
  521. *OptionLength = sizeof(int);
  522. return NO_ERROR;
  523. case IPV6_MULTICAST_LOOP:
  524. *(PINT)OptionValue = context->MulticastLoopback;
  525. *OptionLength = sizeof(int);
  526. return NO_ERROR;
  527. case IPV6_HDRINCL:
  528. *(PINT)OptionValue = context->HeaderInclude;
  529. *OptionLength = sizeof(int);
  530. return NO_ERROR;
  531. case IPV6_PKTINFO:
  532. *OptionValue = (char)context->Ipv6PktInfo;
  533. *OptionLength = sizeof(int);
  534. return NO_ERROR;
  535. case IPV6_HOPLIMIT:
  536. *OptionValue = (char)context->Ipv6HopLimit;
  537. *OptionLength = sizeof(int);
  538. return NO_ERROR;
  539. default:
  540. return WSAENOPROTOOPT;
  541. }
  542. }
  543. //
  544. // Handle socket-level options.
  545. //
  546. switch ( OptionName ) {
  547. case SO_KEEPALIVE:
  548. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  549. return WSAENOPROTOOPT;
  550. }
  551. ZeroMemory( OptionValue, *OptionLength );
  552. *OptionValue = context->KeepAlive;
  553. *OptionLength = sizeof(int);
  554. break;
  555. default:
  556. return WSAENOPROTOOPT;
  557. }
  558. return NO_ERROR;
  559. } // WSHGetSocketInformation
  560. INT
  561. WSHGetWildcardSockaddr (
  562. IN PVOID HelperDllSocketContext,
  563. OUT PSOCKADDR Sockaddr,
  564. OUT PINT SockaddrLength
  565. )
  566. /*++
  567. Routine Description:
  568. This routine returns a wildcard socket address. A wildcard address
  569. is one which will bind the socket to an endpoint of the transport's
  570. choosing. For IPv6, a wildcard address has address ::0 and port 0.
  571. Arguments:
  572. HelperDllSocketContext - the context pointer returned from
  573. WSHOpenSocket() for the socket for which we need a wildcard
  574. address.
  575. Sockaddr - points to a buffer which will receive the wildcard socket
  576. address.
  577. SockaddrLength - receives the length of the wioldcard sockaddr.
  578. Return Value:
  579. INT - a winsock error code indicating the status of the operation, or
  580. NO_ERROR if the operation succeeded.
  581. --*/
  582. {
  583. UNREFERENCED_PARAMETER(HelperDllSocketContext);
  584. if ( *SockaddrLength < sizeof(SOCKADDR_IN6) ) {
  585. return WSAEFAULT;
  586. }
  587. *SockaddrLength = sizeof(SOCKADDR_IN6);
  588. //
  589. // Just zero out the address and set the family to AF_INET6--this is
  590. // a wildcard address for IPv6.
  591. //
  592. ZeroMemory( Sockaddr, sizeof(SOCKADDR_IN6) );
  593. Sockaddr->sa_family = AF_INET6;
  594. return NO_ERROR;
  595. } // WSAGetWildcardSockaddr
  596. DWORD
  597. WSHGetWinsockMapping (
  598. OUT PWINSOCK_MAPPING Mapping,
  599. IN DWORD MappingLength
  600. )
  601. /*++
  602. Routine Description:
  603. Returns the list of address family/socket type/protocol triples
  604. supported by this helper DLL.
  605. Arguments:
  606. Mapping - receives a pointer to a WINSOCK_MAPPING structure that
  607. describes the triples supported here.
  608. MappingLength - the length, in bytes, of the passed-in Mapping buffer.
  609. Return Value:
  610. DWORD - the length, in bytes, of a WINSOCK_MAPPING structure for this
  611. helper DLL. If the passed-in buffer is too small, the return
  612. value will indicate the size of a buffer needed to contain
  613. the WINSOCK_MAPPING structure.
  614. --*/
  615. {
  616. DWORD mappingLength;
  617. mappingLength = sizeof(WINSOCK_MAPPING) - sizeof(MAPPING_TRIPLE) +
  618. sizeof(TcpMappingTriples) + sizeof(UdpMappingTriples)
  619. + sizeof(RawMappingTriples);
  620. //
  621. // If the passed-in buffer is too small, return the length needed
  622. // now without writing to the buffer. The caller should allocate
  623. // enough memory and call this routine again.
  624. //
  625. if ( mappingLength > MappingLength ) {
  626. return mappingLength;
  627. }
  628. //
  629. // Fill in the output mapping buffer with the list of triples
  630. // supported in this helper DLL.
  631. //
  632. Mapping->Rows = sizeof(TcpMappingTriples) / sizeof(TcpMappingTriples[0])
  633. + sizeof(UdpMappingTriples) / sizeof(UdpMappingTriples[0])
  634. + sizeof(RawMappingTriples) / sizeof(RawMappingTriples[0]);
  635. Mapping->Columns = sizeof(MAPPING_TRIPLE) / sizeof(DWORD);
  636. MoveMemory(
  637. Mapping->Mapping,
  638. TcpMappingTriples,
  639. sizeof(TcpMappingTriples)
  640. );
  641. MoveMemory(
  642. (PCHAR)Mapping->Mapping + sizeof(TcpMappingTriples),
  643. UdpMappingTriples,
  644. sizeof(UdpMappingTriples)
  645. );
  646. MoveMemory(
  647. (PCHAR)Mapping->Mapping + sizeof(TcpMappingTriples)
  648. + sizeof(UdpMappingTriples),
  649. RawMappingTriples,
  650. sizeof(RawMappingTriples)
  651. );
  652. //
  653. // Return the number of bytes we wrote.
  654. //
  655. return mappingLength;
  656. } // WSHGetWinsockMapping
  657. INT
  658. WSHOpenSocket (
  659. IN OUT PINT AddressFamily,
  660. IN OUT PINT SocketType,
  661. IN OUT PINT Protocol,
  662. OUT PUNICODE_STRING TransportDeviceName,
  663. OUT PVOID *HelperDllSocketContext,
  664. OUT PDWORD NotificationEvents
  665. )
  666. {
  667. return WSHOpenSocket2(
  668. AddressFamily,
  669. SocketType,
  670. Protocol,
  671. 0, // Group
  672. 0, // Flags
  673. TransportDeviceName,
  674. HelperDllSocketContext,
  675. NotificationEvents
  676. );
  677. } // WSHOpenSocket
  678. INT
  679. WSHOpenSocket2 (
  680. IN OUT PINT AddressFamily,
  681. IN OUT PINT SocketType,
  682. IN OUT PINT Protocol,
  683. IN GROUP Group,
  684. IN DWORD Flags,
  685. OUT PUNICODE_STRING TransportDeviceName,
  686. OUT PVOID *HelperDllSocketContext,
  687. OUT PDWORD NotificationEvents
  688. )
  689. /*++
  690. Routine Description:
  691. Does the necessary work for this helper DLL to open a socket and is
  692. called by the winsock DLL in the socket() routine. This routine
  693. verifies that the specified triple is valid, determines the NT
  694. device name of the TDI provider that will support that triple,
  695. allocates space to hold the socket's context block, and
  696. canonicalizes the triple.
  697. Arguments:
  698. AddressFamily - on input, the address family specified in the
  699. socket() call. On output, the canonicalized value for the
  700. address family.
  701. SocketType - on input, the socket type specified in the socket()
  702. call. On output, the canonicalized value for the socket type.
  703. Protocol - on input, the protocol specified in the socket() call.
  704. On output, the canonicalized value for the protocol.
  705. Group - Identifies the group for the new socket.
  706. Flags - Zero or more WSA_FLAG_* flags as passed into WSASocket().
  707. TransportDeviceName - receives the name of the TDI provider that
  708. will support the specified triple.
  709. HelperDllSocketContext - receives a context pointer that the winsock
  710. DLL will return to this helper DLL on future calls involving
  711. this socket.
  712. NotificationEvents - receives a bitmask of those state transitions
  713. this helper DLL should be notified on.
  714. Return Value:
  715. INT - a winsock error code indicating the status of the operation, or
  716. NO_ERROR if the operation succeeded.
  717. --*/
  718. {
  719. PWSHTCPIP_SOCKET_CONTEXT context;
  720. //
  721. // Determine whether this is to be a TCP, UDP, or RAW socket.
  722. //
  723. if ( IsTripleInList(
  724. TcpMappingTriples,
  725. sizeof(TcpMappingTriples) / sizeof(TcpMappingTriples[0]),
  726. *AddressFamily,
  727. *SocketType,
  728. *Protocol ) ) {
  729. //
  730. // It's a TCP socket. Check the flags.
  731. //
  732. if( ( Flags & ~VALID_TCP_FLAGS ) != 0 ) {
  733. return WSAEINVAL;
  734. }
  735. //
  736. // Return the canonical form of a TCP socket triple.
  737. //
  738. *AddressFamily = TcpMappingTriples[0].AddressFamily;
  739. *SocketType = TcpMappingTriples[0].SocketType;
  740. *Protocol = TcpMappingTriples[0].Protocol;
  741. //
  742. // Indicate the name of the TDI device that will service
  743. // SOCK_STREAM sockets in the internet address family.
  744. //
  745. RtlInitUnicodeString( TransportDeviceName, DD_TCPV6_DEVICE_NAME );
  746. } else if ( IsTripleInList(
  747. UdpMappingTriples,
  748. sizeof(UdpMappingTriples) / sizeof(UdpMappingTriples[0]),
  749. *AddressFamily,
  750. *SocketType,
  751. *Protocol ) ) {
  752. //
  753. // It's a UDP socket. Check the flags & group ID.
  754. //
  755. if( ( Flags & ~VALID_UDP_FLAGS ) != 0 ||
  756. Group == SG_CONSTRAINED_GROUP ) {
  757. return WSAEINVAL;
  758. }
  759. //
  760. // Return the canonical form of a UDP socket triple.
  761. //
  762. *AddressFamily = UdpMappingTriples[0].AddressFamily;
  763. *SocketType = UdpMappingTriples[0].SocketType;
  764. *Protocol = UdpMappingTriples[0].Protocol;
  765. //
  766. // Indicate the name of the TDI device that will service
  767. // SOCK_DGRAM sockets in the internet address family.
  768. //
  769. RtlInitUnicodeString( TransportDeviceName, DD_UDPV6_DEVICE_NAME );
  770. } else if ( IsTripleInList(
  771. RawMappingTriples,
  772. sizeof(RawMappingTriples) / sizeof(RawMappingTriples[0]),
  773. *AddressFamily,
  774. *SocketType,
  775. *Protocol ) )
  776. {
  777. UNICODE_STRING unicodeString;
  778. NTSTATUS status;
  779. //
  780. // There is no canonicalization to be done for SOCK_RAW.
  781. //
  782. if (*Protocol < 0 || *Protocol > 255) {
  783. return(WSAEINVAL);
  784. }
  785. //
  786. // Indicate the name of the TDI device that will service
  787. // SOCK_RAW sockets in the internet address family.
  788. //
  789. RtlInitUnicodeString(&unicodeString, DD_RAW_IPV6_DEVICE_NAME);
  790. RtlInitUnicodeString(TransportDeviceName, NULL);
  791. TransportDeviceName->MaximumLength = unicodeString.Length +
  792. (4 * sizeof(WCHAR) +
  793. sizeof(UNICODE_NULL));
  794. TransportDeviceName->Buffer = HeapAlloc(GetProcessHeap(), 0,
  795. TransportDeviceName->MaximumLength
  796. );
  797. if (TransportDeviceName->Buffer == NULL) {
  798. return(WSAENOBUFS);
  799. }
  800. //
  801. // Append the device name.
  802. //
  803. status = RtlAppendUnicodeStringToString(
  804. TransportDeviceName,
  805. &unicodeString
  806. );
  807. ASSERT(NT_SUCCESS(status));
  808. //
  809. // Append a separator.
  810. //
  811. TransportDeviceName->Buffer[TransportDeviceName->Length/sizeof(WCHAR)] =
  812. OBJ_NAME_PATH_SEPARATOR;
  813. TransportDeviceName->Length += sizeof(WCHAR);
  814. TransportDeviceName->Buffer[TransportDeviceName->Length/sizeof(WCHAR)] =
  815. UNICODE_NULL;
  816. //
  817. // Append the protocol number.
  818. //
  819. unicodeString.Buffer = TransportDeviceName->Buffer +
  820. (TransportDeviceName->Length / sizeof(WCHAR));
  821. unicodeString.Length = 0;
  822. unicodeString.MaximumLength = TransportDeviceName->MaximumLength -
  823. TransportDeviceName->Length;
  824. status = RtlIntegerToUnicodeString(
  825. (ULONG) *Protocol,
  826. 10,
  827. &unicodeString
  828. );
  829. TransportDeviceName->Length = TransportDeviceName->Length +
  830. unicodeString.Length;
  831. ASSERT(NT_SUCCESS(status));
  832. } else {
  833. //
  834. // This should never happen if the registry information about this
  835. // helper DLL is correct. If somehow this did happen, just return
  836. // an error.
  837. //
  838. return WSAEINVAL;
  839. }
  840. //
  841. // Allocate context for this socket. The Windows Sockets DLL will
  842. // return this value to us when it asks us to get/set socket options.
  843. //
  844. context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context) );
  845. if ( context == NULL ) {
  846. return WSAENOBUFS;
  847. }
  848. //
  849. // Initialize the context for the socket.
  850. //
  851. context->AddressFamily = *AddressFamily;
  852. context->SocketType = *SocketType;
  853. context->Protocol = *Protocol;
  854. context->ReceiveBufferSize = DEFAULT_RECEIVE_BUFFER_SIZE;
  855. context->Flags = Flags;
  856. context->MulticastHops = DEFAULT_MULTICAST_HOPS;
  857. context->MulticastInterface = DEFAULT_MULTICAST_INTERFACE;
  858. context->MulticastLoopback = DEFAULT_MULTICAST_LOOPBACK;
  859. context->KeepAlive = FALSE;
  860. context->NoDelay = FALSE;
  861. context->BsdUrgent = TRUE;
  862. context->UnicastHops = DEFAULT_UNICAST_HOPS;
  863. context->MultipointLeaf = FALSE;
  864. context->Reserved3 = FALSE;
  865. context->MultipointRootTdiAddressHandle = NULL;
  866. context->UdpChecksumCoverage = DEFAULT_UDP_CHECKSUM_COVERAGE;
  867. context->KeepAliveVals.onoff = FALSE;
  868. context->Ipv6PktInfo = FALSE;
  869. context->Ipv6HopLimit = FALSE;
  870. context->HeaderInclude = DEFAULT_HEADER_INCLUDE;
  871. context->ProtectionLevel = PROTECTION_LEVEL_DEFAULT;
  872. //
  873. // Tell the Windows Sockets DLL which state transitions we're
  874. // interested in being notified of. The only times we need to be
  875. // called is after a connect has completed so that we can turn on
  876. // the sending of keepalives if SO_KEEPALIVE was set before the
  877. // socket was connected, when the socket is closed so that we can
  878. // free context information, and when a connect fails so that we
  879. // can, if appropriate, dial in to the network that will support the
  880. // connect attempt.
  881. //
  882. *NotificationEvents =
  883. WSH_NOTIFY_CONNECT | WSH_NOTIFY_CLOSE | WSH_NOTIFY_CONNECT_ERROR;
  884. if (IS_DGRAM_SOCK(*SocketType)) {
  885. *NotificationEvents |= WSH_NOTIFY_BIND;
  886. } else {
  887. *NotificationEvents |= WSH_NOTIFY_LISTEN;
  888. }
  889. //
  890. // Everything worked, return success.
  891. //
  892. *HelperDllSocketContext = context;
  893. return NO_ERROR;
  894. } // WSHOpenSocket
  895. INT
  896. WSHNotify (
  897. IN PVOID HelperDllSocketContext,
  898. IN SOCKET SocketHandle,
  899. IN HANDLE TdiAddressObjectHandle,
  900. IN HANDLE TdiConnectionObjectHandle,
  901. IN DWORD NotifyEvent
  902. )
  903. /*++
  904. Routine Description:
  905. This routine is called by the winsock DLL after a state transition
  906. of the socket. Only state transitions returned in the
  907. NotificationEvents parameter of WSHOpenSocket() are notified here.
  908. This routine allows a winsock helper DLL to track the state of
  909. socket and perform necessary actions corresponding to state
  910. transitions.
  911. Arguments:
  912. HelperDllSocketContext - the context pointer given to the winsock
  913. DLL by WSHOpenSocket().
  914. SocketHandle - the handle for the socket.
  915. TdiAddressObjectHandle - the TDI address object of the socket, if
  916. any. If the socket is not yet bound to an address, then
  917. it does not have a TDI address object and this parameter
  918. will be NULL.
  919. TdiConnectionObjectHandle - the TDI connection object of the socket,
  920. if any. If the socket is not yet connected, then it does not
  921. have a TDI connection object and this parameter will be NULL.
  922. NotifyEvent - indicates the state transition for which we're being
  923. called.
  924. Return Value:
  925. INT - a winsock error code indicating the status of the operation, or
  926. NO_ERROR if the operation succeeded.
  927. --*/
  928. {
  929. PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
  930. INT err;
  931. UNREFERENCED_PARAMETER(SocketHandle);
  932. //
  933. // We should only be called after a connect() completes or when the
  934. // socket is being closed.
  935. //
  936. if ( NotifyEvent == WSH_NOTIFY_CONNECT ) {
  937. ULONG true = TRUE;
  938. ULONG false = FALSE;
  939. //
  940. // If a connection-object option was set on the socket before
  941. // it was connected, set the option for real now.
  942. //
  943. if ( context->KeepAlive ) {
  944. err = SetTdiInformation(
  945. TdiConnectionObjectHandle,
  946. CO_TL_ENTITY,
  947. INFO_CLASS_PROTOCOL,
  948. INFO_TYPE_CONNECTION,
  949. TCP_SOCKET_KEEPALIVE,
  950. &true,
  951. sizeof(true),
  952. TRUE
  953. );
  954. if ( err != NO_ERROR ) {
  955. return err;
  956. }
  957. }
  958. if ( context->KeepAliveVals.onoff ) {
  959. err = SetTdiInformation(
  960. TdiConnectionObjectHandle,
  961. CO_TL_ENTITY,
  962. INFO_CLASS_PROTOCOL,
  963. INFO_TYPE_CONNECTION,
  964. TCP_SOCKET_KEEPALIVE_VALS,
  965. &context->KeepAliveVals,
  966. sizeof(struct tcp_keepalive),
  967. TRUE
  968. );
  969. if ( err != NO_ERROR ) {
  970. return err;
  971. }
  972. }
  973. if ( context->NoDelay ) {
  974. err = SetTdiInformation(
  975. TdiConnectionObjectHandle,
  976. CO_TL_ENTITY,
  977. INFO_CLASS_PROTOCOL,
  978. INFO_TYPE_CONNECTION,
  979. TCP_SOCKET_NODELAY,
  980. &true,
  981. sizeof(true),
  982. TRUE
  983. );
  984. if ( err != NO_ERROR ) {
  985. return err;
  986. }
  987. }
  988. if ( context->ReceiveBufferSize != DEFAULT_RECEIVE_BUFFER_SIZE ) {
  989. err = SetTdiInformation(
  990. TdiConnectionObjectHandle,
  991. CO_TL_ENTITY,
  992. INFO_CLASS_PROTOCOL,
  993. INFO_TYPE_CONNECTION,
  994. TCP_SOCKET_WINDOW,
  995. &context->ReceiveBufferSize,
  996. sizeof(context->ReceiveBufferSize),
  997. TRUE
  998. );
  999. if ( err != NO_ERROR ) {
  1000. return err;
  1001. }
  1002. }
  1003. if ( !context->BsdUrgent ) {
  1004. err = SetTdiInformation(
  1005. TdiConnectionObjectHandle,
  1006. CO_TL_ENTITY,
  1007. INFO_CLASS_PROTOCOL,
  1008. INFO_TYPE_CONNECTION,
  1009. TCP_SOCKET_BSDURGENT,
  1010. &false,
  1011. sizeof(false),
  1012. TRUE
  1013. );
  1014. if ( err != NO_ERROR ) {
  1015. return err;
  1016. }
  1017. }
  1018. } else if ( NotifyEvent == WSH_NOTIFY_CLOSE ) {
  1019. //
  1020. // If this is a multipoint leaf, then remove the multipoint target
  1021. // from the session.
  1022. //
  1023. if( context->MultipointLeaf &&
  1024. context->MultipointRootTdiAddressHandle != NULL ) {
  1025. struct ipv6_mreq req;
  1026. req.ipv6mr_multiaddr = context->MultipointTarget;
  1027. req.ipv6mr_interface = 0;
  1028. SetTdiInformation(
  1029. context->MultipointRootTdiAddressHandle,
  1030. CL_TL_ENTITY,
  1031. INFO_CLASS_PROTOCOL,
  1032. INFO_TYPE_ADDRESS_OBJECT,
  1033. AO_OPTION_DEL_MCAST,
  1034. &req,
  1035. sizeof(req),
  1036. TRUE
  1037. );
  1038. }
  1039. //
  1040. // Free the socket context.
  1041. //
  1042. HeapFree(GetProcessHeap(), 0, context );
  1043. } else if ( NotifyEvent == WSH_NOTIFY_CONNECT_ERROR ) {
  1044. //
  1045. // Return WSATRY_AGAIN to get wsock32 to attempt the connect
  1046. // again. Any other return code is ignored.
  1047. //
  1048. } else if ( NotifyEvent == WSH_NOTIFY_BIND ) {
  1049. ULONG true = TRUE;
  1050. if ( context->UnicastHops != DEFAULT_UNICAST_HOPS ) {
  1051. int value = context->UnicastHops;
  1052. err = SetTdiInformation(
  1053. TdiAddressObjectHandle,
  1054. CO_TL_ENTITY,
  1055. INFO_CLASS_PROTOCOL,
  1056. INFO_TYPE_ADDRESS_OBJECT,
  1057. AO_OPTION_TTL,
  1058. &value,
  1059. sizeof(int),
  1060. TRUE
  1061. );
  1062. if ( err != NO_ERROR ) {
  1063. return err;
  1064. }
  1065. }
  1066. if ( context->MulticastHops != DEFAULT_MULTICAST_HOPS ) {
  1067. int value = (int) context->MulticastHops;
  1068. err = SetTdiInformation(
  1069. TdiAddressObjectHandle,
  1070. CO_TL_ENTITY,
  1071. INFO_CLASS_PROTOCOL,
  1072. INFO_TYPE_ADDRESS_OBJECT,
  1073. AO_OPTION_MCASTTTL,
  1074. &value,
  1075. sizeof(int),
  1076. TRUE
  1077. );
  1078. if ( err != NO_ERROR ) {
  1079. return err;
  1080. }
  1081. }
  1082. if ( context->MulticastInterface != DEFAULT_MULTICAST_INTERFACE ) {
  1083. int value = (int) context->MulticastInterface;
  1084. err = SetTdiInformation(
  1085. TdiAddressObjectHandle,
  1086. CO_TL_ENTITY,
  1087. INFO_CLASS_PROTOCOL,
  1088. INFO_TYPE_ADDRESS_OBJECT,
  1089. AO_OPTION_MCASTIF,
  1090. &value,
  1091. sizeof(int),
  1092. TRUE
  1093. );
  1094. if ( err != NO_ERROR ) {
  1095. return err;
  1096. }
  1097. }
  1098. if ( context->MulticastLoopback != DEFAULT_MULTICAST_LOOPBACK ) {
  1099. int value = (int) context->MulticastLoopback;
  1100. err = SetTdiInformation(
  1101. TdiAddressObjectHandle,
  1102. CO_TL_ENTITY,
  1103. INFO_CLASS_PROTOCOL,
  1104. INFO_TYPE_ADDRESS_OBJECT,
  1105. AO_OPTION_MCASTLOOP,
  1106. &value,
  1107. sizeof(int),
  1108. TRUE
  1109. );
  1110. if ( err != NO_ERROR ) {
  1111. return err;
  1112. }
  1113. }
  1114. if ( context->UdpChecksumCoverage != DEFAULT_UDP_CHECKSUM_COVERAGE ) {
  1115. err = SetTdiInformation(
  1116. TdiAddressObjectHandle,
  1117. CL_TL_ENTITY,
  1118. INFO_CLASS_PROTOCOL,
  1119. INFO_TYPE_ADDRESS_OBJECT,
  1120. AO_OPTION_UDP_CHKSUM_COVER,
  1121. &context->UdpChecksumCoverage,
  1122. sizeof context->UdpChecksumCoverage,
  1123. TRUE
  1124. );
  1125. if ( err != NO_ERROR ) {
  1126. return err;
  1127. }
  1128. }
  1129. if ( context->HeaderInclude != DEFAULT_HEADER_INCLUDE ) {
  1130. int value = (int) context->HeaderInclude;
  1131. err = SetTdiInformation(
  1132. TdiAddressObjectHandle,
  1133. CO_TL_ENTITY,
  1134. INFO_CLASS_PROTOCOL,
  1135. INFO_TYPE_ADDRESS_OBJECT,
  1136. AO_OPTION_IP_HDRINCL,
  1137. &value,
  1138. sizeof(int),
  1139. TRUE
  1140. );
  1141. if ( err != NO_ERROR ) {
  1142. return err;
  1143. }
  1144. }
  1145. if ( context->Ipv6PktInfo ) {
  1146. err = SetTdiInformation(
  1147. TdiAddressObjectHandle,
  1148. CO_TL_ENTITY,
  1149. INFO_CLASS_PROTOCOL,
  1150. INFO_TYPE_ADDRESS_OBJECT,
  1151. AO_OPTION_IP_PKTINFO,
  1152. &true,
  1153. sizeof (TRUE),
  1154. TRUE
  1155. );
  1156. if ( err != NO_ERROR ) {
  1157. return err;
  1158. }
  1159. }
  1160. if ( context->Ipv6HopLimit ) {
  1161. err = SetTdiInformation(
  1162. TdiAddressObjectHandle,
  1163. CO_TL_ENTITY,
  1164. INFO_CLASS_PROTOCOL,
  1165. INFO_TYPE_ADDRESS_OBJECT,
  1166. AO_OPTION_RCV_HOPLIMIT,
  1167. &true,
  1168. sizeof (TRUE),
  1169. TRUE
  1170. );
  1171. if ( err != NO_ERROR ) {
  1172. return err;
  1173. }
  1174. }
  1175. if ( context->ProtectionLevel != PROTECTION_LEVEL_DEFAULT ) {
  1176. err = SetTdiInformation(
  1177. TdiAddressObjectHandle,
  1178. CL_TL_ENTITY,
  1179. INFO_CLASS_PROTOCOL,
  1180. INFO_TYPE_ADDRESS_OBJECT,
  1181. AO_OPTION_PROTECT,
  1182. &context->ProtectionLevel,
  1183. sizeof context->ProtectionLevel,
  1184. TRUE
  1185. );
  1186. if ( err != NO_ERROR ) {
  1187. return err;
  1188. }
  1189. }
  1190. } else if ( NotifyEvent == WSH_NOTIFY_LISTEN ) {
  1191. if ( context->ProtectionLevel != PROTECTION_LEVEL_DEFAULT ) {
  1192. err = SetTdiInformation(
  1193. TdiAddressObjectHandle,
  1194. CL_TL_ENTITY,
  1195. INFO_CLASS_PROTOCOL,
  1196. INFO_TYPE_ADDRESS_OBJECT,
  1197. AO_OPTION_PROTECT,
  1198. &context->ProtectionLevel,
  1199. sizeof context->ProtectionLevel,
  1200. TRUE
  1201. );
  1202. if ( err != NO_ERROR ) {
  1203. return err;
  1204. }
  1205. }
  1206. } else {
  1207. return WSAEINVAL;
  1208. }
  1209. return NO_ERROR;
  1210. } // WSHNotify
  1211. INT
  1212. WSHSetSocketInformation (
  1213. IN PVOID HelperDllSocketContext,
  1214. IN SOCKET SocketHandle,
  1215. IN HANDLE TdiAddressObjectHandle,
  1216. IN HANDLE TdiConnectionObjectHandle,
  1217. IN INT Level,
  1218. IN INT OptionName,
  1219. IN PCHAR OptionValue,
  1220. IN INT OptionLength
  1221. )
  1222. /*++
  1223. Routine Description:
  1224. This routine sets information about a socket for those socket
  1225. options supported in this helper DLL. The options supported here
  1226. are SO_KEEPALIVE, SO_DONTROUTE, and TCP_EXPEDITED_1122. This routine is
  1227. called by the winsock DLL when a level/option name combination is
  1228. passed to setsockopt() that the winsock DLL does not understand.
  1229. Arguments:
  1230. HelperDllSocketContext - the context pointer returned from
  1231. WSHOpenSocket().
  1232. SocketHandle - the handle of the socket for which we're getting
  1233. information.
  1234. TdiAddressObjectHandle - the TDI address object of the socket, if
  1235. any. If the socket is not yet bound to an address, then
  1236. it does not have a TDI address object and this parameter
  1237. will be NULL.
  1238. TdiConnectionObjectHandle - the TDI connection object of the socket,
  1239. if any. If the socket is not yet connected, then it does not
  1240. have a TDI connection object and this parameter will be NULL.
  1241. Level - the level parameter passed to setsockopt().
  1242. OptionName - the optname parameter passed to setsockopt().
  1243. OptionValue - the optval parameter passed to setsockopt().
  1244. OptionLength - the optlen parameter passed to setsockopt().
  1245. Return Value:
  1246. INT - a winsock error code indicating the status of the operation, or
  1247. NO_ERROR if the operation succeeded.
  1248. --*/
  1249. {
  1250. PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
  1251. INT error;
  1252. INT optionValue;
  1253. UNREFERENCED_PARAMETER( SocketHandle );
  1254. UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
  1255. UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
  1256. //
  1257. // Check if this is an internal request for context information.
  1258. //
  1259. if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
  1260. //
  1261. // The Windows Sockets DLL is requesting that we set context
  1262. // information for a new socket. If the new socket was
  1263. // accept()'ed, then we have already been notified of the socket
  1264. // and HelperDllSocketContext will be valid. If the new socket
  1265. // was inherited or duped into this process, then this is our
  1266. // first notification of the socket and HelperDllSocketContext
  1267. // will be equal to NULL.
  1268. //
  1269. // Insure that the context information being passed to us is
  1270. // sufficiently large.
  1271. //
  1272. if ( OptionLength < sizeof(*context) ) {
  1273. return WSAEINVAL;
  1274. }
  1275. if ( HelperDllSocketContext == NULL ) {
  1276. //
  1277. // This is our notification that a socket handle was
  1278. // inherited or duped into this process. Allocate a context
  1279. // structure for the new socket.
  1280. //
  1281. context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context) );
  1282. if ( context == NULL ) {
  1283. return WSAENOBUFS;
  1284. }
  1285. //
  1286. // Copy over information into the context block.
  1287. //
  1288. CopyMemory( context, OptionValue, sizeof(*context) );
  1289. //
  1290. // Tell the Windows Sockets DLL where our context information is
  1291. // stored so that it can return the context pointer in future
  1292. // calls.
  1293. //
  1294. *(PWSHTCPIP_SOCKET_CONTEXT *)OptionValue = context;
  1295. return NO_ERROR;
  1296. } else {
  1297. PWSHTCPIP_SOCKET_CONTEXT parentContext;
  1298. INT one = 1;
  1299. //
  1300. // The socket was accept()'ed and it needs to have the same
  1301. // properties as it's parent. The OptionValue buffer
  1302. // contains the context information of this socket's parent.
  1303. //
  1304. parentContext = (PWSHTCPIP_SOCKET_CONTEXT)OptionValue;
  1305. ASSERT( context->AddressFamily == parentContext->AddressFamily );
  1306. ASSERT( context->SocketType == parentContext->SocketType );
  1307. ASSERT( context->Protocol == parentContext->Protocol );
  1308. //
  1309. // Turn on in the child any options that have been set in
  1310. // the parent.
  1311. //
  1312. if ( parentContext->KeepAlive ) {
  1313. error = WSHSetSocketInformation(
  1314. HelperDllSocketContext,
  1315. SocketHandle,
  1316. TdiAddressObjectHandle,
  1317. TdiConnectionObjectHandle,
  1318. SOL_SOCKET,
  1319. SO_KEEPALIVE,
  1320. (PCHAR)&one,
  1321. sizeof(one)
  1322. );
  1323. if ( error != NO_ERROR ) {
  1324. return error;
  1325. }
  1326. }
  1327. if ( parentContext->KeepAliveVals.onoff ) {
  1328. struct tcp_keepalive *optionval;
  1329. //
  1330. // Atempt to turn on or off keepalive sending, as necessary.
  1331. //
  1332. optionval = &parentContext->KeepAliveVals;
  1333. if ( TdiConnectionObjectHandle != NULL ) {
  1334. error = SetTdiInformation(
  1335. TdiConnectionObjectHandle,
  1336. CO_TL_ENTITY,
  1337. INFO_CLASS_PROTOCOL,
  1338. INFO_TYPE_CONNECTION,
  1339. TCP_SOCKET_KEEPALIVE_VALS,
  1340. optionval,
  1341. sizeof(struct tcp_keepalive),
  1342. TRUE
  1343. );
  1344. if ( error != NO_ERROR ) {
  1345. return error;
  1346. }
  1347. }
  1348. //
  1349. // Remember that keepalives are enabled for this socket.
  1350. //
  1351. context->KeepAliveVals = *optionval;
  1352. }
  1353. if ( parentContext->NoDelay ) {
  1354. error = WSHSetSocketInformation(
  1355. HelperDllSocketContext,
  1356. SocketHandle,
  1357. TdiAddressObjectHandle,
  1358. TdiConnectionObjectHandle,
  1359. IPPROTO_TCP,
  1360. TCP_NODELAY,
  1361. (PCHAR)&one,
  1362. sizeof(one)
  1363. );
  1364. if ( error != NO_ERROR ) {
  1365. return error;
  1366. }
  1367. }
  1368. if ( parentContext->ReceiveBufferSize != DEFAULT_RECEIVE_BUFFER_SIZE ) {
  1369. error = WSHSetSocketInformation(
  1370. HelperDllSocketContext,
  1371. SocketHandle,
  1372. TdiAddressObjectHandle,
  1373. TdiConnectionObjectHandle,
  1374. SOL_SOCKET,
  1375. SO_RCVBUF,
  1376. (PCHAR)&parentContext->ReceiveBufferSize,
  1377. sizeof(parentContext->ReceiveBufferSize)
  1378. );
  1379. if ( error != NO_ERROR ) {
  1380. return error;
  1381. }
  1382. }
  1383. if ( !parentContext->BsdUrgent ) {
  1384. error = WSHSetSocketInformation(
  1385. HelperDllSocketContext,
  1386. SocketHandle,
  1387. TdiAddressObjectHandle,
  1388. TdiConnectionObjectHandle,
  1389. IPPROTO_TCP,
  1390. TCP_EXPEDITED_1122,
  1391. (PCHAR)&one,
  1392. sizeof(one)
  1393. );
  1394. if ( error != NO_ERROR ) {
  1395. return error;
  1396. }
  1397. }
  1398. return NO_ERROR;
  1399. }
  1400. }
  1401. //
  1402. // The only other levels we support here are SOL_SOCKET,
  1403. // IPPROTO_TCP, IPPROTO_UDP, and IPPROTO_IPV6.
  1404. //
  1405. if ( Level != SOL_SOCKET &&
  1406. Level != IPPROTO_TCP &&
  1407. Level != IPPROTO_UDP &&
  1408. Level != IPPROTO_IPV6 ) {
  1409. return WSAEINVAL;
  1410. }
  1411. //
  1412. // Make sure that the option length is sufficient.
  1413. //
  1414. if ( OptionLength < sizeof(int) ) {
  1415. return WSAEFAULT;
  1416. }
  1417. optionValue = *(INT UNALIGNED *)OptionValue;
  1418. //
  1419. // Handle TCP-level options.
  1420. //
  1421. if ( Level == IPPROTO_TCP && OptionName == TCP_NODELAY ) {
  1422. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  1423. return WSAENOPROTOOPT;
  1424. }
  1425. //
  1426. // Atempt to turn on or off Nagle's algorithm, as necessary.
  1427. //
  1428. if ( !context->NoDelay && optionValue != 0 ) {
  1429. optionValue = TRUE;
  1430. //
  1431. // NoDelay is currently off and the application wants to
  1432. // turn it on. If the TDI connection object handle is NULL,
  1433. // then the socket is not yet connected. In this case we'll
  1434. // just remember that the no delay option was set and
  1435. // actually turn them on in WSHNotify() after a connect()
  1436. // has completed on the socket.
  1437. //
  1438. if ( TdiConnectionObjectHandle != NULL ) {
  1439. error = SetTdiInformation(
  1440. TdiConnectionObjectHandle,
  1441. CO_TL_ENTITY,
  1442. INFO_CLASS_PROTOCOL,
  1443. INFO_TYPE_CONNECTION,
  1444. TCP_SOCKET_NODELAY,
  1445. &optionValue,
  1446. sizeof(optionValue),
  1447. TRUE
  1448. );
  1449. if ( error != NO_ERROR ) {
  1450. return error;
  1451. }
  1452. }
  1453. //
  1454. // Remember that no delay is enabled for this socket.
  1455. //
  1456. context->NoDelay = TRUE;
  1457. } else if ( context->NoDelay && optionValue == 0 ) {
  1458. //
  1459. // No delay is currently enabled and the application wants
  1460. // to turn it off. If the TDI connection object is NULL,
  1461. // the socket is not yet connected. In this case we'll just
  1462. // remember that nodelay is disabled.
  1463. //
  1464. if ( TdiConnectionObjectHandle != NULL ) {
  1465. error = SetTdiInformation(
  1466. TdiConnectionObjectHandle,
  1467. CO_TL_ENTITY,
  1468. INFO_CLASS_PROTOCOL,
  1469. INFO_TYPE_CONNECTION,
  1470. TCP_SOCKET_NODELAY,
  1471. &optionValue,
  1472. sizeof(optionValue),
  1473. TRUE
  1474. );
  1475. if ( error != NO_ERROR ) {
  1476. return error;
  1477. }
  1478. }
  1479. //
  1480. // Remember that no delay is disabled for this socket.
  1481. //
  1482. context->NoDelay = FALSE;
  1483. }
  1484. return NO_ERROR;
  1485. }
  1486. if ( Level == IPPROTO_TCP && OptionName == TCP_EXPEDITED_1122 ) {
  1487. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  1488. return WSAENOPROTOOPT;
  1489. }
  1490. //
  1491. // Atempt to turn on or off BSD-style urgent data semantics as
  1492. // necessary.
  1493. //
  1494. if ( !context->BsdUrgent && optionValue == 0 ) {
  1495. optionValue = TRUE;
  1496. //
  1497. // BsdUrgent is currently off and the application wants to
  1498. // turn it on. If the TDI connection object handle is NULL,
  1499. // then the socket is not yet connected. In this case we'll
  1500. // just remember that the no delay option was set and
  1501. // actually turn them on in WSHNotify() after a connect()
  1502. // has completed on the socket.
  1503. //
  1504. if ( TdiConnectionObjectHandle != NULL ) {
  1505. error = SetTdiInformation(
  1506. TdiConnectionObjectHandle,
  1507. CO_TL_ENTITY,
  1508. INFO_CLASS_PROTOCOL,
  1509. INFO_TYPE_CONNECTION,
  1510. TCP_SOCKET_BSDURGENT,
  1511. &optionValue,
  1512. sizeof(optionValue),
  1513. TRUE
  1514. );
  1515. if ( error != NO_ERROR ) {
  1516. return error;
  1517. }
  1518. }
  1519. //
  1520. // Remember that no delay is enabled for this socket.
  1521. //
  1522. context->BsdUrgent = TRUE;
  1523. } else if ( context->BsdUrgent && optionValue != 0 ) {
  1524. //
  1525. // No delay is currently enabled and the application wants
  1526. // to turn it off. If the TDI connection object is NULL,
  1527. // the socket is not yet connected. In this case we'll just
  1528. // remember that BsdUrgent is disabled.
  1529. //
  1530. if ( TdiConnectionObjectHandle != NULL ) {
  1531. error = SetTdiInformation(
  1532. TdiConnectionObjectHandle,
  1533. CO_TL_ENTITY,
  1534. INFO_CLASS_PROTOCOL,
  1535. INFO_TYPE_CONNECTION,
  1536. TCP_SOCKET_BSDURGENT,
  1537. &optionValue,
  1538. sizeof(optionValue),
  1539. TRUE
  1540. );
  1541. if ( error != NO_ERROR ) {
  1542. return error;
  1543. }
  1544. }
  1545. //
  1546. // Remember that BSD urgent is disabled for this socket.
  1547. //
  1548. context->BsdUrgent = FALSE;
  1549. }
  1550. return NO_ERROR;
  1551. }
  1552. //
  1553. // Handle UDP-level options.
  1554. //
  1555. if ( Level == IPPROTO_UDP ) {
  1556. //
  1557. // These options are only valid for datagram sockets.
  1558. //
  1559. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1560. return WSAENOPROTOOPT;
  1561. }
  1562. //
  1563. // Note that UDP_NOCHECKSUM is not supported for IPv6.
  1564. //
  1565. switch ( OptionName ) {
  1566. case UDP_CHECKSUM_COVERAGE:
  1567. //
  1568. // The default is 0 which covers the entire datagram.
  1569. // The minimum is the UDP header.
  1570. //
  1571. if ((optionValue != DEFAULT_UDP_CHECKSUM_COVERAGE) &&
  1572. (optionValue < UDP_HEADER_SIZE)) {
  1573. return WSAEINVAL;
  1574. }
  1575. //
  1576. // If we have a TDI address object, set this option to
  1577. // the address object. If we don't have a TDI address
  1578. // object then we'll have to wait until after the socket
  1579. // is bound.
  1580. //
  1581. if ( TdiAddressObjectHandle != NULL ) {
  1582. error = SetTdiInformation(
  1583. TdiAddressObjectHandle,
  1584. CL_TL_ENTITY,
  1585. INFO_CLASS_PROTOCOL,
  1586. INFO_TYPE_ADDRESS_OBJECT,
  1587. AO_OPTION_UDP_CHKSUM_COVER,
  1588. &optionValue,
  1589. sizeof(optionValue),
  1590. TRUE
  1591. );
  1592. if ( error != NO_ERROR ) {
  1593. return error;
  1594. }
  1595. } else {
  1596. return WSAEINVAL;
  1597. }
  1598. context->UdpChecksumCoverage = (USHORT)optionValue;
  1599. break;
  1600. default :
  1601. return WSAEINVAL;
  1602. }
  1603. return NO_ERROR;
  1604. }
  1605. //
  1606. // Handle IP-level options.
  1607. //
  1608. if ( Level == IPPROTO_IPV6 ) {
  1609. //
  1610. // Act based on the specific option.
  1611. //
  1612. switch ( OptionName ) {
  1613. case IPV6_UNICAST_HOPS:
  1614. //
  1615. // An attempt to change the unicast TTL sent on
  1616. // this socket. It is illegal to set this to a value
  1617. // greater than 255.
  1618. //
  1619. if ( optionValue > 255 || optionValue < -1 ) {
  1620. return WSAEINVAL;
  1621. }
  1622. //
  1623. // If we have a TDI address object, set this option to
  1624. // the address object. If we don't have a TDI address
  1625. // object then we'll have to wait until after the socket
  1626. // is bound.
  1627. //
  1628. if ( TdiAddressObjectHandle != NULL ) {
  1629. error = SetTdiInformation(
  1630. TdiAddressObjectHandle,
  1631. CL_TL_ENTITY,
  1632. INFO_CLASS_PROTOCOL,
  1633. INFO_TYPE_ADDRESS_OBJECT,
  1634. AO_OPTION_TTL,
  1635. &optionValue,
  1636. sizeof(optionValue),
  1637. TRUE
  1638. );
  1639. if ( error != NO_ERROR ) {
  1640. return error;
  1641. }
  1642. }
  1643. context->UnicastHops = optionValue;
  1644. return NO_ERROR;
  1645. case IPV6_MULTICAST_HOPS:
  1646. //
  1647. // This option is only valid for datagram sockets.
  1648. //
  1649. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1650. return WSAENOPROTOOPT;
  1651. }
  1652. //
  1653. // An attempt to change the TTL on multicasts sent on
  1654. // this socket. It is illegal to set this to a value
  1655. // greater than 255.
  1656. //
  1657. if ( optionValue > 255 || optionValue < -1 ) {
  1658. return WSAEINVAL;
  1659. }
  1660. //
  1661. // If we have a TDI address object, set this option to
  1662. // the address object. If we don't have a TDI address
  1663. // object then we'll have to wait until after the socket
  1664. // is bound.
  1665. //
  1666. if ( TdiAddressObjectHandle != NULL ) {
  1667. error = SetTdiInformation(
  1668. TdiAddressObjectHandle,
  1669. CL_TL_ENTITY,
  1670. INFO_CLASS_PROTOCOL,
  1671. INFO_TYPE_ADDRESS_OBJECT,
  1672. AO_OPTION_MCASTTTL,
  1673. &optionValue,
  1674. sizeof(optionValue),
  1675. TRUE
  1676. );
  1677. if ( error != NO_ERROR ) {
  1678. return error;
  1679. }
  1680. }
  1681. context->MulticastHops = optionValue;
  1682. return NO_ERROR;
  1683. case IPV6_MULTICAST_IF:
  1684. //
  1685. // This option is only valid for datagram sockets.
  1686. //
  1687. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1688. return WSAENOPROTOOPT;
  1689. }
  1690. //
  1691. // If we have a TDI address object, set this option to
  1692. // the address object. If we don't have a TDI address
  1693. // object then we'll have to wait until after the socket
  1694. // is bound.
  1695. //
  1696. if ( TdiAddressObjectHandle != NULL ) {
  1697. error = SetTdiInformation(
  1698. TdiAddressObjectHandle,
  1699. CL_TL_ENTITY,
  1700. INFO_CLASS_PROTOCOL,
  1701. INFO_TYPE_ADDRESS_OBJECT,
  1702. AO_OPTION_MCASTIF,
  1703. &optionValue,
  1704. sizeof(optionValue),
  1705. TRUE
  1706. );
  1707. if ( error != NO_ERROR ) {
  1708. return error;
  1709. }
  1710. }
  1711. context->MulticastInterface = optionValue;
  1712. return NO_ERROR;
  1713. case IPV6_MULTICAST_LOOP:
  1714. //
  1715. // This option is only valid for datagram sockets.
  1716. //
  1717. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1718. return WSAENOPROTOOPT;
  1719. }
  1720. //
  1721. // This is a boolean option. 0 = false, 1 = true.
  1722. // All other values are illegal.
  1723. //
  1724. if ( optionValue > 1) {
  1725. return WSAEINVAL;
  1726. }
  1727. //
  1728. // If we have a TDI address object, set this option to
  1729. // the address object. If we don't have a TDI address
  1730. // object then we'll have to wait until after the socket
  1731. // is bound.
  1732. //
  1733. if ( TdiAddressObjectHandle != NULL ) {
  1734. error = SetTdiInformation(
  1735. TdiAddressObjectHandle,
  1736. CL_TL_ENTITY,
  1737. INFO_CLASS_PROTOCOL,
  1738. INFO_TYPE_ADDRESS_OBJECT,
  1739. AO_OPTION_MCASTLOOP,
  1740. &optionValue,
  1741. sizeof(optionValue),
  1742. TRUE
  1743. );
  1744. if ( error != NO_ERROR ) {
  1745. return error;
  1746. }
  1747. }
  1748. context->MulticastLoopback = optionValue;
  1749. return NO_ERROR;
  1750. case IPV6_ADD_MEMBERSHIP:
  1751. case IPV6_DROP_MEMBERSHIP:
  1752. //
  1753. // This option is only valid for datagram sockets.
  1754. //
  1755. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1756. return WSAENOPROTOOPT;
  1757. }
  1758. //
  1759. // Make sure that the option buffer is large enough.
  1760. //
  1761. if ( OptionLength < sizeof(struct ipv6_mreq) ) {
  1762. return WSAEINVAL;
  1763. }
  1764. //
  1765. // If we have a TDI address object, set this option to
  1766. // the address object. If we don't have a TDI address
  1767. // object then we'll have to wait until after the socket
  1768. // is bound.
  1769. //
  1770. if ( TdiAddressObjectHandle != NULL ) {
  1771. error = SetTdiInformation(
  1772. TdiAddressObjectHandle,
  1773. CL_TL_ENTITY,
  1774. INFO_CLASS_PROTOCOL,
  1775. INFO_TYPE_ADDRESS_OBJECT,
  1776. OptionName == IPV6_ADD_MEMBERSHIP ?
  1777. AO_OPTION_ADD_MCAST : AO_OPTION_DEL_MCAST,
  1778. OptionValue,
  1779. OptionLength,
  1780. TRUE
  1781. );
  1782. if ( error != NO_ERROR ) {
  1783. return error;
  1784. }
  1785. } else {
  1786. return WSAEINVAL;
  1787. }
  1788. return NO_ERROR;
  1789. case IPV6_HDRINCL:
  1790. //
  1791. // This option is only valid for datagram sockets.
  1792. //
  1793. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1794. return WSAENOPROTOOPT;
  1795. }
  1796. //
  1797. // This is a boolean option. 0 = false, 1 = true.
  1798. // All other values are illegal.
  1799. //
  1800. if ( optionValue > 1) {
  1801. return WSAEINVAL;
  1802. }
  1803. //
  1804. // If we have a TDI address object, set this option to
  1805. // the address object. If we don't have a TDI address
  1806. // object then we'll have to wait until after the socket
  1807. // is bound.
  1808. //
  1809. if ( TdiAddressObjectHandle != NULL ) {
  1810. error = SetTdiInformation(
  1811. TdiAddressObjectHandle,
  1812. CL_TL_ENTITY,
  1813. INFO_CLASS_PROTOCOL,
  1814. INFO_TYPE_ADDRESS_OBJECT,
  1815. AO_OPTION_IP_HDRINCL,
  1816. &optionValue,
  1817. sizeof(optionValue),
  1818. TRUE
  1819. );
  1820. if ( error != NO_ERROR ) {
  1821. return error;
  1822. }
  1823. }
  1824. context->HeaderInclude = optionValue;
  1825. return NO_ERROR;
  1826. case IPV6_PKTINFO:
  1827. //
  1828. // This option is only valid for datagram sockets.
  1829. //
  1830. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1831. return WSAENOPROTOOPT;
  1832. }
  1833. //
  1834. // This is a boolean option. 0 = false, 1 = true.
  1835. // All other values are illegal.
  1836. //
  1837. if ( optionValue > 1) {
  1838. return WSAEINVAL;
  1839. }
  1840. if ( TdiAddressObjectHandle != NULL ) {
  1841. error = SetTdiInformation(
  1842. TdiAddressObjectHandle,
  1843. CL_TL_ENTITY,
  1844. INFO_CLASS_PROTOCOL,
  1845. INFO_TYPE_ADDRESS_OBJECT,
  1846. AO_OPTION_IP_PKTINFO,
  1847. &optionValue,
  1848. sizeof(optionValue),
  1849. TRUE
  1850. );
  1851. if ( error != NO_ERROR ) {
  1852. return error;
  1853. }
  1854. }
  1855. context->Ipv6PktInfo = optionValue;
  1856. return NO_ERROR;
  1857. case IPV6_HOPLIMIT:
  1858. //
  1859. // This option is only valid for datagram sockets.
  1860. //
  1861. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1862. return WSAENOPROTOOPT;
  1863. }
  1864. //
  1865. // This is a boolean option. 0 = false, 1 = true.
  1866. // All other values are illegal.
  1867. //
  1868. if ( optionValue > 1) {
  1869. return WSAEINVAL;
  1870. }
  1871. if ( TdiAddressObjectHandle != NULL ) {
  1872. error = SetTdiInformation(
  1873. TdiAddressObjectHandle,
  1874. CL_TL_ENTITY,
  1875. INFO_CLASS_PROTOCOL,
  1876. INFO_TYPE_ADDRESS_OBJECT,
  1877. AO_OPTION_RCV_HOPLIMIT,
  1878. &optionValue,
  1879. sizeof(optionValue),
  1880. TRUE
  1881. );
  1882. if ( error != NO_ERROR ) {
  1883. return error;
  1884. }
  1885. }
  1886. context->Ipv6HopLimit = optionValue;
  1887. return NO_ERROR;
  1888. case IPV6_PROTECTION_LEVEL:
  1889. if ((optionValue != PROTECTION_LEVEL_RESTRICTED) &&
  1890. (optionValue != PROTECTION_LEVEL_DEFAULT) &&
  1891. (optionValue != PROTECTION_LEVEL_UNRESTRICTED)) {
  1892. return WSAEINVAL;
  1893. }
  1894. if ( TdiAddressObjectHandle != NULL ) {
  1895. error = SetTdiInformation(
  1896. TdiAddressObjectHandle,
  1897. CL_TL_ENTITY,
  1898. INFO_CLASS_PROTOCOL,
  1899. INFO_TYPE_ADDRESS_OBJECT,
  1900. AO_OPTION_PROTECT,
  1901. &optionValue,
  1902. sizeof(optionValue),
  1903. TRUE
  1904. );
  1905. if ( error != NO_ERROR ) {
  1906. return error;
  1907. }
  1908. }
  1909. context->ProtectionLevel = optionValue;
  1910. return NO_ERROR;
  1911. default:
  1912. //
  1913. // No match, fall through.
  1914. //
  1915. break;
  1916. }
  1917. //
  1918. // We don't support this option.
  1919. //
  1920. return WSAENOPROTOOPT;
  1921. }
  1922. //
  1923. // Handle socket-level options.
  1924. //
  1925. switch ( OptionName ) {
  1926. case SO_KEEPALIVE:
  1927. //
  1928. // Atempt to turn on or off keepalive sending, as necessary.
  1929. //
  1930. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  1931. return WSAENOPROTOOPT;
  1932. }
  1933. if ( !context->KeepAlive && optionValue != 0 ) {
  1934. optionValue = TRUE;
  1935. //
  1936. // Keepalives are currently off and the application wants to
  1937. // turn them on. If the TDI connection object handle is
  1938. // NULL, then the socket is not yet connected. In this case
  1939. // we'll just remember that the keepalive option was set and
  1940. // actually turn them on in WSHNotify() after a connect()
  1941. // has completed on the socket.
  1942. //
  1943. if ( TdiConnectionObjectHandle != NULL ) {
  1944. error = SetTdiInformation(
  1945. TdiConnectionObjectHandle,
  1946. CO_TL_ENTITY,
  1947. INFO_CLASS_PROTOCOL,
  1948. INFO_TYPE_CONNECTION,
  1949. TCP_SOCKET_KEEPALIVE,
  1950. &optionValue,
  1951. sizeof(optionValue),
  1952. TRUE
  1953. );
  1954. if ( error != NO_ERROR ) {
  1955. return error;
  1956. }
  1957. }
  1958. //
  1959. // Remember that keepalives are enabled for this socket.
  1960. //
  1961. context->KeepAlive = TRUE;
  1962. } else if ( context->KeepAlive && optionValue == 0 ) {
  1963. //
  1964. // Keepalives are currently enabled and the application
  1965. // wants to turn them off. If the TDI connection object is
  1966. // NULL, the socket is not yet connected. In this case
  1967. // we'll just remember that keepalives are disabled.
  1968. //
  1969. if ( TdiConnectionObjectHandle != NULL ) {
  1970. error = SetTdiInformation(
  1971. TdiConnectionObjectHandle,
  1972. CO_TL_ENTITY,
  1973. INFO_CLASS_PROTOCOL,
  1974. INFO_TYPE_CONNECTION,
  1975. TCP_SOCKET_KEEPALIVE,
  1976. &optionValue,
  1977. sizeof(optionValue),
  1978. TRUE
  1979. );
  1980. if ( error != NO_ERROR ) {
  1981. return error;
  1982. }
  1983. }
  1984. //
  1985. // Remember that keepalives are disabled for this socket.
  1986. //
  1987. context->KeepAlive = FALSE;
  1988. }
  1989. break;
  1990. case SO_RCVBUF:
  1991. //
  1992. // If the receive buffer size is being changed, tell TCP about
  1993. // it. Do nothing if this is a datagram.
  1994. //
  1995. if ( context->ReceiveBufferSize == optionValue ||
  1996. IS_DGRAM_SOCK(context->SocketType)
  1997. ) {
  1998. break;
  1999. }
  2000. if ( TdiConnectionObjectHandle != NULL ) {
  2001. error = SetTdiInformation(
  2002. TdiConnectionObjectHandle,
  2003. CO_TL_ENTITY,
  2004. INFO_CLASS_PROTOCOL,
  2005. INFO_TYPE_CONNECTION,
  2006. TCP_SOCKET_WINDOW,
  2007. &optionValue,
  2008. sizeof(optionValue),
  2009. TRUE
  2010. );
  2011. if ( error != NO_ERROR ) {
  2012. return error;
  2013. }
  2014. }
  2015. context->ReceiveBufferSize = optionValue;
  2016. break;
  2017. default:
  2018. return WSAENOPROTOOPT;
  2019. }
  2020. return NO_ERROR;
  2021. } // WSHSetSocketInformation
  2022. INT
  2023. WSHEnumProtocols (
  2024. IN LPINT lpiProtocols,
  2025. IN LPWSTR lpTransportKeyName,
  2026. IN OUT LPVOID lpProtocolBuffer,
  2027. IN OUT LPDWORD lpdwBufferLength
  2028. )
  2029. /*++
  2030. Routine Description:
  2031. Enumerates the protocols supported by this helper.
  2032. Arguments:
  2033. lpiProtocols - Pointer to a NULL-terminated array of protocol
  2034. identifiers. Only protocols specified in this array will
  2035. be returned by this function. If this pointer is NULL,
  2036. all protocols are returned.
  2037. lpTransportKeyName -
  2038. lpProtocolBuffer - Pointer to a buffer to fill with PROTOCOL_INFO
  2039. structures.
  2040. lpdwBufferLength - Pointer to a variable that, on input, contains
  2041. the size of lpProtocolBuffer. On output, this value will be
  2042. updated with the size of the data actually written to the buffer.
  2043. Return Value:
  2044. INT - The number of protocols returned if successful, -1 if not.
  2045. --*/
  2046. {
  2047. DWORD bytesRequired;
  2048. PPROTOCOL_INFO tcpProtocolInfo;
  2049. PPROTOCOL_INFO udpProtocolInfo;
  2050. BOOL useTcp = FALSE;
  2051. BOOL useUdp = FALSE;
  2052. DWORD i;
  2053. lpTransportKeyName; // Avoid compiler warnings.
  2054. //
  2055. // Make sure that the caller cares about TCP and/or UDP.
  2056. //
  2057. if ( ARGUMENT_PRESENT( lpiProtocols ) ) {
  2058. for ( i = 0; lpiProtocols[i] != 0; i++ ) {
  2059. if ( lpiProtocols[i] == IPPROTO_TCP ) {
  2060. useTcp = TRUE;
  2061. }
  2062. if ( lpiProtocols[i] == IPPROTO_UDP ) {
  2063. useUdp = TRUE;
  2064. }
  2065. }
  2066. } else {
  2067. useTcp = TRUE;
  2068. useUdp = TRUE;
  2069. }
  2070. if ( !useTcp && !useUdp ) {
  2071. *lpdwBufferLength = 0;
  2072. return 0;
  2073. }
  2074. //
  2075. // Make sure that the caller has specified a sufficiently large
  2076. // buffer.
  2077. //
  2078. bytesRequired = (DWORD)((sizeof(PROTOCOL_INFO) * 2) +
  2079. ( (wcslen( TCP_NAME ) + 1) * sizeof(WCHAR)) +
  2080. ( (wcslen( UDP_NAME ) + 1) * sizeof(WCHAR)));
  2081. if ( bytesRequired > *lpdwBufferLength ) {
  2082. *lpdwBufferLength = bytesRequired;
  2083. return -1;
  2084. }
  2085. //
  2086. // Fill in TCP info, if requested.
  2087. //
  2088. if ( useTcp ) {
  2089. tcpProtocolInfo = lpProtocolBuffer;
  2090. tcpProtocolInfo->dwServiceFlags = XP_GUARANTEED_DELIVERY |
  2091. XP_GUARANTEED_ORDER |
  2092. XP_GRACEFUL_CLOSE |
  2093. XP_EXPEDITED_DATA |
  2094. XP_FRAGMENTATION;
  2095. tcpProtocolInfo->iAddressFamily = AF_INET6;
  2096. tcpProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_IN6);
  2097. tcpProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_IN6);
  2098. tcpProtocolInfo->iSocketType = SOCK_STREAM;
  2099. tcpProtocolInfo->iProtocol = IPPROTO_TCP;
  2100. tcpProtocolInfo->dwMessageSize = 0;
  2101. tcpProtocolInfo->lpProtocol = (LPWSTR)
  2102. ( (PBYTE)lpProtocolBuffer + *lpdwBufferLength -
  2103. ( (wcslen( TCP_NAME ) + 1) * sizeof(WCHAR) ) );
  2104. wcscpy( tcpProtocolInfo->lpProtocol, TCP_NAME );
  2105. udpProtocolInfo = tcpProtocolInfo + 1;
  2106. udpProtocolInfo->lpProtocol = (LPWSTR)
  2107. ( (PBYTE)tcpProtocolInfo->lpProtocol -
  2108. ( (wcslen( UDP_NAME ) + 1) * sizeof(WCHAR) ) );
  2109. } else {
  2110. udpProtocolInfo = lpProtocolBuffer;
  2111. udpProtocolInfo->lpProtocol = (LPWSTR)
  2112. ( (PBYTE)lpProtocolBuffer + *lpdwBufferLength -
  2113. ( (wcslen( UDP_NAME ) + 1) * sizeof(WCHAR) ) );
  2114. }
  2115. //
  2116. // Fill in UDP info, if requested.
  2117. //
  2118. if ( useUdp ) {
  2119. udpProtocolInfo->dwServiceFlags = XP_CONNECTIONLESS |
  2120. XP_MESSAGE_ORIENTED |
  2121. XP_SUPPORTS_BROADCAST |
  2122. XP_SUPPORTS_MULTICAST |
  2123. XP_FRAGMENTATION;
  2124. udpProtocolInfo->iAddressFamily = AF_INET6;
  2125. udpProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_IN6);
  2126. udpProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_IN6);
  2127. udpProtocolInfo->iSocketType = SOCK_DGRAM;
  2128. udpProtocolInfo->iProtocol = IPPROTO_UDP;
  2129. udpProtocolInfo->dwMessageSize = UDP_MESSAGE_SIZE;
  2130. wcscpy( udpProtocolInfo->lpProtocol, UDP_NAME );
  2131. }
  2132. *lpdwBufferLength = bytesRequired;
  2133. return (useTcp && useUdp) ? 2 : 1;
  2134. } // WSHEnumProtocols
  2135. BOOLEAN
  2136. IsTripleInList (
  2137. IN PMAPPING_TRIPLE List,
  2138. IN ULONG ListLength,
  2139. IN INT AddressFamily,
  2140. IN INT SocketType,
  2141. IN INT Protocol
  2142. )
  2143. /*++
  2144. Routine Description:
  2145. Determines whether the specified triple has an exact match in the
  2146. list of triples.
  2147. Arguments:
  2148. List - a list of triples (address family/socket type/protocol) to
  2149. search.
  2150. ListLength - the number of triples in the list.
  2151. AddressFamily - the address family to look for in the list.
  2152. SocketType - the socket type to look for in the list.
  2153. Protocol - the protocol to look for in the list.
  2154. Return Value:
  2155. BOOLEAN - TRUE if the triple was found in the list, false if not.
  2156. --*/
  2157. {
  2158. ULONG i;
  2159. //
  2160. // Walk through the list searching for an exact match.
  2161. //
  2162. for ( i = 0; i < ListLength; i++ ) {
  2163. //
  2164. // If all three elements of the triple match, return indicating
  2165. // that the triple did exist in the list.
  2166. //
  2167. if ( AddressFamily == List[i].AddressFamily &&
  2168. SocketType == List[i].SocketType &&
  2169. ( (Protocol == List[i].Protocol) || (SocketType == SOCK_RAW) )
  2170. ) {
  2171. return TRUE;
  2172. }
  2173. }
  2174. //
  2175. // The triple was not found in the list.
  2176. //
  2177. return FALSE;
  2178. } // IsTripleInList
  2179. INT
  2180. NtStatusToSocketError (
  2181. IN NTSTATUS Status
  2182. )
  2183. {
  2184. switch ( Status ) {
  2185. case STATUS_PENDING:
  2186. ASSERT (FALSE);
  2187. return WSASYSCALLFAILURE;
  2188. case STATUS_INVALID_HANDLE:
  2189. case STATUS_OBJECT_TYPE_MISMATCH:
  2190. return WSAENOTSOCK;
  2191. case STATUS_INSUFFICIENT_RESOURCES:
  2192. case STATUS_PAGEFILE_QUOTA:
  2193. case STATUS_COMMITMENT_LIMIT:
  2194. case STATUS_WORKING_SET_QUOTA:
  2195. case STATUS_NO_MEMORY:
  2196. case STATUS_CONFLICTING_ADDRESSES:
  2197. case STATUS_QUOTA_EXCEEDED:
  2198. case STATUS_TOO_MANY_PAGING_FILES:
  2199. case STATUS_REMOTE_RESOURCES:
  2200. case STATUS_TOO_MANY_ADDRESSES:
  2201. return WSAENOBUFS;
  2202. case STATUS_SHARING_VIOLATION:
  2203. case STATUS_ADDRESS_ALREADY_EXISTS:
  2204. return WSAEADDRINUSE;
  2205. case STATUS_LINK_TIMEOUT:
  2206. case STATUS_IO_TIMEOUT:
  2207. case STATUS_TIMEOUT:
  2208. return WSAETIMEDOUT;
  2209. case STATUS_GRACEFUL_DISCONNECT:
  2210. return WSAEDISCON;
  2211. case STATUS_REMOTE_DISCONNECT:
  2212. case STATUS_CONNECTION_RESET:
  2213. case STATUS_LINK_FAILED:
  2214. case STATUS_CONNECTION_DISCONNECTED:
  2215. case STATUS_PORT_UNREACHABLE:
  2216. return WSAECONNRESET;
  2217. case STATUS_LOCAL_DISCONNECT:
  2218. case STATUS_TRANSACTION_ABORTED:
  2219. case STATUS_CONNECTION_ABORTED:
  2220. return WSAECONNABORTED;
  2221. case STATUS_BAD_NETWORK_PATH:
  2222. case STATUS_NETWORK_UNREACHABLE:
  2223. case STATUS_PROTOCOL_UNREACHABLE:
  2224. return WSAENETUNREACH;
  2225. case STATUS_HOST_UNREACHABLE:
  2226. return WSAEHOSTUNREACH;
  2227. case STATUS_CANCELLED:
  2228. case STATUS_REQUEST_ABORTED:
  2229. return WSAEINTR;
  2230. case STATUS_BUFFER_OVERFLOW:
  2231. case STATUS_INVALID_BUFFER_SIZE:
  2232. return WSAEMSGSIZE;
  2233. case STATUS_BUFFER_TOO_SMALL:
  2234. case STATUS_ACCESS_VIOLATION:
  2235. return WSAEFAULT;
  2236. case STATUS_DEVICE_NOT_READY:
  2237. case STATUS_REQUEST_NOT_ACCEPTED:
  2238. return WSAEWOULDBLOCK;
  2239. case STATUS_INVALID_NETWORK_RESPONSE:
  2240. case STATUS_NETWORK_BUSY:
  2241. case STATUS_NO_SUCH_DEVICE:
  2242. case STATUS_NO_SUCH_FILE:
  2243. case STATUS_OBJECT_PATH_NOT_FOUND:
  2244. case STATUS_OBJECT_NAME_NOT_FOUND:
  2245. case STATUS_UNEXPECTED_NETWORK_ERROR:
  2246. return WSAENETDOWN;
  2247. case STATUS_INVALID_CONNECTION:
  2248. return WSAENOTCONN;
  2249. case STATUS_REMOTE_NOT_LISTENING:
  2250. case STATUS_CONNECTION_REFUSED:
  2251. return WSAECONNREFUSED;
  2252. case STATUS_PIPE_DISCONNECTED:
  2253. return WSAESHUTDOWN;
  2254. case STATUS_INVALID_ADDRESS:
  2255. case STATUS_INVALID_ADDRESS_COMPONENT:
  2256. return WSAEADDRNOTAVAIL;
  2257. case STATUS_NOT_SUPPORTED:
  2258. case STATUS_NOT_IMPLEMENTED:
  2259. return WSAEOPNOTSUPP;
  2260. case STATUS_ACCESS_DENIED:
  2261. return WSAEACCES;
  2262. default:
  2263. if ( NT_SUCCESS(Status) ) {
  2264. #if DBG
  2265. DbgPrint ("SockNtStatusToSocketError: success status %lx "
  2266. "not mapped\n", Status );
  2267. #endif
  2268. return NO_ERROR;
  2269. }
  2270. #if DBG
  2271. DbgPrint ("SockNtStatusToSocketError: unable to map 0x%lX, returning\n",
  2272. Status );
  2273. #endif
  2274. return WSAENOBUFS;
  2275. case STATUS_UNSUCCESSFUL:
  2276. case STATUS_INVALID_PARAMETER:
  2277. case STATUS_ADDRESS_CLOSED:
  2278. case STATUS_CONNECTION_INVALID:
  2279. case STATUS_ADDRESS_ALREADY_ASSOCIATED:
  2280. case STATUS_ADDRESS_NOT_ASSOCIATED:
  2281. case STATUS_CONNECTION_ACTIVE:
  2282. case STATUS_INVALID_DEVICE_STATE:
  2283. case STATUS_INVALID_DEVICE_REQUEST:
  2284. return WSAEINVAL;
  2285. }
  2286. } // NtStatusToSocketError
  2287. INT
  2288. SetTdiInformation (
  2289. IN HANDLE TdiConnectionObjectHandle,
  2290. IN ULONG Entity,
  2291. IN ULONG Class,
  2292. IN ULONG Type,
  2293. IN ULONG Id,
  2294. IN PVOID Value,
  2295. IN ULONG ValueLength,
  2296. IN BOOLEAN WaitForCompletion
  2297. )
  2298. /*++
  2299. Routine Description:
  2300. Performs a TDI action to the TCP/IP driver. A TDI action translates
  2301. into a streams T_OPTMGMT_REQ.
  2302. Arguments:
  2303. TdiConnectionObjectHandle - a TDI connection object on which to perform
  2304. the TDI action.
  2305. Entity - value to put in the tei_entity field of the TDIObjectID
  2306. structure.
  2307. Class - value to put in the toi_class field of the TDIObjectID
  2308. structure.
  2309. Type - value to put in the toi_type field of the TDIObjectID
  2310. structure.
  2311. Id - value to put in the toi_id field of the TDIObjectID structure.
  2312. Value - a pointer to a buffer to set as the information.
  2313. ValueLength - the length of the buffer.
  2314. WaitForCompletion - TRUE if we should wait for the TDI action to
  2315. complete, FALSE if we're at APC level and cannot do a wait.
  2316. Return Value:
  2317. INT - NO_ERROR, or a Windows Sockets error code.
  2318. --*/
  2319. {
  2320. NTSTATUS status;
  2321. PTCP_REQUEST_SET_INFORMATION_EX setInfoEx;
  2322. PIO_STATUS_BLOCK ioStatusBlock;
  2323. PVOID completionApc;
  2324. PVOID apcContext;
  2325. //
  2326. // Allocate space to hold the TDI set information buffers and the IO
  2327. // status block. These cannot be stack variables in case we must
  2328. // return before the operation is complete.
  2329. //
  2330. ioStatusBlock = HeapAlloc(GetProcessHeap(), 0,
  2331. sizeof(*ioStatusBlock) + sizeof(*setInfoEx) +
  2332. ValueLength
  2333. );
  2334. if ( ioStatusBlock == NULL ) {
  2335. return WSAENOBUFS;
  2336. }
  2337. //
  2338. // Initialize the TDI information buffers.
  2339. //
  2340. setInfoEx = (PTCP_REQUEST_SET_INFORMATION_EX)(ioStatusBlock + 1);
  2341. setInfoEx->ID.toi_entity.tei_entity = Entity;
  2342. setInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
  2343. setInfoEx->ID.toi_class = Class;
  2344. setInfoEx->ID.toi_type = Type;
  2345. setInfoEx->ID.toi_id = Id;
  2346. CopyMemory( setInfoEx->Buffer, Value, ValueLength );
  2347. setInfoEx->BufferSize = ValueLength;
  2348. //
  2349. // If we need to wait for completion of the operation, create an
  2350. // event to wait on. If we can't wait for completion because we
  2351. // are being called at APC level, we'll use an APC routine to
  2352. // free the heap we allocated above.
  2353. //
  2354. if ( WaitForCompletion ) {
  2355. completionApc = NULL;
  2356. apcContext = NULL;
  2357. } else {
  2358. completionApc = CompleteTdiActionApc;
  2359. apcContext = ioStatusBlock;
  2360. }
  2361. //
  2362. // Make the actual TDI action call. The Streams TDI mapper will
  2363. // translate this into a TPI option management request for us and
  2364. // give it to TCP/IP.
  2365. //
  2366. status = NtDeviceIoControlFile(
  2367. TdiConnectionObjectHandle,
  2368. NULL,
  2369. completionApc,
  2370. apcContext,
  2371. ioStatusBlock,
  2372. IOCTL_TCP_WSH_SET_INFORMATION_EX,
  2373. setInfoEx,
  2374. sizeof(*setInfoEx) + ValueLength,
  2375. NULL,
  2376. 0
  2377. );
  2378. //
  2379. // If the call pended and we were supposed to wait for completion,
  2380. // then wait.
  2381. //
  2382. if ( status == STATUS_PENDING && WaitForCompletion ) {
  2383. while (ioStatusBlock->Status==STATUS_PENDING) {
  2384. LARGE_INTEGER timeout;
  2385. //
  2386. // Wait one millisecond
  2387. //
  2388. timeout.QuadPart = -1i64*1000i64*10i64;
  2389. NtDelayExecution (FALSE, &timeout);
  2390. }
  2391. status = ioStatusBlock->Status;
  2392. }
  2393. if ( WaitForCompletion || !NT_SUCCESS(status) ) {
  2394. RtlFreeHeap( RtlProcessHeap( ), 0, ioStatusBlock );
  2395. }
  2396. if (NT_SUCCESS (status)) {
  2397. return NO_ERROR;
  2398. }
  2399. else {
  2400. return NtStatusToSocketError (status);
  2401. }
  2402. } // SetTdiInformation
  2403. VOID
  2404. CompleteTdiActionApc (
  2405. IN PVOID ApcContext,
  2406. IN PIO_STATUS_BLOCK IoStatusBlock
  2407. )
  2408. {
  2409. UNREFERENCED_PARAMETER(IoStatusBlock);
  2410. //
  2411. // Just free the heap we allocated to hold the IO status block and
  2412. // the TDI action buffer. There is nothing we can do if the call
  2413. // failed.
  2414. //
  2415. HeapFree(GetProcessHeap(), 0, ApcContext );
  2416. } // CompleteTdiActionApc
  2417. INT
  2418. WINAPI
  2419. WSHJoinLeaf (
  2420. IN PVOID HelperDllSocketContext,
  2421. IN SOCKET SocketHandle,
  2422. IN HANDLE TdiAddressObjectHandle,
  2423. IN HANDLE TdiConnectionObjectHandle,
  2424. IN PVOID LeafHelperDllSocketContext,
  2425. IN SOCKET LeafSocketHandle,
  2426. IN PSOCKADDR Sockaddr,
  2427. IN DWORD SockaddrLength,
  2428. IN LPWSABUF CallerData,
  2429. IN LPWSABUF CalleeData,
  2430. IN LPQOS SocketQOS,
  2431. IN LPQOS GroupQOS,
  2432. IN DWORD Flags
  2433. )
  2434. /*++
  2435. Routine Description:
  2436. Performs the protocol-dependent portion of creating a multicast
  2437. socket.
  2438. Arguments:
  2439. The following four parameters correspond to the socket passed into
  2440. the WSAJoinLeaf() API:
  2441. HelperDllSocketContext - The context pointer returned from
  2442. WSHOpenSocket().
  2443. SocketHandle - The handle of the socket used to establish the
  2444. multicast "session".
  2445. TdiAddressObjectHandle - The TDI address object of the socket, if
  2446. any. If the socket is not yet bound to an address, then
  2447. it does not have a TDI address object and this parameter
  2448. will be NULL.
  2449. TdiConnectionObjectHandle - The TDI connection object of the socket,
  2450. if any. If the socket is not yet connected, then it does not
  2451. have a TDI connection object and this parameter will be NULL.
  2452. The next two parameters correspond to the newly created socket that
  2453. identifies the multicast "session":
  2454. LeafHelperDllSocketContext - The context pointer returned from
  2455. WSHOpenSocket().
  2456. LeafSocketHandle - The handle of the socket that identifies the
  2457. multicast "session".
  2458. Sockaddr - The name of the peer to which the socket is to be joined.
  2459. SockaddrLength - The length of Sockaddr.
  2460. CallerData - Pointer to user data to be transferred to the peer
  2461. during multipoint session establishment.
  2462. CalleeData - Pointer to user data to be transferred back from
  2463. the peer during multipoint session establishment.
  2464. SocketQOS - Pointer to the flowspecs for SocketHandle, one in each
  2465. direction.
  2466. GroupQOS - Pointer to the flowspecs for the socket group, if any.
  2467. Flags - Flags to indicate if the socket is acting as sender,
  2468. receiver, or both.
  2469. Return Value:
  2470. INT - 0 if successful, a WinSock error code if not.
  2471. --*/
  2472. {
  2473. struct ipv6_mreq req;
  2474. INT err;
  2475. PWSHTCPIP_SOCKET_CONTEXT context;
  2476. UNREFERENCED_PARAMETER(TdiConnectionObjectHandle);
  2477. UNREFERENCED_PARAMETER(Flags);
  2478. //
  2479. // Quick sanity checks.
  2480. //
  2481. if( HelperDllSocketContext == NULL ||
  2482. SocketHandle == INVALID_SOCKET ||
  2483. TdiAddressObjectHandle == NULL ||
  2484. Sockaddr == NULL ||
  2485. Sockaddr->sa_family != AF_INET6 ||
  2486. SockaddrLength < sizeof(SOCKADDR_IN6) ||
  2487. ( CallerData != NULL && CallerData->len > 0 ) ||
  2488. ( CalleeData != NULL && CalleeData->len > 0 ) ||
  2489. SocketQOS != NULL ||
  2490. GroupQOS != NULL ) {
  2491. return WSAEINVAL;
  2492. }
  2493. //
  2494. // Add membership.
  2495. //
  2496. req.ipv6mr_multiaddr = ((LPSOCKADDR_IN6)Sockaddr)->sin6_addr;
  2497. req.ipv6mr_interface = 0;
  2498. err = SetTdiInformation(
  2499. TdiAddressObjectHandle,
  2500. CL_TL_ENTITY,
  2501. INFO_CLASS_PROTOCOL,
  2502. INFO_TYPE_ADDRESS_OBJECT,
  2503. AO_OPTION_ADD_MCAST,
  2504. &req,
  2505. sizeof(req),
  2506. TRUE
  2507. );
  2508. if( err == NO_ERROR ) {
  2509. //
  2510. // On NT4, we are called with a leaf socket.
  2511. // On NT5, the leaf socket is null.
  2512. //
  2513. if ((LeafHelperDllSocketContext != NULL) &&
  2514. (LeafSocketHandle != INVALID_SOCKET)) {
  2515. //
  2516. // Record this fact in the leaf socket so we can drop membership
  2517. // when the leaf socket is closed.
  2518. //
  2519. context = LeafHelperDllSocketContext;
  2520. context->MultipointLeaf = TRUE;
  2521. context->MultipointTarget = req.ipv6mr_multiaddr;
  2522. context->MultipointRootTdiAddressHandle = TdiAddressObjectHandle;
  2523. }
  2524. }
  2525. return err;
  2526. } // WSHJoinLeaf
  2527. INT
  2528. WINAPI
  2529. WSHGetWSAProtocolInfo (
  2530. IN LPWSTR ProviderName,
  2531. OUT LPWSAPROTOCOL_INFOW * ProtocolInfo,
  2532. OUT LPDWORD ProtocolInfoEntries
  2533. )
  2534. /*++
  2535. Routine Description:
  2536. Retrieves a pointer to the WSAPROTOCOL_INFOW structure(s) describing
  2537. the protocol(s) supported by this helper.
  2538. Arguments:
  2539. ProviderName - Contains the name of the provider, such as "TcpIp".
  2540. ProtocolInfo - Receives a pointer to the WSAPROTOCOL_INFOW array.
  2541. ProtocolInfoEntries - Receives the number of entries in the array.
  2542. Return Value:
  2543. INT - 0 if successful, WinSock error code if not.
  2544. --*/
  2545. {
  2546. if( ProviderName == NULL ||
  2547. ProtocolInfo == NULL ||
  2548. ProtocolInfoEntries == NULL ) {
  2549. return WSAEFAULT;
  2550. }
  2551. if( _wcsicmp( ProviderName, TCPIPV6_NAME ) == 0 ) {
  2552. *ProtocolInfo = Winsock2Protocols;
  2553. *ProtocolInfoEntries = NUM_WINSOCK2_PROTOCOLS;
  2554. return NO_ERROR;
  2555. }
  2556. return WSAEINVAL;
  2557. } // WSHGetWSAProtocolInfo
  2558. INT
  2559. WINAPI
  2560. WSHAddressToString (
  2561. IN LPSOCKADDR Address,
  2562. IN INT AddressLength,
  2563. IN LPWSAPROTOCOL_INFOW ProtocolInfo,
  2564. OUT LPWSTR AddressString,
  2565. IN OUT LPDWORD AddressStringLength
  2566. )
  2567. /*++
  2568. Routine Description:
  2569. Converts a SOCKADDR to a human-readable form.
  2570. Arguments:
  2571. Address - The SOCKADDR to convert.
  2572. AddressLength - The length of Address.
  2573. ProtocolInfo - The WSAPROTOCOL_INFOW for a particular provider.
  2574. AddressString - Receives the formatted address string.
  2575. AddressStringLength - On input, contains the length of AddressString.
  2576. On output, contains the number of characters actually written
  2577. to AddressString.
  2578. Return Value:
  2579. INT - 0 if successful, WinSock error code if not.
  2580. --*/
  2581. {
  2582. PSOCKADDR_IN6 addr;
  2583. UNREFERENCED_PARAMETER(ProtocolInfo);
  2584. //
  2585. // Quick sanity checks.
  2586. //
  2587. if ((Address == NULL) ||
  2588. (AddressLength < sizeof(SOCKADDR_IN6)) ||
  2589. (AddressString == NULL) ||
  2590. (AddressStringLength == NULL)) {
  2591. return WSAEFAULT;
  2592. }
  2593. addr = (PSOCKADDR_IN6)Address;
  2594. if (addr->sin6_family != AF_INET6) {
  2595. return WSAEINVAL;
  2596. }
  2597. if (!NT_SUCCESS(RtlIpv6AddressToStringExW(&addr->sin6_addr,
  2598. addr->sin6_scope_id,
  2599. addr->sin6_port,
  2600. AddressString,
  2601. AddressStringLength))) {
  2602. return WSAEFAULT;
  2603. }
  2604. return NO_ERROR;
  2605. } // WSHAddressToString
  2606. INT
  2607. WINAPI
  2608. WSHStringToAddress (
  2609. IN LPWSTR AddressString,
  2610. IN DWORD AddressFamily,
  2611. IN LPWSAPROTOCOL_INFOW ProtocolInfo,
  2612. OUT LPSOCKADDR Address,
  2613. IN OUT LPINT AddressLength
  2614. )
  2615. /*++
  2616. Routine Description:
  2617. Fills in a SOCKADDR structure by parsing a human-readable string.
  2618. The syntax is address%scope-id or [address%scope-id]:port, where
  2619. the scope-id and port are optional.
  2620. Note that since the IPv6 address format uses a varying number
  2621. of ':' characters, the IPv4 convention of address:port cannot
  2622. be supported without the braces.
  2623. Arguments:
  2624. AddressString - Points to the zero-terminated human-readable string.
  2625. AddressFamily - The address family to which the string belongs.
  2626. ProtocolInfo - The WSAPROTOCOL_INFOW for a particular provider.
  2627. Address - Receives the SOCKADDR structure.
  2628. AddressLength - On input, contains the length of Address. On output,
  2629. contains the number of bytes actually written to Address.
  2630. Return Value:
  2631. INT - 0 if successful, WinSock error code if not.
  2632. --*/
  2633. {
  2634. PSOCKADDR_IN6 addr;
  2635. UNREFERENCED_PARAMETER(ProtocolInfo);
  2636. //
  2637. // Quick sanity checks.
  2638. //
  2639. if ((AddressString == NULL) ||
  2640. (Address == NULL) ||
  2641. (AddressLength == NULL) ||
  2642. (*AddressLength < sizeof(SOCKADDR_IN6))) {
  2643. return WSAEFAULT;
  2644. }
  2645. if (AddressFamily != AF_INET6) {
  2646. return WSAEINVAL;
  2647. }
  2648. addr = (PSOCKADDR_IN6)Address;
  2649. ZeroMemory(Address, sizeof(SOCKADDR_IN6));
  2650. if (!NT_SUCCESS(RtlIpv6StringToAddressExW(AddressString,
  2651. &addr->sin6_addr,
  2652. &addr->sin6_scope_id,
  2653. &addr->sin6_port))) {
  2654. return WSAEINVAL;
  2655. }
  2656. addr->sin6_family = AF_INET6;
  2657. *AddressLength = sizeof(SOCKADDR_IN6);
  2658. return NO_ERROR;
  2659. } // WSHStringToAddress
  2660. INT
  2661. WINAPI
  2662. WSHGetProviderGuid (
  2663. IN LPWSTR ProviderName,
  2664. OUT LPGUID ProviderGuid
  2665. )
  2666. /*++
  2667. Routine Description:
  2668. Returns the GUID identifying the protocols supported by this helper.
  2669. Arguments:
  2670. ProviderName - Contains the name of the provider, such as "TcpIp".
  2671. ProviderGuid - Points to a buffer that receives the provider's GUID.
  2672. Return Value:
  2673. INT - 0 if successful, WinSock error code if not.
  2674. --*/
  2675. {
  2676. if( ProviderName == NULL ||
  2677. ProviderGuid == NULL ) {
  2678. return WSAEFAULT;
  2679. }
  2680. if( _wcsicmp( ProviderName, TCPIPV6_NAME ) == 0 ) {
  2681. CopyMemory(
  2682. ProviderGuid,
  2683. &IPv6ProviderGuid,
  2684. sizeof(GUID)
  2685. );
  2686. return NO_ERROR;
  2687. }
  2688. return WSAEINVAL;
  2689. } // WSHGetProviderGuid
  2690. INT
  2691. SortIPv6Addrs(
  2692. IN LPVOID InputBuffer,
  2693. IN DWORD InputBufferLength,
  2694. IN LPVOID OutputBuffer,
  2695. IN DWORD OutputBufferLength,
  2696. OUT LPDWORD NumberOfBytesReturned)
  2697. {
  2698. PBYTE pBuff = NULL;
  2699. PBYTE pDupIn = NULL;
  2700. TDI_ADDRESS_IP6 *pTDI;
  2701. SOCKET_ADDRESS_LIST *pIn = (SOCKET_ADDRESS_LIST *)InputBuffer;
  2702. SOCKET_ADDRESS_LIST *pOut = (SOCKET_ADDRESS_LIST *)OutputBuffer;
  2703. SOCKADDR_IN6 *pAddr6;
  2704. HANDLE Handle = INVALID_HANDLE_VALUE;
  2705. DWORD *pKey, i, NumAddrsIn;
  2706. DWORD NumAddrsOut, InListLength;
  2707. u_long AddrListBytes;
  2708. int rc;
  2709. INT err = 0;
  2710. *NumberOfBytesReturned = 0;
  2711. // Make sure input buffer is big enough to contain a list
  2712. if (InputBufferLength < sizeof(SOCKET_ADDRESS_LIST)) {
  2713. return WSAEINVAL;
  2714. }
  2715. NumAddrsIn = pIn->iAddressCount;
  2716. // Make sure input buffer is actually big enough to hold the whole list
  2717. InListLength = (DWORD)FIELD_OFFSET(SOCKET_ADDRESS_LIST,Address[NumAddrsIn]);
  2718. if (InputBufferLength < InListLength) {
  2719. return WSAEINVAL;
  2720. }
  2721. //
  2722. // Open a handle to the IPv6 device.
  2723. //
  2724. Handle = CreateFileW(WIN_IPV6_DEVICE_NAME,
  2725. 0, // access mode
  2726. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2727. NULL, // security attributes
  2728. OPEN_EXISTING,
  2729. 0, // flags & attributes
  2730. NULL); // template file
  2731. if (Handle == INVALID_HANDLE_VALUE) {
  2732. //
  2733. // We can not sort the list.
  2734. //
  2735. err = WSASERVICE_NOT_FOUND;
  2736. goto Done;
  2737. }
  2738. //
  2739. // Convert input to TDI list,
  2740. // with extra space for an array of indices
  2741. // following the array of addresses.
  2742. //
  2743. AddrListBytes = ALIGN_UP(NumAddrsIn * sizeof(TDI_ADDRESS_IP6), DWORD);
  2744. AddrListBytes += NumAddrsIn * sizeof(DWORD);
  2745. pBuff = HeapAlloc(GetProcessHeap(), 0, AddrListBytes);
  2746. if (!pBuff) {
  2747. err = WSAENOBUFS;
  2748. goto Done;
  2749. }
  2750. pTDI = (TDI_ADDRESS_IP6 *)pBuff;
  2751. for (i=0; i<NumAddrsIn; i++) {
  2752. pAddr6 = (LPSOCKADDR_IN6)(pIn->Address[i].lpSockaddr);
  2753. // Make sure it's an IPv6 sockaddr
  2754. if (pAddr6->sin6_family != AF_INET6) {
  2755. err = WSAEINVAL;
  2756. break;
  2757. }
  2758. memcpy(&pTDI[i], &pAddr6->sin6_port, sizeof(TDI_ADDRESS_IP6));
  2759. }
  2760. if (err)
  2761. goto Done;
  2762. rc = DeviceIoControl(Handle, IOCTL_IPV6_SORT_DEST_ADDRS,
  2763. pBuff, NumAddrsIn * sizeof(TDI_ADDRESS_IP6),
  2764. pBuff, AddrListBytes,
  2765. &AddrListBytes, NULL);
  2766. if (! rc) {
  2767. //
  2768. // We can not sort the list.
  2769. //
  2770. err = GetLastError();
  2771. goto Done;
  2772. }
  2773. //
  2774. // There might be fewer addresses now.
  2775. //
  2776. NumAddrsOut = (AddrListBytes - NumAddrsIn * sizeof(TDI_ADDRESS_IP6))
  2777. / sizeof(DWORD);
  2778. //
  2779. // The key array starts after the address array.
  2780. //
  2781. pKey = (PDWORD)ALIGN_UP_POINTER(pBuff +
  2782. NumAddrsIn * sizeof(TDI_ADDRESS_IP6), DWORD);
  2783. *NumberOfBytesReturned = FIELD_OFFSET(SOCKET_ADDRESS_LIST,
  2784. Address[NumAddrsOut]);
  2785. if (OutputBufferLength < *NumberOfBytesReturned) {
  2786. err = WSAEFAULT;
  2787. goto Done;
  2788. }
  2789. // First go and update all the scope ids
  2790. for (i=0; i<NumAddrsIn; i++) {
  2791. ((LPSOCKADDR_IN6)pIn->Address[i].lpSockaddr)->sin6_scope_id =
  2792. pTDI[i].sin6_scope_id;
  2793. }
  2794. // Make a copy of the input buffer in case we will overwrite it
  2795. if (pIn == pOut) {
  2796. pDupIn = HeapAlloc(GetProcessHeap(), 0, InListLength);
  2797. if (!pDupIn) {
  2798. err = WSAENOBUFS;
  2799. goto Done;
  2800. }
  2801. CopyMemory(pDupIn, InputBuffer, InListLength );
  2802. pIn = (SOCKET_ADDRESS_LIST *)pDupIn;
  2803. }
  2804. // Now fill in the output sockaddr list
  2805. pOut->iAddressCount = NumAddrsOut;
  2806. for (i=0; i<NumAddrsOut; i++) {
  2807. pOut->Address[i] = pIn->Address[pKey[i]];
  2808. }
  2809. Done:
  2810. if (pDupIn)
  2811. HeapFree(GetProcessHeap(), 0, pDupIn);
  2812. if (pBuff)
  2813. HeapFree(GetProcessHeap(), 0, pBuff);
  2814. if (Handle != INVALID_HANDLE_VALUE)
  2815. CloseHandle(Handle);
  2816. return err;
  2817. }
  2818. INT
  2819. WINAPI
  2820. WSHIoctl (
  2821. IN PVOID HelperDllSocketContext,
  2822. IN SOCKET SocketHandle,
  2823. IN HANDLE TdiAddressObjectHandle,
  2824. IN HANDLE TdiConnectionObjectHandle,
  2825. IN DWORD IoControlCode,
  2826. IN LPVOID InputBuffer,
  2827. IN DWORD InputBufferLength,
  2828. IN LPVOID OutputBuffer,
  2829. IN DWORD OutputBufferLength,
  2830. OUT LPDWORD NumberOfBytesReturned,
  2831. IN LPWSAOVERLAPPED Overlapped,
  2832. IN LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine,
  2833. OUT LPBOOL NeedsCompletion
  2834. )
  2835. /*++
  2836. Routine Description:
  2837. Performs queries & controls on the socket. This is basically an
  2838. "escape hatch" for IOCTLs not supported by MSAFD.DLL. Any unknown
  2839. IOCTLs are routed to the socket's helper DLL for protocol-specific
  2840. processing.
  2841. Arguments:
  2842. HelperDllSocketContext - the context pointer returned from
  2843. WSHOpenSocket().
  2844. SocketHandle - the handle of the socket for which we're controlling.
  2845. TdiAddressObjectHandle - the TDI address object of the socket, if
  2846. any. If the socket is not yet bound to an address, then
  2847. it does not have a TDI address object and this parameter
  2848. will be NULL.
  2849. TdiConnectionObjectHandle - the TDI connection object of the socket,
  2850. if any. If the socket is not yet connected, then it does not
  2851. have a TDI connection object and this parameter will be NULL.
  2852. IoControlCode - Control code of the operation to perform.
  2853. InputBuffer - Address of the input buffer.
  2854. InputBufferLength - The length of InputBuffer.
  2855. OutputBuffer - Address of the output buffer.
  2856. OutputBufferLength - The length of OutputBuffer.
  2857. NumberOfBytesReturned - Receives the number of bytes actually written
  2858. to the output buffer.
  2859. Overlapped - Pointer to a WSAOVERLAPPED structure for overlapped
  2860. operations.
  2861. CompletionRoutine - Pointer to a completion routine to call when
  2862. the operation is completed.
  2863. NeedsCompletion - WSAIoctl() can be overlapped, with all the gory
  2864. details that involves, such as setting events, queuing completion
  2865. routines, and posting to IO completion ports. Since the majority
  2866. of the IOCTL codes can be completed quickly "in-line", MSAFD.DLL
  2867. can optionally perform the overlapped completion of the operation.
  2868. Setting *NeedsCompletion to TRUE (the default) causes MSAFD.DLL
  2869. to handle all of the IO completion details iff this is an
  2870. overlapped operation on an overlapped socket.
  2871. Setting *NeedsCompletion to FALSE tells MSAFD.DLL to take no
  2872. further action because the helper DLL will perform any necessary
  2873. IO completion.
  2874. Note that if a helper performs its own IO completion, the helper
  2875. is responsible for maintaining the "overlapped" mode of the socket
  2876. at socket creation time and NOT performing overlapped IO completion
  2877. on non-overlapped sockets.
  2878. Return Value:
  2879. INT - 0 if successful, WinSock error code if not.
  2880. --*/
  2881. {
  2882. INT err;
  2883. UNREFERENCED_PARAMETER(Overlapped);
  2884. UNREFERENCED_PARAMETER(CompletionRoutine);
  2885. //
  2886. // Quick sanity checks.
  2887. //
  2888. if( HelperDllSocketContext == NULL ||
  2889. SocketHandle == INVALID_SOCKET ||
  2890. NumberOfBytesReturned == NULL ||
  2891. NeedsCompletion == NULL ) {
  2892. return WSAEINVAL;
  2893. }
  2894. *NeedsCompletion = TRUE;
  2895. switch( IoControlCode ) {
  2896. case SIO_MULTIPOINT_LOOPBACK :
  2897. err = WSHSetSocketInformation(
  2898. HelperDllSocketContext,
  2899. SocketHandle,
  2900. TdiAddressObjectHandle,
  2901. TdiConnectionObjectHandle,
  2902. IPPROTO_IPV6,
  2903. IPV6_MULTICAST_LOOP,
  2904. (PCHAR)InputBuffer,
  2905. (INT)InputBufferLength
  2906. );
  2907. break;
  2908. case SIO_MULTICAST_SCOPE :
  2909. err = WSHSetSocketInformation(
  2910. HelperDllSocketContext,
  2911. SocketHandle,
  2912. TdiAddressObjectHandle,
  2913. TdiConnectionObjectHandle,
  2914. IPPROTO_IPV6,
  2915. IPV6_MULTICAST_HOPS,
  2916. (PCHAR)InputBuffer,
  2917. (INT)InputBufferLength
  2918. );
  2919. break;
  2920. case SIO_ADDRESS_LIST_SORT:
  2921. err = SortIPv6Addrs(InputBuffer, InputBufferLength,
  2922. OutputBuffer, OutputBufferLength,
  2923. NumberOfBytesReturned);
  2924. break;
  2925. case SIO_KEEPALIVE_VALS: {
  2926. struct tcp_keepalive *optionval;
  2927. PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
  2928. //
  2929. // Atempt to turn on or off keepalive sending, as necessary.
  2930. //
  2931. if ( IS_DGRAM_SOCK(context->SocketType) ) {
  2932. return WSAENOPROTOOPT;
  2933. }
  2934. if ( InputBufferLength != sizeof(struct tcp_keepalive) ) {
  2935. return WSAEINVAL;
  2936. }
  2937. optionval = (struct tcp_keepalive *)InputBuffer;
  2938. if (optionval->onoff != 0 ) {
  2939. //
  2940. // Application wants to turn the keepalive on and also give the
  2941. // relevant parameters for it. If the TDI connection object handle
  2942. // is NULL, then the socket is not yet connected. In this case
  2943. // we'll just remember that the keepalive option was set and
  2944. // actually turn them on in WSHNotify() after a connect()
  2945. // has completed on the socket.
  2946. //
  2947. if ( TdiConnectionObjectHandle != NULL ) {
  2948. err = SetTdiInformation(
  2949. TdiConnectionObjectHandle,
  2950. CO_TL_ENTITY,
  2951. INFO_CLASS_PROTOCOL,
  2952. INFO_TYPE_CONNECTION,
  2953. TCP_SOCKET_KEEPALIVE_VALS,
  2954. optionval,
  2955. InputBufferLength,
  2956. TRUE
  2957. );
  2958. if ( err != NO_ERROR ) {
  2959. return err;
  2960. }
  2961. }
  2962. //
  2963. // Remember that keepalives are enabled for this socket.
  2964. //
  2965. context->KeepAliveVals.onoff = TRUE;
  2966. context->KeepAliveVals.keepalivetime = optionval->keepalivetime;
  2967. context->KeepAliveVals.keepaliveinterval = optionval->keepaliveinterval;
  2968. } else if ( optionval->onoff == 0 ) {
  2969. //
  2970. // Application wants to turn keepalive off. If the TDI
  2971. // connection object is NULL, the socket is not yet
  2972. // connected. In this case we'll just remember that
  2973. // keepalives are disabled.
  2974. //
  2975. if ( TdiConnectionObjectHandle != NULL ) {
  2976. err = SetTdiInformation(
  2977. TdiConnectionObjectHandle,
  2978. CO_TL_ENTITY,
  2979. INFO_CLASS_PROTOCOL,
  2980. INFO_TYPE_CONNECTION,
  2981. TCP_SOCKET_KEEPALIVE_VALS,
  2982. optionval,
  2983. InputBufferLength,
  2984. TRUE
  2985. );
  2986. if ( err != NO_ERROR ) {
  2987. return err;
  2988. }
  2989. }
  2990. //
  2991. // Remember that keepalives are disabled for this socket.
  2992. //
  2993. context->KeepAliveVals.onoff = FALSE;
  2994. }
  2995. err = NO_ERROR;
  2996. break;
  2997. }
  2998. default :
  2999. err = WSAEINVAL;
  3000. break;
  3001. }
  3002. return err;
  3003. } // WSHIoctl