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

1514 lines
42 KiB

  1. /*++
  2. Copyright (c) 1991-1997 Microsoft Corporation
  3. Module Name: //KERNEL/RAZZLE3/src/sockets/tcpcmd/icmp/icmp.c
  4. Abstract: Definitions of the ICMP Echo request API.
  5. Author: Mike Massa (mikemas) Dec 30, 1993
  6. Revision History:
  7. Who When What
  8. -------- -------- ----------------------------------------------
  9. mikemas 12-30-93 created
  10. RameshV 20-Jul-97 new async function IcmpSendEcho2
  11. Notes:
  12. In the functions do_echo_req/do_echo_rep the
  13. precedence/tos bits are not used as defined RFC 1349.
  14. -- MohsinA, 30-Jul-97
  15. --*/
  16. #include "inc.h"
  17. #pragma hdrstop
  18. #include <align.h>
  19. #include <icmp.h>
  20. #include <icmpapi.h>
  21. #include <icmpif.h>
  22. #include <winsock2.h>
  23. #include <ws2tcpip.h>
  24. #include <wscntl.h>
  25. #include <ntddip6.h>
  26. //
  27. // Constants
  28. //
  29. #define PLATFORM_NT 0x0
  30. #define PLATFORM_VXD 0x1
  31. #define VXD_HANDLE_VALUE 0xDFFFFFFF
  32. //
  33. // Common Global variables
  34. //
  35. DWORD Platform = 0xFFFFFFFF;
  36. // VxD external function pointers
  37. //
  38. LPWSCONTROL wsControl = NULL;
  39. __inline void
  40. CopyTDIFromSA6(TDI_ADDRESS_IP6 *To, SOCKADDR_IN6 *From)
  41. {
  42. memcpy(To, &From->sin6_port, sizeof *To);
  43. }
  44. __inline void
  45. CopySAFromTDI6(SOCKADDR_IN6 *To, TDI_ADDRESS_IP6 *From)
  46. {
  47. To->sin6_family = AF_INET6;
  48. memcpy(&To->sin6_port, From, sizeof *From);
  49. }
  50. /////////////////////////////////////////////////////////////////////////////
  51. //
  52. // Public functions
  53. //
  54. /////////////////////////////////////////////////////////////////////////////
  55. HANDLE
  56. WINAPI
  57. IcmpCreateFile(
  58. VOID
  59. )
  60. /*++
  61. Routine Description:
  62. Opens a handle on which ICMP Echo Requests can be issued.
  63. Arguments:
  64. None.
  65. Return Value:
  66. An open file handle or INVALID_HANDLE_VALUE. Extended error information
  67. is available by calling GetLastError().
  68. Notes:
  69. This function is effectively a no-op for the VxD platform.
  70. --*/
  71. {
  72. HANDLE IcmpHandle = INVALID_HANDLE_VALUE;
  73. if (Platform == PLATFORM_NT) {
  74. OBJECT_ATTRIBUTES objectAttributes;
  75. IO_STATUS_BLOCK ioStatusBlock;
  76. UNICODE_STRING nameString;
  77. NTSTATUS status;
  78. //
  79. // Open a Handle to the IP driver.
  80. //
  81. RtlInitUnicodeString(&nameString, DD_IP_DEVICE_NAME);
  82. InitializeObjectAttributes(
  83. &objectAttributes,
  84. &nameString,
  85. OBJ_CASE_INSENSITIVE,
  86. (HANDLE) NULL,
  87. (PSECURITY_DESCRIPTOR) NULL
  88. );
  89. status = NtCreateFile(
  90. &IcmpHandle,
  91. GENERIC_EXECUTE,
  92. &objectAttributes,
  93. &ioStatusBlock,
  94. NULL,
  95. FILE_ATTRIBUTE_NORMAL,
  96. FILE_SHARE_READ | FILE_SHARE_WRITE,
  97. FILE_OPEN_IF,
  98. 0,
  99. NULL,
  100. 0
  101. );
  102. if (!NT_SUCCESS(status)) {
  103. SetLastError(RtlNtStatusToDosError(status));
  104. IcmpHandle = INVALID_HANDLE_VALUE;
  105. }
  106. }
  107. else {
  108. IcmpHandle = LongToHandle(VXD_HANDLE_VALUE);
  109. }
  110. return(IcmpHandle);
  111. } // IcmpCreateFile
  112. HANDLE
  113. WINAPI
  114. Icmp6CreateFile(
  115. VOID
  116. )
  117. /*++
  118. Routine Description:
  119. Opens a handle on which ICMPv6 Echo Requests can be issued.
  120. Arguments:
  121. None.
  122. Return Value:
  123. An open file handle or INVALID_HANDLE_VALUE. Extended error information
  124. is available by calling GetLastError().
  125. --*/
  126. {
  127. HANDLE IcmpHandle = INVALID_HANDLE_VALUE;
  128. if (Platform == PLATFORM_NT) {
  129. OBJECT_ATTRIBUTES objectAttributes;
  130. IO_STATUS_BLOCK ioStatusBlock;
  131. UNICODE_STRING nameString;
  132. NTSTATUS status;
  133. //
  134. // Open a Handle to the IPv6 driver.
  135. //
  136. RtlInitUnicodeString(&nameString, DD_IPV6_DEVICE_NAME);
  137. InitializeObjectAttributes(
  138. &objectAttributes,
  139. &nameString,
  140. OBJ_CASE_INSENSITIVE,
  141. (HANDLE) NULL,
  142. (PSECURITY_DESCRIPTOR) NULL
  143. );
  144. status = NtCreateFile(
  145. &IcmpHandle,
  146. GENERIC_EXECUTE,
  147. &objectAttributes,
  148. &ioStatusBlock,
  149. NULL,
  150. FILE_ATTRIBUTE_NORMAL,
  151. FILE_SHARE_READ | FILE_SHARE_WRITE,
  152. FILE_OPEN_IF,
  153. 0,
  154. NULL,
  155. 0
  156. );
  157. if (!NT_SUCCESS(status)) {
  158. SetLastError(RtlNtStatusToDosError(status));
  159. IcmpHandle = INVALID_HANDLE_VALUE;
  160. }
  161. }
  162. else {
  163. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  164. IcmpHandle = INVALID_HANDLE_VALUE;
  165. }
  166. return(IcmpHandle);
  167. }
  168. BOOL
  169. WINAPI
  170. IcmpCloseHandle(
  171. HANDLE IcmpHandle
  172. )
  173. /*++
  174. Routine Description:
  175. Closes a handle opened by IcmpCreateFile.
  176. Arguments:
  177. IcmpHandle - The handle to close.
  178. Return Value:
  179. TRUE if the handle was closed successfully, otherwise FALSE. Extended
  180. error information is available by calling GetLastError().
  181. Notes:
  182. This function is a no-op for the VxD platform.
  183. --*/
  184. {
  185. if (Platform == PLATFORM_NT) {
  186. NTSTATUS status;
  187. status = NtClose(IcmpHandle);
  188. if (!NT_SUCCESS(status)) {
  189. SetLastError(RtlNtStatusToDosError(status));
  190. return(FALSE);
  191. }
  192. }
  193. return(TRUE);
  194. } // IcmpCloseHandle
  195. DWORD
  196. IcmpParseReplies(
  197. LPVOID ReplyBuffer,
  198. DWORD ReplySize
  199. )
  200. /*++
  201. Routine Description:
  202. Parses the reply buffer provided and returns the number of ICMP responses found.
  203. Arguments:
  204. ReplyBuffer - This must be the same buffer that was passed to IcmpSendEcho2
  205. This is rewritten to hold an array of ICMP_ECHO_REPLY structures.
  206. (i.e. the type is PICMP_ECHO_REPLY).
  207. ReplySize - This must be the size of the above buffer.
  208. Return Value:
  209. Returns the number of ICMP responses found. If there is an errors, return value is
  210. zero. The error can be determined by a call to GetLastError.
  211. --*/
  212. {
  213. DWORD numberOfReplies = 0;
  214. PICMP_ECHO_REPLY reply;
  215. unsigned short i;
  216. reply = ((PICMP_ECHO_REPLY) ReplyBuffer);
  217. if( NULL == reply || 0 == ReplySize ) {
  218. //
  219. // Invalid parameter passed. But we ignore this and just return # of replies =0
  220. //
  221. return 0;
  222. }
  223. //
  224. // Convert new IP status IP_NEGOTIATING_IPSEC to IP_DEST_HOST_UNREACHABLE.
  225. //
  226. if (reply->Status == IP_NEGOTIATING_IPSEC) {
  227. reply->Status = IP_DEST_HOST_UNREACHABLE;
  228. }
  229. //
  230. // The reserved field of the first reply contains the number of replies.
  231. //
  232. numberOfReplies = reply->Reserved;
  233. reply->Reserved = 0;
  234. if (numberOfReplies == 0) {
  235. //
  236. // Internal IP error. The error code is in the first reply slot.
  237. //
  238. SetLastError(reply->Status);
  239. }
  240. else {
  241. //
  242. // Walk through the replies and convert the data offsets to user mode
  243. // pointers.
  244. //
  245. for (i=0; i<numberOfReplies; i++, reply++) {
  246. reply->Data = ((UCHAR *) reply) + ((ULONG_PTR) reply->Data);
  247. reply->Options.OptionsData =
  248. ((UCHAR FAR *) reply) + ((ULONG_PTR) reply->Options.OptionsData);
  249. }
  250. }
  251. return(numberOfReplies);
  252. } // IcmpParseReplies
  253. DWORD
  254. IcmpParseReplies2(
  255. LPVOID ReplyBuffer,
  256. DWORD ReplySize
  257. )
  258. /*++
  259. Routine Description:
  260. Parses the reply buffer provided and returns the number of ICMP responses found.
  261. Arguments:
  262. ReplyBuffer - This must be the same buffer that was passed to IcmpSendEcho2
  263. This is rewritten to hold an array of ICMP_ECHO_REPLY structures.
  264. (i.e. the type is PICMP_ECHO_REPLY).
  265. ReplySize - This must be the size of the above buffer.
  266. Return Value:
  267. Returns the number of ICMP responses found. If there is an errors, return value is
  268. zero. The error can be determined by a call to GetLastError.
  269. --*/
  270. {
  271. DWORD numberOfReplies = 0;
  272. PICMP_ECHO_REPLY reply;
  273. unsigned short i;
  274. reply = ((PICMP_ECHO_REPLY) ReplyBuffer);
  275. if( NULL == reply || 0 == ReplySize ) {
  276. //
  277. // Invalid parameter passed. But we ignore this and just return # of replies =0
  278. //
  279. return 0;
  280. }
  281. //
  282. // The reserved field of the first reply contains the number of replies.
  283. //
  284. numberOfReplies = reply->Reserved;
  285. reply->Reserved = 0;
  286. if (numberOfReplies == 0) {
  287. //
  288. // Internal IP error. The error code is in the first reply slot.
  289. //
  290. SetLastError(reply->Status);
  291. }
  292. else {
  293. //
  294. // Walk through the replies and convert the data offsets to user mode
  295. // pointers.
  296. //
  297. for (i=0; i<numberOfReplies; i++, reply++) {
  298. reply->Data = ((UCHAR *) reply) + ((ULONG_PTR) reply->Data);
  299. reply->Options.OptionsData =
  300. ((UCHAR FAR *) reply) + ((ULONG_PTR) reply->Options.OptionsData);
  301. }
  302. }
  303. return(numberOfReplies);
  304. } // IcmpParseReplies
  305. DWORD
  306. WINAPI
  307. IcmpSendEcho(
  308. HANDLE IcmpHandle,
  309. IPAddr DestinationAddress,
  310. LPVOID RequestData,
  311. WORD RequestSize,
  312. PIP_OPTION_INFORMATION RequestOptions,
  313. LPVOID ReplyBuffer,
  314. DWORD ReplySize,
  315. DWORD Timeout
  316. )
  317. /*++
  318. Routine Description:
  319. Sends an ICMP Echo request and returns one or more replies. The
  320. call returns when the timeout has expired or the reply buffer
  321. is filled.
  322. Arguments:
  323. IcmpHandle - An open handle returned by ICMPCreateFile.
  324. DestinationAddress - The destination of the echo request.
  325. RequestData - A buffer containing the data to send in the
  326. request.
  327. RequestSize - The number of bytes in the request data buffer.
  328. RequestOptions - Pointer to the IP header options for the request.
  329. May be NULL.
  330. ReplyBuffer - A buffer to hold any replies to the request.
  331. On return, the buffer will contain an array of
  332. ICMP_ECHO_REPLY structures followed by options
  333. and data. The buffer must be large enough to
  334. hold at least one ICMP_ECHO_REPLY structure.
  335. It should be large enough to also hold
  336. 8 more bytes of data - this is the size of
  337. an ICMP error message.
  338. ReplySize - The size in bytes of the reply buffer.
  339. Timeout - The time in milliseconds to wait for replies.
  340. Return Value:
  341. Returns the number of replies received and stored in ReplyBuffer. If
  342. the return value is zero, extended error information is available
  343. via GetLastError().
  344. --*/
  345. {
  346. PICMP_ECHO_REQUEST requestBuffer = NULL;
  347. ULONG requestBufferSize;
  348. DWORD numberOfReplies = 0;
  349. if (ReplySize < sizeof(ICMP_ECHO_REPLY)) {
  350. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  351. return(0);
  352. }
  353. requestBufferSize = sizeof(ICMP_ECHO_REQUEST) + RequestSize;
  354. if (RequestOptions != NULL) {
  355. requestBufferSize += RequestOptions->OptionsSize;
  356. }
  357. if (requestBufferSize < ReplySize) {
  358. requestBufferSize = ReplySize;
  359. }
  360. requestBuffer = LocalAlloc(LMEM_FIXED, requestBufferSize);
  361. if (requestBuffer == NULL) {
  362. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  363. return(0);
  364. }
  365. //
  366. // Initialize the input buffer.
  367. //
  368. requestBuffer->Address = DestinationAddress;
  369. requestBuffer->Timeout = Timeout;
  370. requestBuffer->DataSize = RequestSize;
  371. requestBuffer->OptionsOffset = sizeof(ICMP_ECHO_REQUEST);
  372. if (RequestOptions != NULL) {
  373. requestBuffer->OptionsValid = 1;
  374. requestBuffer->Ttl = RequestOptions->Ttl;
  375. requestBuffer->Tos = RequestOptions->Tos;
  376. requestBuffer->Flags = RequestOptions->Flags;
  377. requestBuffer->OptionsSize = RequestOptions->OptionsSize;
  378. if (RequestOptions->OptionsSize > 0) {
  379. CopyMemory(
  380. ((UCHAR *) requestBuffer) + requestBuffer->OptionsOffset,
  381. RequestOptions->OptionsData,
  382. RequestOptions->OptionsSize
  383. );
  384. }
  385. }
  386. else {
  387. requestBuffer->OptionsValid = 0;
  388. requestBuffer->OptionsSize = 0;
  389. }
  390. requestBuffer->DataOffset = requestBuffer->OptionsOffset +
  391. requestBuffer->OptionsSize;
  392. if (RequestSize > 0) {
  393. CopyMemory(
  394. ((UCHAR *)requestBuffer) + requestBuffer->DataOffset,
  395. RequestData,
  396. RequestSize
  397. );
  398. }
  399. if (Platform == PLATFORM_NT) {
  400. IO_STATUS_BLOCK ioStatusBlock;
  401. NTSTATUS status;
  402. HANDLE eventHandle;
  403. eventHandle = CreateEvent(
  404. NULL, // default security
  405. FALSE, // auto reset
  406. FALSE, // initially non-signalled
  407. NULL // unnamed
  408. );
  409. if (NULL == eventHandle) {
  410. goto error_exit;
  411. }
  412. status = NtDeviceIoControlFile(
  413. IcmpHandle, // Driver handle
  414. eventHandle, // Event
  415. NULL, // APC Routine
  416. NULL, // APC context
  417. &ioStatusBlock, // Status block
  418. IOCTL_ICMP_ECHO_REQUEST, // Control code
  419. requestBuffer, // Input buffer
  420. requestBufferSize, // Input buffer size
  421. ReplyBuffer, // Output buffer
  422. ReplySize // Output buffer size
  423. );
  424. if (status == STATUS_PENDING) {
  425. NtWaitForSingleObject(
  426. eventHandle,
  427. FALSE,
  428. NULL);
  429. status = ioStatusBlock.Status;
  430. }
  431. CloseHandle(eventHandle);
  432. if (status != STATUS_SUCCESS) {
  433. SetLastError(RtlNtStatusToDosError(status));
  434. goto error_exit;
  435. }
  436. }
  437. else {
  438. //
  439. // VxD Platform
  440. //
  441. DWORD status;
  442. ULONG replyBufferSize = ReplySize;
  443. status = (*wsControl)(
  444. IPPROTO_TCP,
  445. WSCNTL_TCPIP_ICMP_ECHO,
  446. requestBuffer,
  447. &requestBufferSize,
  448. ReplyBuffer,
  449. &replyBufferSize
  450. );
  451. if (status != NO_ERROR) {
  452. SetLastError(status);
  453. goto error_exit;
  454. }
  455. }
  456. numberOfReplies = IcmpParseReplies(ReplyBuffer, ReplySize);
  457. error_exit:
  458. LocalFree(requestBuffer);
  459. return(numberOfReplies);
  460. } // IcmpSendEcho
  461. DWORD
  462. WINAPI
  463. IcmpSendEcho2(
  464. HANDLE IcmpHandle,
  465. HANDLE Event,
  466. PIO_APC_ROUTINE ApcRoutine,
  467. PVOID ApcContext,
  468. IPAddr DestinationAddress,
  469. LPVOID RequestData,
  470. WORD RequestSize,
  471. PIP_OPTION_INFORMATION RequestOptions,
  472. LPVOID ReplyBuffer,
  473. DWORD ReplySize,
  474. DWORD Timeout
  475. )
  476. /*++
  477. Routine Description:
  478. Sends an ICMP Echo request and the call returns either immediately
  479. (if Event or ApcRoutine is NonNULL) or returns after the specified
  480. timeout. The ReplyBuffer contains the ICMP responses, if any.
  481. Arguments:
  482. IcmpHandle - An open handle returned by ICMPCreateFile.
  483. Event - This is the event to be signalled whenever an IcmpResponse
  484. comes in.
  485. ApcRoutine - This routine would be called when the calling thread
  486. is in an alertable thread and an ICMP reply comes in.
  487. ApcContext - This optional parameter is given to the ApcRoutine when
  488. this call succeeds.
  489. DestinationAddress - The destination of the echo request.
  490. RequestData - A buffer containing the data to send in the
  491. request.
  492. RequestSize - The number of bytes in the request data buffer.
  493. RequestOptions - Pointer to the IP header options for the request.
  494. May be NULL.
  495. ReplyBuffer - A buffer to hold any replies to the request.
  496. On return, the buffer will contain an array of
  497. ICMP_ECHO_REPLY structures followed by options
  498. and data. The buffer must be large enough to
  499. hold at least one ICMP_ECHO_REPLY structure.
  500. It should be large enough to also hold
  501. 8 more bytes of data - this is the size of
  502. an ICMP error message + this should also have
  503. space for IO_STATUS_BLOCK which requires 8 or
  504. 16 bytes...
  505. ReplySize - The size in bytes of the reply buffer.
  506. Timeout - The time in milliseconds to wait for replies.
  507. This is NOT used if ApcRoutine is not NULL or if Event
  508. is not NULL.
  509. Return Value:
  510. Returns the number of replies received and stored in ReplyBuffer. If
  511. the return value is zero, extended error information is available
  512. via GetLastError().
  513. Remarks:
  514. On NT platforms,
  515. If used Asynchronously (either ApcRoutine or Event is specified), then
  516. ReplyBuffer and ReplySize are still needed. This is where the response
  517. comes in.
  518. ICMP Response data is copied to the ReplyBuffer provided, and the caller of
  519. this function has to parse it asynchronously. The function IcmpParseReply
  520. is provided for this purpose.
  521. On non-NT platforms,
  522. Event, ApcRoutine and ApcContext are IGNORED.
  523. --*/
  524. {
  525. PICMP_ECHO_REQUEST requestBuffer = NULL;
  526. ULONG requestBufferSize;
  527. DWORD numberOfReplies = 0;
  528. BOOL Asynchronous;
  529. Asynchronous = (Platform == PLATFORM_NT && (Event || ApcRoutine));
  530. if (ReplySize < sizeof(ICMP_ECHO_REPLY)) {
  531. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  532. return(0);
  533. }
  534. requestBufferSize = sizeof(ICMP_ECHO_REQUEST) + RequestSize;
  535. if (RequestOptions != NULL) {
  536. requestBufferSize += RequestOptions->OptionsSize;
  537. }
  538. if (requestBufferSize < ReplySize) {
  539. requestBufferSize = ReplySize;
  540. }
  541. requestBuffer = LocalAlloc(LMEM_FIXED, requestBufferSize);
  542. if (requestBuffer == NULL) {
  543. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  544. return(0);
  545. }
  546. //
  547. // Initialize the input buffer.
  548. //
  549. requestBuffer->Address = DestinationAddress;
  550. requestBuffer->Timeout = Timeout;
  551. requestBuffer->DataSize = RequestSize;
  552. requestBuffer->OptionsOffset = sizeof(ICMP_ECHO_REQUEST);
  553. if (RequestOptions != NULL) {
  554. requestBuffer->OptionsValid = 1;
  555. requestBuffer->Ttl = RequestOptions->Ttl;
  556. requestBuffer->Tos = RequestOptions->Tos;
  557. requestBuffer->Flags = RequestOptions->Flags;
  558. requestBuffer->OptionsSize = RequestOptions->OptionsSize;
  559. if (RequestOptions->OptionsSize > 0) {
  560. CopyMemory(
  561. ((UCHAR *) requestBuffer) + requestBuffer->OptionsOffset,
  562. RequestOptions->OptionsData,
  563. RequestOptions->OptionsSize
  564. );
  565. }
  566. }
  567. else {
  568. requestBuffer->OptionsValid = 0;
  569. requestBuffer->OptionsSize = 0;
  570. }
  571. requestBuffer->DataOffset = requestBuffer->OptionsOffset +
  572. requestBuffer->OptionsSize;
  573. if (RequestSize > 0) {
  574. CopyMemory(
  575. ((UCHAR *)requestBuffer) + requestBuffer->DataOffset,
  576. RequestData,
  577. RequestSize
  578. );
  579. }
  580. if (Platform == PLATFORM_NT) {
  581. IO_STATUS_BLOCK *pioStatusBlock;
  582. NTSTATUS status;
  583. HANDLE eventHandle;
  584. //
  585. // allocate status block on the reply buffer..
  586. //
  587. pioStatusBlock = (IO_STATUS_BLOCK*)((LPBYTE)ReplyBuffer + ReplySize);
  588. pioStatusBlock --;
  589. pioStatusBlock = ROUND_DOWN_POINTER(pioStatusBlock, ALIGN_WORST);
  590. ReplySize = (ULONG)(((LPBYTE)pioStatusBlock) - (LPBYTE)ReplyBuffer );
  591. if( (PVOID)pioStatusBlock < ReplyBuffer
  592. || ReplySize < sizeof(ICMP_ECHO_REPLY) ) {
  593. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  594. goto error_exit;
  595. }
  596. if(!Asynchronous) { // Normal synchronous.
  597. eventHandle = CreateEvent(
  598. NULL, // default security
  599. FALSE, // auto reset
  600. FALSE, // initially non-signalled
  601. NULL // unnamed
  602. );
  603. if (NULL == eventHandle) {
  604. goto error_exit;
  605. }
  606. } else { // Asynchronous call.
  607. eventHandle = Event; // Use specified Event.
  608. }
  609. status = NtDeviceIoControlFile(
  610. IcmpHandle, // Driver handle
  611. eventHandle, // Event
  612. ApcRoutine, // APC Routine
  613. ApcContext, // APC context
  614. pioStatusBlock, // Status block
  615. IOCTL_ICMP_ECHO_REQUEST, // Control code
  616. requestBuffer, // Input buffer
  617. requestBufferSize, // Input buffer size
  618. ReplyBuffer, // Output buffer
  619. ReplySize // Output buffer size
  620. );
  621. if (Asynchronous) {
  622. // Asynchronous calls. We cannot give any information.
  623. // We let the user do the other work.
  624. SetLastError(RtlNtStatusToDosError(status));
  625. goto error_exit;
  626. }
  627. if (status == STATUS_PENDING) {
  628. NtWaitForSingleObject(
  629. eventHandle,
  630. FALSE,
  631. NULL);
  632. status = pioStatusBlock->Status;
  633. }
  634. CloseHandle(eventHandle);
  635. if (status != STATUS_SUCCESS) {
  636. SetLastError(RtlNtStatusToDosError(status));
  637. goto error_exit;
  638. }
  639. }
  640. else {
  641. //
  642. // VxD Platform
  643. //
  644. DWORD status;
  645. ULONG replyBufferSize = ReplySize;
  646. status = (*wsControl)(
  647. IPPROTO_TCP,
  648. WSCNTL_TCPIP_ICMP_ECHO,
  649. requestBuffer,
  650. &requestBufferSize,
  651. ReplyBuffer,
  652. &replyBufferSize
  653. );
  654. if (status != NO_ERROR) {
  655. SetLastError(status);
  656. goto error_exit;
  657. }
  658. }
  659. numberOfReplies = IcmpParseReplies2(ReplyBuffer, ReplySize);
  660. error_exit:
  661. LocalFree(requestBuffer);
  662. return(numberOfReplies);
  663. } // IcmpSendEcho2
  664. DWORD
  665. Icmp6ParseReplies(
  666. LPVOID ReplyBuffer,
  667. DWORD ReplySize
  668. )
  669. /*++
  670. Routine Description:
  671. Parses the reply buffer provided and returns the number of ICMPv6 responses
  672. found.
  673. Arguments:
  674. ReplyBuffer - This must be the same buffer that was passed to
  675. Icmp6SendEcho2. This is written to hold an array of
  676. ICMPV6_ECHO_REPLY structures (i.e., the type is
  677. PICMPV6_ECHO_REPLY).
  678. ReplySize - This must be the size of the above buffer.
  679. Return Value:
  680. Returns the number of ICMPv6 responses found. If there is an error,
  681. return value is zero. The error can be determined by a call to
  682. GetLastError.
  683. --*/
  684. {
  685. PICMPV6_ECHO_REPLY reply;
  686. reply = ((PICMPV6_ECHO_REPLY) ReplyBuffer);
  687. if( NULL == reply || 0 == ReplySize ) {
  688. //
  689. // Invalid parameter passed. But we ignore this and just return # of
  690. // replies =0
  691. //
  692. return 0;
  693. }
  694. //
  695. // Convert new IP status IP_NEGOTIATING_IPSEC to IP_DEST_HOST_UNREACHABLE.
  696. //
  697. if (reply->Status == IP_NEGOTIATING_IPSEC) {
  698. reply->Status = IP_DEST_HOST_UNREACHABLE;
  699. }
  700. if ((reply->Status == IP_SUCCESS) || (reply->Status == IP_TTL_EXPIRED_TRANSIT)) {
  701. return 1;
  702. } else {
  703. //
  704. // Internal IP error. The error code is in the first reply slot.
  705. //
  706. SetLastError(reply->Status);
  707. return 0;
  708. }
  709. }
  710. DWORD
  711. WINAPI
  712. Icmp6SendEcho2(
  713. HANDLE IcmpHandle,
  714. HANDLE Event,
  715. PIO_APC_ROUTINE ApcRoutine,
  716. PVOID ApcContext,
  717. LPSOCKADDR_IN6 SourceAddress,
  718. LPSOCKADDR_IN6 DestinationAddress,
  719. LPVOID RequestData,
  720. WORD RequestSize,
  721. PIP_OPTION_INFORMATION RequestOptions,
  722. LPVOID ReplyBuffer,
  723. DWORD ReplySize,
  724. DWORD Timeout
  725. )
  726. /*++
  727. Routine Description:
  728. Sends an ICMPv6 Echo request and the call returns either immediately
  729. (if Event or ApcRoutine is NonNULL) or returns after the specified
  730. timeout. The ReplyBuffer contains the ICMPv6 responses, if any.
  731. Arguments:
  732. IcmpHandle - An open handle returned by ICMP6CreateFile.
  733. Event - This is the event to be signalled whenever an
  734. IcmpResponse comes in.
  735. ApcRoutine - This routine would be called when the calling thread
  736. is in an alertable thread and an ICMPv6 reply comes
  737. in.
  738. ApcContext - This optional parameter is given to the ApcRoutine
  739. when this call succeeds.
  740. DestinationAddress - The destination of the echo request.
  741. RequestData - A buffer containing the data to send in the
  742. request.
  743. RequestSize - The number of bytes in the request data buffer.
  744. RequestOptions - Pointer to the IPv6 header options for the request.
  745. May be NULL.
  746. ReplyBuffer - A buffer to hold any replies to the request.
  747. On return, the buffer will contain an array of
  748. ICMPV6_ECHO_REPLY structures followed by options
  749. and data. The buffer must be large enough to
  750. hold at least one ICMPV6_ECHO_REPLY structure.
  751. It should be large enough to also hold
  752. 8 more bytes of data - this is the size of
  753. an ICMPv6 error message + this should also have
  754. space for IO_STATUS_BLOCK which requires 8 or
  755. 16 bytes...
  756. ReplySize - The size in bytes of the reply buffer.
  757. Timeout - The time in milliseconds to wait for replies.
  758. This is NOT used if ApcRoutine is not NULL or if
  759. Event is not NULL.
  760. Return Value:
  761. Returns the number of replies received and stored in ReplyBuffer. If
  762. the return value is zero, extended error information is available
  763. via GetLastError().
  764. Remarks:
  765. If used Asynchronously (either ApcRoutine or Event is specified), then
  766. ReplyBuffer and ReplySize are still needed. This is where the response
  767. comes in.
  768. ICMP Response data is copied to the ReplyBuffer provided, and the caller of
  769. this function has to parse it asynchronously. The function Icmp6ParseReply
  770. is provided for this purpose.
  771. --*/
  772. {
  773. PICMPV6_ECHO_REQUEST requestBuffer = NULL;
  774. ULONG requestBufferSize;
  775. DWORD numberOfReplies = 0;
  776. BOOL Asynchronous;
  777. IO_STATUS_BLOCK *pioStatusBlock;
  778. NTSTATUS status;
  779. HANDLE eventHandle;
  780. Asynchronous = (Platform == PLATFORM_NT && (Event || ApcRoutine));
  781. if (ReplySize < sizeof(ICMPV6_ECHO_REPLY)) {
  782. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  783. return(0);
  784. }
  785. requestBufferSize = sizeof(ICMPV6_ECHO_REQUEST) + RequestSize;
  786. requestBuffer = LocalAlloc(LMEM_FIXED, requestBufferSize);
  787. if (requestBuffer == NULL) {
  788. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  789. return(0);
  790. }
  791. if (Platform != PLATFORM_NT) {
  792. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  793. goto error_exit;
  794. }
  795. //
  796. // Initialize the input buffer.
  797. //
  798. CopyTDIFromSA6(&requestBuffer->DstAddress, DestinationAddress);
  799. CopyTDIFromSA6(&requestBuffer->SrcAddress, SourceAddress);
  800. requestBuffer->Timeout = Timeout;
  801. requestBuffer->TTL = RequestOptions->Ttl;
  802. requestBuffer->Flags = RequestOptions->Flags;
  803. if (RequestSize > 0) {
  804. CopyMemory(
  805. (UCHAR *)(requestBuffer + 1),
  806. RequestData,
  807. RequestSize
  808. );
  809. }
  810. //
  811. // allocate status block on the reply buffer..
  812. //
  813. pioStatusBlock = (IO_STATUS_BLOCK*)((LPBYTE)ReplyBuffer + ReplySize);
  814. pioStatusBlock --;
  815. pioStatusBlock = ROUND_DOWN_POINTER(pioStatusBlock, ALIGN_WORST);
  816. ReplySize = (ULONG)(((LPBYTE)pioStatusBlock) - (LPBYTE)ReplyBuffer );
  817. if( (PVOID)pioStatusBlock < ReplyBuffer
  818. || ReplySize < sizeof(ICMPV6_ECHO_REPLY) ) {
  819. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  820. goto error_exit;
  821. }
  822. if(!Asynchronous) { // Normal synchronous.
  823. eventHandle = CreateEvent(
  824. NULL, // default security
  825. FALSE, // auto reset
  826. FALSE, // initially non-signalled
  827. NULL // unnamed
  828. );
  829. if (NULL == eventHandle) {
  830. goto error_exit;
  831. }
  832. } else { // Asynchronous call.
  833. eventHandle = Event; // Use specified Event.
  834. }
  835. status = NtDeviceIoControlFile(
  836. IcmpHandle, // Driver handle
  837. eventHandle, // Event
  838. ApcRoutine, // APC Routine
  839. ApcContext, // APC context
  840. pioStatusBlock, // Status block
  841. IOCTL_ICMPV6_ECHO_REQUEST, // Control code
  842. requestBuffer, // Input buffer
  843. requestBufferSize, // Input buffer size
  844. ReplyBuffer, // Output buffer
  845. ReplySize // Output buffer size
  846. );
  847. if (Asynchronous) {
  848. // Asynchronous calls. We cannot give any information.
  849. // We let the user do the other work.
  850. SetLastError(RtlNtStatusToDosError(status));
  851. goto error_exit;
  852. }
  853. if (status == STATUS_PENDING) {
  854. NtWaitForSingleObject(
  855. eventHandle,
  856. FALSE,
  857. NULL);
  858. status = pioStatusBlock->Status;
  859. }
  860. CloseHandle(eventHandle);
  861. if (status != STATUS_SUCCESS) {
  862. SetLastError(RtlNtStatusToDosError(status));
  863. goto error_exit;
  864. }
  865. numberOfReplies = Icmp6ParseReplies(ReplyBuffer, ReplySize);
  866. error_exit:
  867. LocalFree(requestBuffer);
  868. return(numberOfReplies);
  869. }
  870. //
  871. // Constants
  872. //
  873. #define PING_WAIT 1000
  874. #define DEFAULT_TTL 32
  875. //
  876. // Local type definitions
  877. //
  878. typedef struct icmp_local_storage {
  879. struct icmp_local_storage *Next;
  880. HANDLE IcmpHandle;
  881. LPVOID ReplyBuffer;
  882. DWORD NumberOfReplies;
  883. DWORD Status;
  884. } ICMP_LOCAL_STORAGE, *PICMP_LOCAL_STORAGE;
  885. typedef struct status_table {
  886. IP_STATUS NewStatus;
  887. int OldStatus;
  888. } STATUS_TABLE, *PSTATUS_TABLE;
  889. //
  890. // Global variables
  891. //
  892. CRITICAL_SECTION g_IcmpLock;
  893. PICMP_LOCAL_STORAGE RequestHead = NULL;
  894. STATUS_TABLE StatusTable[] = {
  895. { IP_SUCCESS, ECHO_REPLY },
  896. { IP_DEST_NET_UNREACHABLE, DEST_UNR },
  897. { IP_DEST_HOST_UNREACHABLE, DEST_UNR },
  898. { IP_NEGOTIATING_IPSEC, DEST_UNR },
  899. { IP_DEST_PROT_UNREACHABLE, DEST_UNR },
  900. { IP_TTL_EXPIRED_TRANSIT, TIME_EXCEEDED },
  901. { IP_TTL_EXPIRED_REASSEM, TIME_EXCEEDED },
  902. { IP_PARAM_PROBLEM, PARAMETER_ERROR },
  903. { IP_BAD_ROUTE, PARAMETER_ERROR },
  904. { IP_BAD_OPTION, PARAMETER_ERROR },
  905. { IP_BUF_TOO_SMALL, PARAMETER_ERROR },
  906. { IP_PACKET_TOO_BIG, PARAMETER_ERROR },
  907. { IP_BAD_DESTINATION, PARAMETER_ERROR },
  908. { IP_GENERAL_FAILURE, POLL_FAILED }
  909. };
  910. HANDLE
  911. STRMAPI
  912. register_icmp(
  913. void
  914. )
  915. {
  916. HANDLE icmpHandle;
  917. icmpHandle = IcmpCreateFile();
  918. if (icmpHandle == INVALID_HANDLE_VALUE) {
  919. SetLastError(ICMP_OPEN_ERROR);
  920. return(ICMP_ERROR);
  921. }
  922. return(icmpHandle);
  923. } // register_icmp
  924. int
  925. STRMAPI
  926. do_echo_req(
  927. HANDLE fd,
  928. long addr,
  929. char *data,
  930. int amount,
  931. char *optptr,
  932. int optlen,
  933. int df,
  934. int ttl,
  935. int tos,
  936. int precedence
  937. )
  938. {
  939. PICMP_LOCAL_STORAGE localStorage;
  940. DWORD replySize;
  941. IP_OPTION_INFORMATION options;
  942. LPVOID replyBuffer;
  943. replySize = sizeof(ICMP_ECHO_REPLY) + amount + optlen;
  944. //
  945. // Allocate a buffer to hold the reply.
  946. //
  947. localStorage = (PICMP_LOCAL_STORAGE) LocalAlloc(
  948. LMEM_FIXED,
  949. replySize +
  950. sizeof(ICMP_LOCAL_STORAGE)
  951. );
  952. if (localStorage == NULL) {
  953. return((int)GetLastError());
  954. }
  955. replyBuffer = ((char *) localStorage) + sizeof(ICMP_LOCAL_STORAGE);
  956. if (ttl == 0) {
  957. options.Ttl = DEFAULT_TTL;
  958. }
  959. else {
  960. options.Ttl = (BYTE)ttl;
  961. }
  962. options.Tos = (UCHAR)((tos << 4) | precedence);
  963. options.Flags = df ? IP_FLAG_DF : 0;
  964. options.OptionsSize = (BYTE)optlen;
  965. options.OptionsData = (PUCHAR)optptr;
  966. localStorage->NumberOfReplies = IcmpSendEcho(
  967. fd,
  968. (IPAddr) addr,
  969. data,
  970. (WORD)amount,
  971. &options,
  972. replyBuffer,
  973. replySize,
  974. PING_WAIT
  975. );
  976. if (localStorage->NumberOfReplies == 0) {
  977. localStorage->Status = GetLastError();
  978. }
  979. else {
  980. localStorage->Status = IP_SUCCESS;
  981. }
  982. localStorage->IcmpHandle = fd;
  983. localStorage->ReplyBuffer = replyBuffer;
  984. //
  985. // Save the reply for later retrieval.
  986. //
  987. EnterCriticalSection(&g_IcmpLock);
  988. localStorage->Next = RequestHead;
  989. RequestHead = localStorage;
  990. LeaveCriticalSection(&g_IcmpLock);
  991. return(0);
  992. } // do_echo_req
  993. int
  994. STRMAPI
  995. do_echo_rep(
  996. HANDLE fd,
  997. char *data,
  998. int amount,
  999. int *rettype,
  1000. int *retttl,
  1001. int *rettos,
  1002. int *retprec,
  1003. int *retdf,
  1004. char *ropt,
  1005. int *roptlen
  1006. )
  1007. {
  1008. PICMP_LOCAL_STORAGE localStorage, tmp;
  1009. PICMP_ECHO_REPLY reply;
  1010. PSTATUS_TABLE entry;
  1011. DWORD status;
  1012. //
  1013. // Find the reply.
  1014. //
  1015. EnterCriticalSection(&g_IcmpLock);
  1016. for ( localStorage = RequestHead, tmp = NULL;
  1017. localStorage != NULL;
  1018. localStorage = localStorage->Next
  1019. ) {
  1020. if (localStorage->IcmpHandle == fd) {
  1021. if (RequestHead == localStorage) {
  1022. RequestHead = localStorage->Next;
  1023. }
  1024. else {
  1025. tmp->Next = localStorage->Next;
  1026. }
  1027. break;
  1028. }
  1029. tmp = localStorage;
  1030. }
  1031. LeaveCriticalSection(&g_IcmpLock);
  1032. if (localStorage == NULL) {
  1033. SetLastError(POLL_FAILED);
  1034. return(-1);
  1035. }
  1036. //
  1037. // Process the reply.
  1038. //
  1039. if (localStorage->NumberOfReplies == 0) {
  1040. status = localStorage->Status;
  1041. reply = NULL;
  1042. }
  1043. else {
  1044. reply = (PICMP_ECHO_REPLY) localStorage->ReplyBuffer;
  1045. status = reply->Status;
  1046. }
  1047. if ((status == IP_SUCCESS) && (reply != NULL)) {
  1048. if (amount < reply->DataSize) {
  1049. status = POLL_FAILED;
  1050. goto der_error_exit;
  1051. }
  1052. CopyMemory(data, reply->Data, reply->DataSize);
  1053. *rettype = ECHO_REPLY;
  1054. }
  1055. else {
  1056. //
  1057. // Map to the appropriate old status code & return value.
  1058. //
  1059. if (status < IP_STATUS_BASE) {
  1060. status = POLL_FAILED;
  1061. goto der_error_exit;
  1062. }
  1063. if (status == IP_REQ_TIMED_OUT) {
  1064. status = POLL_TIMEOUT;
  1065. goto der_error_exit;
  1066. }
  1067. for ( entry = StatusTable;
  1068. entry->NewStatus != IP_GENERAL_FAILURE;
  1069. entry++
  1070. ) {
  1071. if (entry->NewStatus == status) {
  1072. *rettype = entry->OldStatus;
  1073. break;
  1074. }
  1075. }
  1076. if (entry->NewStatus == IP_GENERAL_FAILURE) {
  1077. status = POLL_FAILED;
  1078. goto der_error_exit;
  1079. }
  1080. }
  1081. if (reply != NULL) {
  1082. *retdf = reply->Options.Flags ? 1 : 0;
  1083. *retttl = reply->Options.Ttl;
  1084. *rettos = (reply->Options.Tos & 0xf0) >> 4;
  1085. *retprec = reply->Options.Tos & 0x0f;
  1086. if (ropt) {
  1087. if (reply->Options.OptionsSize > *roptlen) {
  1088. reply->Options.OptionsSize = (BYTE)*roptlen;
  1089. }
  1090. *roptlen = reply->Options.OptionsSize;
  1091. if (reply->Options.OptionsSize) {
  1092. CopyMemory(
  1093. ropt,
  1094. reply->Options.OptionsData,
  1095. reply->Options.OptionsSize
  1096. );
  1097. }
  1098. }
  1099. }
  1100. LocalFree(localStorage);
  1101. return(0);
  1102. der_error_exit:
  1103. LocalFree(localStorage);
  1104. SetLastError(status);
  1105. return(-1);
  1106. } // do_echo_rep
  1107. //////////////////////////////////////////////////////////////////////////////
  1108. //
  1109. // DLL entry point
  1110. //
  1111. //////////////////////////////////////////////////////////////////////////////
  1112. BOOL WINAPI
  1113. IcmpEntryPoint(
  1114. HANDLE hDll,
  1115. DWORD dwReason,
  1116. LPVOID lpReserved
  1117. )
  1118. {
  1119. OSVERSIONINFO versionInfo;
  1120. PICMP_LOCAL_STORAGE entry;
  1121. UNREFERENCED_PARAMETER(hDll);
  1122. UNREFERENCED_PARAMETER(lpReserved);
  1123. switch(dwReason) {
  1124. case DLL_PROCESS_ATTACH:
  1125. versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1126. if (!GetVersionEx(&versionInfo)) {
  1127. return(FALSE);
  1128. }
  1129. //
  1130. // NT 3.1 interface initialization
  1131. //
  1132. __try {
  1133. InitializeCriticalSection(&g_IcmpLock);
  1134. }
  1135. __except((GetExceptionCode() == STATUS_NO_MEMORY)
  1136. ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
  1137. return(FALSE);
  1138. }
  1139. if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
  1140. HINSTANCE WSock32Dll;
  1141. Platform = PLATFORM_VXD;
  1142. WSock32Dll = LoadLibrary("wsock32.dll");
  1143. if (WSock32Dll == NULL) {
  1144. return(FALSE);
  1145. }
  1146. wsControl = (LPWSCONTROL) GetProcAddress(
  1147. WSock32Dll,
  1148. "WsControl"
  1149. );
  1150. if (wsControl == NULL) {
  1151. return(FALSE);
  1152. }
  1153. }
  1154. else if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  1155. Platform = PLATFORM_NT;
  1156. }
  1157. else {
  1158. //
  1159. // Unsupported OS Version
  1160. //
  1161. return(FALSE);
  1162. }
  1163. break;
  1164. case DLL_PROCESS_DETACH:
  1165. //
  1166. // NT 3.1 interface cleanup
  1167. //
  1168. DeleteCriticalSection(&g_IcmpLock);
  1169. while((entry = RequestHead) != NULL) {
  1170. RequestHead = RequestHead->Next;
  1171. LocalFree(entry);
  1172. }
  1173. break;
  1174. default:
  1175. break;
  1176. }
  1177. return(TRUE);
  1178. } // DllEntryPoint