Source code of Windows XP (NT5)
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.

4266 lines
114 KiB

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