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.

1514 lines
40 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. PICMP_ECHO_REPLY reply;
  350. unsigned short i;
  351. if (ReplySize < sizeof(ICMP_ECHO_REPLY)) {
  352. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  353. return(0);
  354. }
  355. requestBufferSize = sizeof(ICMP_ECHO_REQUEST) + RequestSize;
  356. if (RequestOptions != NULL) {
  357. requestBufferSize += RequestOptions->OptionsSize;
  358. }
  359. if (requestBufferSize < ReplySize) {
  360. requestBufferSize = ReplySize;
  361. }
  362. requestBuffer = LocalAlloc(LMEM_FIXED, requestBufferSize);
  363. if (requestBuffer == NULL) {
  364. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  365. return(0);
  366. }
  367. //
  368. // Initialize the input buffer.
  369. //
  370. requestBuffer->Address = DestinationAddress;
  371. requestBuffer->Timeout = Timeout;
  372. requestBuffer->DataSize = RequestSize;
  373. requestBuffer->OptionsOffset = sizeof(ICMP_ECHO_REQUEST);
  374. if (RequestOptions != NULL) {
  375. requestBuffer->OptionsValid = 1;
  376. requestBuffer->Ttl = RequestOptions->Ttl;
  377. requestBuffer->Tos = RequestOptions->Tos;
  378. requestBuffer->Flags = RequestOptions->Flags;
  379. requestBuffer->OptionsSize = RequestOptions->OptionsSize;
  380. if (RequestOptions->OptionsSize > 0) {
  381. CopyMemory(
  382. ((UCHAR *) requestBuffer) + requestBuffer->OptionsOffset,
  383. RequestOptions->OptionsData,
  384. RequestOptions->OptionsSize
  385. );
  386. }
  387. }
  388. else {
  389. requestBuffer->OptionsValid = 0;
  390. requestBuffer->OptionsSize = 0;
  391. }
  392. requestBuffer->DataOffset = requestBuffer->OptionsOffset +
  393. requestBuffer->OptionsSize;
  394. if (RequestSize > 0) {
  395. CopyMemory(
  396. ((UCHAR *)requestBuffer) + requestBuffer->DataOffset,
  397. RequestData,
  398. RequestSize
  399. );
  400. }
  401. if (Platform == PLATFORM_NT) {
  402. IO_STATUS_BLOCK ioStatusBlock;
  403. NTSTATUS status;
  404. HANDLE eventHandle;
  405. eventHandle = CreateEvent(
  406. NULL, // default security
  407. FALSE, // auto reset
  408. FALSE, // initially non-signalled
  409. NULL // unnamed
  410. );
  411. if (NULL == eventHandle) {
  412. goto error_exit;
  413. }
  414. status = NtDeviceIoControlFile(
  415. IcmpHandle, // Driver handle
  416. eventHandle, // Event
  417. NULL, // APC Routine
  418. NULL, // APC context
  419. &ioStatusBlock, // Status block
  420. IOCTL_ICMP_ECHO_REQUEST, // Control code
  421. requestBuffer, // Input buffer
  422. requestBufferSize, // Input buffer size
  423. ReplyBuffer, // Output buffer
  424. ReplySize // Output buffer size
  425. );
  426. if (status == STATUS_PENDING) {
  427. status = NtWaitForSingleObject(
  428. eventHandle,
  429. FALSE,
  430. NULL
  431. );
  432. }
  433. CloseHandle(eventHandle);
  434. if (status != STATUS_SUCCESS) {
  435. SetLastError(RtlNtStatusToDosError(status));
  436. goto error_exit;
  437. }
  438. }
  439. else {
  440. //
  441. // VxD Platform
  442. //
  443. DWORD status;
  444. ULONG replyBufferSize = ReplySize;
  445. status = (*wsControl)(
  446. IPPROTO_TCP,
  447. WSCNTL_TCPIP_ICMP_ECHO,
  448. requestBuffer,
  449. &requestBufferSize,
  450. ReplyBuffer,
  451. &replyBufferSize
  452. );
  453. if (status != NO_ERROR) {
  454. SetLastError(status);
  455. goto error_exit;
  456. }
  457. }
  458. numberOfReplies = IcmpParseReplies(ReplyBuffer, ReplySize);
  459. error_exit:
  460. LocalFree(requestBuffer);
  461. return(numberOfReplies);
  462. } // IcmpSendEcho
  463. DWORD
  464. WINAPI
  465. IcmpSendEcho2(
  466. HANDLE IcmpHandle,
  467. HANDLE Event,
  468. PIO_APC_ROUTINE ApcRoutine,
  469. PVOID ApcContext,
  470. IPAddr DestinationAddress,
  471. LPVOID RequestData,
  472. WORD RequestSize,
  473. PIP_OPTION_INFORMATION RequestOptions,
  474. LPVOID ReplyBuffer,
  475. DWORD ReplySize,
  476. DWORD Timeout
  477. )
  478. /*++
  479. Routine Description:
  480. Sends an ICMP Echo request and the call returns either immediately
  481. (if Event or ApcRoutine is NonNULL) or returns after the specified
  482. timeout. The ReplyBuffer contains the ICMP responses, if any.
  483. Arguments:
  484. IcmpHandle - An open handle returned by ICMPCreateFile.
  485. Event - This is the event to be signalled whenever an IcmpResponse
  486. comes in.
  487. ApcRoutine - This routine would be called when the calling thread
  488. is in an alertable thread and an ICMP reply comes in.
  489. ApcContext - This optional parameter is given to the ApcRoutine when
  490. this call succeeds.
  491. DestinationAddress - The destination of the echo request.
  492. RequestData - A buffer containing the data to send in the
  493. request.
  494. RequestSize - The number of bytes in the request data buffer.
  495. RequestOptions - Pointer to the IP header options for the request.
  496. May be NULL.
  497. ReplyBuffer - A buffer to hold any replies to the request.
  498. On return, the buffer will contain an array of
  499. ICMP_ECHO_REPLY structures followed by options
  500. and data. The buffer must be large enough to
  501. hold at least one ICMP_ECHO_REPLY structure.
  502. It should be large enough to also hold
  503. 8 more bytes of data - this is the size of
  504. an ICMP error message + this should also have
  505. space for IO_STATUS_BLOCK which requires 8 or
  506. 16 bytes...
  507. ReplySize - The size in bytes of the reply buffer.
  508. Timeout - The time in milliseconds to wait for replies.
  509. This is NOT used if ApcRoutine is not NULL or if Event
  510. is not NULL.
  511. Return Value:
  512. Returns the number of replies received and stored in ReplyBuffer. If
  513. the return value is zero, extended error information is available
  514. via GetLastError().
  515. Remarks:
  516. On NT platforms,
  517. If used Asynchronously (either ApcRoutine or Event is specified), then
  518. ReplyBuffer and ReplySize are still needed. This is where the response
  519. comes in.
  520. ICMP Response data is copied to the ReplyBuffer provided, and the caller of
  521. this function has to parse it asynchronously. The function IcmpParseReply
  522. is provided for this purpose.
  523. On non-NT platforms,
  524. Event, ApcRoutine and ApcContext are IGNORED.
  525. --*/
  526. {
  527. PICMP_ECHO_REQUEST requestBuffer = NULL;
  528. ULONG requestBufferSize;
  529. DWORD numberOfReplies = 0;
  530. unsigned short i;
  531. BOOL Asynchronous;
  532. Asynchronous = (Platform == PLATFORM_NT && (Event || ApcRoutine));
  533. if (ReplySize < sizeof(ICMP_ECHO_REPLY)) {
  534. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  535. return(0);
  536. }
  537. requestBufferSize = sizeof(ICMP_ECHO_REQUEST) + RequestSize;
  538. if (RequestOptions != NULL) {
  539. requestBufferSize += RequestOptions->OptionsSize;
  540. }
  541. if (requestBufferSize < ReplySize) {
  542. requestBufferSize = ReplySize;
  543. }
  544. requestBuffer = LocalAlloc(LMEM_FIXED, requestBufferSize);
  545. if (requestBuffer == NULL) {
  546. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  547. return(0);
  548. }
  549. //
  550. // Initialize the input buffer.
  551. //
  552. requestBuffer->Address = DestinationAddress;
  553. requestBuffer->Timeout = Timeout;
  554. requestBuffer->DataSize = RequestSize;
  555. requestBuffer->OptionsOffset = sizeof(ICMP_ECHO_REQUEST);
  556. if (RequestOptions != NULL) {
  557. requestBuffer->OptionsValid = 1;
  558. requestBuffer->Ttl = RequestOptions->Ttl;
  559. requestBuffer->Tos = RequestOptions->Tos;
  560. requestBuffer->Flags = RequestOptions->Flags;
  561. requestBuffer->OptionsSize = RequestOptions->OptionsSize;
  562. if (RequestOptions->OptionsSize > 0) {
  563. CopyMemory(
  564. ((UCHAR *) requestBuffer) + requestBuffer->OptionsOffset,
  565. RequestOptions->OptionsData,
  566. RequestOptions->OptionsSize
  567. );
  568. }
  569. }
  570. else {
  571. requestBuffer->OptionsValid = 0;
  572. requestBuffer->OptionsSize = 0;
  573. }
  574. requestBuffer->DataOffset = requestBuffer->OptionsOffset +
  575. requestBuffer->OptionsSize;
  576. if (RequestSize > 0) {
  577. CopyMemory(
  578. ((UCHAR *)requestBuffer) + requestBuffer->DataOffset,
  579. RequestData,
  580. RequestSize
  581. );
  582. }
  583. if (Platform == PLATFORM_NT) {
  584. IO_STATUS_BLOCK *pioStatusBlock;
  585. NTSTATUS status;
  586. HANDLE eventHandle;
  587. //
  588. // allocate status block on the reply buffer..
  589. //
  590. pioStatusBlock = (IO_STATUS_BLOCK*)((LPBYTE)ReplyBuffer + ReplySize);
  591. pioStatusBlock --;
  592. pioStatusBlock = ROUND_DOWN_POINTER(pioStatusBlock, ALIGN_WORST);
  593. ReplySize = (ULONG)(((LPBYTE)pioStatusBlock) - (LPBYTE)ReplyBuffer );
  594. if( (PVOID)pioStatusBlock < ReplyBuffer
  595. || ReplySize < sizeof(ICMP_ECHO_REPLY) ) {
  596. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  597. goto error_exit;
  598. }
  599. if(!Asynchronous) { // Normal synchronous.
  600. eventHandle = CreateEvent(
  601. NULL, // default security
  602. FALSE, // auto reset
  603. FALSE, // initially non-signalled
  604. NULL // unnamed
  605. );
  606. if (NULL == eventHandle) {
  607. goto error_exit;
  608. }
  609. } else { // Asynchronous call.
  610. eventHandle = Event; // Use specified Event.
  611. }
  612. status = NtDeviceIoControlFile(
  613. IcmpHandle, // Driver handle
  614. eventHandle, // Event
  615. ApcRoutine, // APC Routine
  616. ApcContext, // APC context
  617. pioStatusBlock, // Status block
  618. IOCTL_ICMP_ECHO_REQUEST, // Control code
  619. requestBuffer, // Input buffer
  620. requestBufferSize, // Input buffer size
  621. ReplyBuffer, // Output buffer
  622. ReplySize // Output buffer size
  623. );
  624. if (Asynchronous) {
  625. // Asynchronous calls. We cannot give any information.
  626. // We let the user do the other work.
  627. SetLastError(RtlNtStatusToDosError(status));
  628. goto error_exit;
  629. }
  630. if (status == STATUS_PENDING) {
  631. status = NtWaitForSingleObject(
  632. eventHandle,
  633. FALSE,
  634. NULL
  635. );
  636. }
  637. CloseHandle(eventHandle);
  638. if (status != STATUS_SUCCESS) {
  639. SetLastError(RtlNtStatusToDosError(status));
  640. goto error_exit;
  641. }
  642. }
  643. else {
  644. //
  645. // VxD Platform
  646. //
  647. DWORD status;
  648. ULONG replyBufferSize = ReplySize;
  649. status = (*wsControl)(
  650. IPPROTO_TCP,
  651. WSCNTL_TCPIP_ICMP_ECHO,
  652. requestBuffer,
  653. &requestBufferSize,
  654. ReplyBuffer,
  655. &replyBufferSize
  656. );
  657. if (status != NO_ERROR) {
  658. SetLastError(status);
  659. goto error_exit;
  660. }
  661. }
  662. numberOfReplies = IcmpParseReplies2(ReplyBuffer, ReplySize);
  663. error_exit:
  664. LocalFree(requestBuffer);
  665. return(numberOfReplies);
  666. } // IcmpSendEcho2
  667. DWORD
  668. Icmp6ParseReplies(
  669. LPVOID ReplyBuffer,
  670. DWORD ReplySize
  671. )
  672. /*++
  673. Routine Description:
  674. Parses the reply buffer provided and returns the number of ICMPv6 responses
  675. found.
  676. Arguments:
  677. ReplyBuffer - This must be the same buffer that was passed to
  678. Icmp6SendEcho2. This is written to hold an array of
  679. ICMPV6_ECHO_REPLY structures (i.e., the type is
  680. PICMPV6_ECHO_REPLY).
  681. ReplySize - This must be the size of the above buffer.
  682. Return Value:
  683. Returns the number of ICMPv6 responses found. If there is an error,
  684. return value is zero. The error can be determined by a call to
  685. GetLastError.
  686. --*/
  687. {
  688. PICMPV6_ECHO_REPLY reply;
  689. unsigned short i;
  690. reply = ((PICMPV6_ECHO_REPLY) ReplyBuffer);
  691. if( NULL == reply || 0 == ReplySize ) {
  692. //
  693. // Invalid parameter passed. But we ignore this and just return # of
  694. // replies =0
  695. //
  696. return 0;
  697. }
  698. //
  699. // Convert new IP status IP_NEGOTIATING_IPSEC to IP_DEST_HOST_UNREACHABLE.
  700. //
  701. if (reply->Status == IP_NEGOTIATING_IPSEC) {
  702. reply->Status = IP_DEST_HOST_UNREACHABLE;
  703. }
  704. if ((reply->Status == IP_SUCCESS) || (reply->Status == IP_TTL_EXPIRED_TRANSIT)) {
  705. return 1;
  706. } else {
  707. //
  708. // Internal IP error. The error code is in the first reply slot.
  709. //
  710. SetLastError(reply->Status);
  711. return 0;
  712. }
  713. }
  714. DWORD
  715. WINAPI
  716. Icmp6SendEcho2(
  717. HANDLE IcmpHandle,
  718. HANDLE Event,
  719. PIO_APC_ROUTINE ApcRoutine,
  720. PVOID ApcContext,
  721. LPSOCKADDR_IN6 SourceAddress,
  722. LPSOCKADDR_IN6 DestinationAddress,
  723. LPVOID RequestData,
  724. WORD RequestSize,
  725. PIP_OPTION_INFORMATION RequestOptions,
  726. LPVOID ReplyBuffer,
  727. DWORD ReplySize,
  728. DWORD Timeout
  729. )
  730. /*++
  731. Routine Description:
  732. Sends an ICMPv6 Echo request and the call returns either immediately
  733. (if Event or ApcRoutine is NonNULL) or returns after the specified
  734. timeout. The ReplyBuffer contains the ICMPv6 responses, if any.
  735. Arguments:
  736. IcmpHandle - An open handle returned by ICMP6CreateFile.
  737. Event - This is the event to be signalled whenever an
  738. IcmpResponse comes in.
  739. ApcRoutine - This routine would be called when the calling thread
  740. is in an alertable thread and an ICMPv6 reply comes
  741. in.
  742. ApcContext - This optional parameter is given to the ApcRoutine
  743. when this call succeeds.
  744. DestinationAddress - The destination of the echo request.
  745. RequestData - A buffer containing the data to send in the
  746. request.
  747. RequestSize - The number of bytes in the request data buffer.
  748. RequestOptions - Pointer to the IPv6 header options for the request.
  749. May be NULL.
  750. ReplyBuffer - A buffer to hold any replies to the request.
  751. On return, the buffer will contain an array of
  752. ICMPV6_ECHO_REPLY structures followed by options
  753. and data. The buffer must be large enough to
  754. hold at least one ICMPV6_ECHO_REPLY structure.
  755. It should be large enough to also hold
  756. 8 more bytes of data - this is the size of
  757. an ICMPv6 error message + this should also have
  758. space for IO_STATUS_BLOCK which requires 8 or
  759. 16 bytes...
  760. ReplySize - The size in bytes of the reply buffer.
  761. Timeout - The time in milliseconds to wait for replies.
  762. This is NOT used if ApcRoutine is not NULL or if
  763. Event is not NULL.
  764. Return Value:
  765. Returns the number of replies received and stored in ReplyBuffer. If
  766. the return value is zero, extended error information is available
  767. via GetLastError().
  768. Remarks:
  769. If used Asynchronously (either ApcRoutine or Event is specified), then
  770. ReplyBuffer and ReplySize are still needed. This is where the response
  771. comes in.
  772. ICMP Response data is copied to the ReplyBuffer provided, and the caller of
  773. this function has to parse it asynchronously. The function Icmp6ParseReply
  774. is provided for this purpose.
  775. --*/
  776. {
  777. PICMPV6_ECHO_REQUEST requestBuffer = NULL;
  778. ULONG requestBufferSize;
  779. DWORD numberOfReplies = 0;
  780. unsigned short i;
  781. BOOL Asynchronous;
  782. IO_STATUS_BLOCK *pioStatusBlock;
  783. NTSTATUS status;
  784. HANDLE eventHandle;
  785. Asynchronous = (Platform == PLATFORM_NT && (Event || ApcRoutine));
  786. if (ReplySize < sizeof(ICMPV6_ECHO_REPLY)) {
  787. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  788. return(0);
  789. }
  790. requestBufferSize = sizeof(ICMPV6_ECHO_REQUEST) + RequestSize;
  791. requestBuffer = LocalAlloc(LMEM_FIXED, requestBufferSize);
  792. if (requestBuffer == NULL) {
  793. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  794. return(0);
  795. }
  796. if (Platform != PLATFORM_NT) {
  797. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  798. goto error_exit;
  799. }
  800. //
  801. // Initialize the input buffer.
  802. //
  803. CopyTDIFromSA6(&requestBuffer->DstAddress, DestinationAddress);
  804. CopyTDIFromSA6(&requestBuffer->SrcAddress, SourceAddress);
  805. requestBuffer->Timeout = Timeout;
  806. requestBuffer->TTL = RequestOptions->Ttl;
  807. requestBuffer->Flags = RequestOptions->Flags;
  808. if (RequestSize > 0) {
  809. CopyMemory(
  810. (UCHAR *)(requestBuffer + 1),
  811. RequestData,
  812. RequestSize
  813. );
  814. }
  815. //
  816. // allocate status block on the reply buffer..
  817. //
  818. pioStatusBlock = (IO_STATUS_BLOCK*)((LPBYTE)ReplyBuffer + ReplySize);
  819. pioStatusBlock --;
  820. pioStatusBlock = ROUND_DOWN_POINTER(pioStatusBlock, ALIGN_WORST);
  821. ReplySize = (ULONG)(((LPBYTE)pioStatusBlock) - (LPBYTE)ReplyBuffer );
  822. if( (PVOID)pioStatusBlock < ReplyBuffer
  823. || ReplySize < sizeof(ICMPV6_ECHO_REPLY) ) {
  824. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  825. goto error_exit;
  826. }
  827. if(!Asynchronous) { // Normal synchronous.
  828. eventHandle = CreateEvent(
  829. NULL, // default security
  830. FALSE, // auto reset
  831. FALSE, // initially non-signalled
  832. NULL // unnamed
  833. );
  834. if (NULL == eventHandle) {
  835. goto error_exit;
  836. }
  837. } else { // Asynchronous call.
  838. eventHandle = Event; // Use specified Event.
  839. }
  840. status = NtDeviceIoControlFile(
  841. IcmpHandle, // Driver handle
  842. eventHandle, // Event
  843. ApcRoutine, // APC Routine
  844. ApcContext, // APC context
  845. pioStatusBlock, // Status block
  846. IOCTL_ICMPV6_ECHO_REQUEST, // Control code
  847. requestBuffer, // Input buffer
  848. requestBufferSize, // Input buffer size
  849. ReplyBuffer, // Output buffer
  850. ReplySize // Output buffer size
  851. );
  852. if (Asynchronous) {
  853. // Asynchronous calls. We cannot give any information.
  854. // We let the user do the other work.
  855. SetLastError(RtlNtStatusToDosError(status));
  856. goto error_exit;
  857. }
  858. if (status == STATUS_PENDING) {
  859. status = NtWaitForSingleObject(
  860. eventHandle,
  861. FALSE,
  862. NULL
  863. );
  864. }
  865. CloseHandle(eventHandle);
  866. if (status != STATUS_SUCCESS) {
  867. SetLastError(RtlNtStatusToDosError(status));
  868. goto error_exit;
  869. }
  870. numberOfReplies = Icmp6ParseReplies(ReplyBuffer, ReplySize);
  871. error_exit:
  872. LocalFree(requestBuffer);
  873. return(numberOfReplies);
  874. }
  875. //
  876. // Constants
  877. //
  878. #define PING_WAIT 1000
  879. #define DEFAULT_TTL 32
  880. //
  881. // Local type definitions
  882. //
  883. typedef struct icmp_local_storage {
  884. struct icmp_local_storage *Next;
  885. HANDLE IcmpHandle;
  886. LPVOID ReplyBuffer;
  887. DWORD NumberOfReplies;
  888. DWORD Status;
  889. } ICMP_LOCAL_STORAGE, *PICMP_LOCAL_STORAGE;
  890. typedef struct status_table {
  891. IP_STATUS NewStatus;
  892. int OldStatus;
  893. } STATUS_TABLE, *PSTATUS_TABLE;
  894. //
  895. // Global variables
  896. //
  897. CRITICAL_SECTION g_IcmpLock;
  898. PICMP_LOCAL_STORAGE RequestHead = NULL;
  899. STATUS_TABLE StatusTable[] = {
  900. { IP_SUCCESS, ECHO_REPLY },
  901. { IP_DEST_NET_UNREACHABLE, DEST_UNR },
  902. { IP_DEST_HOST_UNREACHABLE, DEST_UNR },
  903. { IP_NEGOTIATING_IPSEC, DEST_UNR },
  904. { IP_DEST_PROT_UNREACHABLE, DEST_UNR },
  905. { IP_TTL_EXPIRED_TRANSIT, TIME_EXCEEDED },
  906. { IP_TTL_EXPIRED_REASSEM, TIME_EXCEEDED },
  907. { IP_PARAM_PROBLEM, PARAMETER_ERROR },
  908. { IP_BAD_ROUTE, PARAMETER_ERROR },
  909. { IP_BAD_OPTION, PARAMETER_ERROR },
  910. { IP_BUF_TOO_SMALL, PARAMETER_ERROR },
  911. { IP_PACKET_TOO_BIG, PARAMETER_ERROR },
  912. { IP_BAD_DESTINATION, PARAMETER_ERROR },
  913. { IP_GENERAL_FAILURE, POLL_FAILED }
  914. };
  915. HANDLE
  916. STRMAPI
  917. register_icmp(
  918. void
  919. )
  920. {
  921. HANDLE icmpHandle;
  922. icmpHandle = IcmpCreateFile();
  923. if (icmpHandle == INVALID_HANDLE_VALUE) {
  924. SetLastError(ICMP_OPEN_ERROR);
  925. return(ICMP_ERROR);
  926. }
  927. return(icmpHandle);
  928. } // register_icmp
  929. int
  930. STRMAPI
  931. do_echo_req(
  932. HANDLE fd,
  933. long addr,
  934. char *data,
  935. int amount,
  936. char *optptr,
  937. int optlen,
  938. int df,
  939. int ttl,
  940. int tos,
  941. int precedence
  942. )
  943. {
  944. PICMP_LOCAL_STORAGE localStorage;
  945. DWORD replySize;
  946. IP_OPTION_INFORMATION options;
  947. LPVOID replyBuffer;
  948. replySize = sizeof(ICMP_ECHO_REPLY) + amount + optlen;
  949. //
  950. // Allocate a buffer to hold the reply.
  951. //
  952. localStorage = (PICMP_LOCAL_STORAGE) LocalAlloc(
  953. LMEM_FIXED,
  954. replySize +
  955. sizeof(ICMP_LOCAL_STORAGE)
  956. );
  957. if (localStorage == NULL) {
  958. return((int)GetLastError());
  959. }
  960. replyBuffer = ((char *) localStorage) + sizeof(ICMP_LOCAL_STORAGE);
  961. if (ttl == 0) {
  962. options.Ttl = DEFAULT_TTL;
  963. }
  964. else {
  965. options.Ttl = (BYTE)ttl;
  966. }
  967. options.Tos = (tos << 4) | precedence;
  968. options.Flags = df ? IP_FLAG_DF : 0;
  969. options.OptionsSize = (BYTE)optlen;
  970. options.OptionsData = optptr;
  971. localStorage->NumberOfReplies = IcmpSendEcho(
  972. fd,
  973. (IPAddr) addr,
  974. data,
  975. (WORD)amount,
  976. &options,
  977. replyBuffer,
  978. replySize,
  979. PING_WAIT
  980. );
  981. if (localStorage->NumberOfReplies == 0) {
  982. localStorage->Status = GetLastError();
  983. }
  984. else {
  985. localStorage->Status = IP_SUCCESS;
  986. }
  987. localStorage->IcmpHandle = fd;
  988. localStorage->ReplyBuffer = replyBuffer;
  989. //
  990. // Save the reply for later retrieval.
  991. //
  992. EnterCriticalSection(&g_IcmpLock);
  993. localStorage->Next = RequestHead;
  994. RequestHead = localStorage;
  995. LeaveCriticalSection(&g_IcmpLock);
  996. return(0);
  997. } // do_echo_req
  998. int
  999. STRMAPI
  1000. do_echo_rep(
  1001. HANDLE fd,
  1002. char *data,
  1003. int amount,
  1004. int *rettype,
  1005. int *retttl,
  1006. int *rettos,
  1007. int *retprec,
  1008. int *retdf,
  1009. char *ropt,
  1010. int *roptlen
  1011. )
  1012. {
  1013. PICMP_LOCAL_STORAGE localStorage, tmp;
  1014. PICMP_ECHO_REPLY reply;
  1015. PSTATUS_TABLE entry;
  1016. DWORD status;
  1017. //
  1018. // Find the reply.
  1019. //
  1020. EnterCriticalSection(&g_IcmpLock);
  1021. for ( localStorage = RequestHead, tmp = NULL;
  1022. localStorage != NULL;
  1023. localStorage = localStorage->Next
  1024. ) {
  1025. if (localStorage->IcmpHandle == fd) {
  1026. if (RequestHead == localStorage) {
  1027. RequestHead = localStorage->Next;
  1028. }
  1029. else {
  1030. tmp->Next = localStorage->Next;
  1031. }
  1032. break;
  1033. }
  1034. tmp = localStorage;
  1035. }
  1036. LeaveCriticalSection(&g_IcmpLock);
  1037. if (localStorage == NULL) {
  1038. SetLastError(POLL_FAILED);
  1039. return(-1);
  1040. }
  1041. //
  1042. // Process the reply.
  1043. //
  1044. if (localStorage->NumberOfReplies == 0) {
  1045. status = localStorage->Status;
  1046. reply = NULL;
  1047. }
  1048. else {
  1049. reply = (PICMP_ECHO_REPLY) localStorage->ReplyBuffer;
  1050. status = reply->Status;
  1051. }
  1052. if ((status == IP_SUCCESS) && (reply != NULL)) {
  1053. if (amount < reply->DataSize) {
  1054. status = POLL_FAILED;
  1055. goto der_error_exit;
  1056. }
  1057. CopyMemory(data, reply->Data, reply->DataSize);
  1058. *rettype = ECHO_REPLY;
  1059. }
  1060. else {
  1061. //
  1062. // Map to the appropriate old status code & return value.
  1063. //
  1064. if (status < IP_STATUS_BASE) {
  1065. status = POLL_FAILED;
  1066. goto der_error_exit;
  1067. }
  1068. if (status == IP_REQ_TIMED_OUT) {
  1069. status = POLL_TIMEOUT;
  1070. goto der_error_exit;
  1071. }
  1072. for ( entry = StatusTable;
  1073. entry->NewStatus != IP_GENERAL_FAILURE;
  1074. entry++
  1075. ) {
  1076. if (entry->NewStatus == status) {
  1077. *rettype = entry->OldStatus;
  1078. break;
  1079. }
  1080. }
  1081. if (entry->NewStatus == IP_GENERAL_FAILURE) {
  1082. status = POLL_FAILED;
  1083. goto der_error_exit;
  1084. }
  1085. }
  1086. if (reply != NULL) {
  1087. *retdf = reply->Options.Flags ? 1 : 0;
  1088. *retttl = reply->Options.Ttl;
  1089. *rettos = (reply->Options.Tos & 0xf0) >> 4;
  1090. *retprec = reply->Options.Tos & 0x0f;
  1091. if (ropt) {
  1092. if (reply->Options.OptionsSize > *roptlen) {
  1093. reply->Options.OptionsSize = (BYTE)*roptlen;
  1094. }
  1095. *roptlen = reply->Options.OptionsSize;
  1096. if (reply->Options.OptionsSize) {
  1097. CopyMemory(
  1098. ropt,
  1099. reply->Options.OptionsData,
  1100. reply->Options.OptionsSize
  1101. );
  1102. }
  1103. }
  1104. }
  1105. LocalFree(localStorage);
  1106. return(0);
  1107. der_error_exit:
  1108. LocalFree(localStorage);
  1109. SetLastError(status);
  1110. return(-1);
  1111. } // do_echo_rep
  1112. //////////////////////////////////////////////////////////////////////////////
  1113. //
  1114. // DLL entry point
  1115. //
  1116. //////////////////////////////////////////////////////////////////////////////
  1117. BOOL WINAPI
  1118. IcmpEntryPoint(
  1119. HANDLE hDll,
  1120. DWORD dwReason,
  1121. LPVOID lpReserved
  1122. )
  1123. {
  1124. OSVERSIONINFO versionInfo;
  1125. PICMP_LOCAL_STORAGE entry;
  1126. UNREFERENCED_PARAMETER(hDll);
  1127. UNREFERENCED_PARAMETER(lpReserved);
  1128. switch(dwReason) {
  1129. case DLL_PROCESS_ATTACH:
  1130. versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1131. if (!GetVersionEx(&versionInfo)) {
  1132. return(FALSE);
  1133. }
  1134. //
  1135. // NT 3.1 interface initialization
  1136. //
  1137. InitializeCriticalSection(&g_IcmpLock);
  1138. if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
  1139. HINSTANCE WSock32Dll;
  1140. Platform = PLATFORM_VXD;
  1141. WSock32Dll = LoadLibrary("wsock32.dll");
  1142. if (WSock32Dll == NULL) {
  1143. return(FALSE);
  1144. }
  1145. wsControl = (LPWSCONTROL) GetProcAddress(
  1146. WSock32Dll,
  1147. "WsControl"
  1148. );
  1149. if (wsControl == NULL) {
  1150. return(FALSE);
  1151. }
  1152. }
  1153. else if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  1154. Platform = PLATFORM_NT;
  1155. }
  1156. else {
  1157. //
  1158. // Unsupported OS Version
  1159. //
  1160. return(FALSE);
  1161. }
  1162. break;
  1163. case DLL_PROCESS_DETACH:
  1164. //
  1165. // NT 3.1 interface cleanup
  1166. //
  1167. DeleteCriticalSection(&g_IcmpLock);
  1168. while((entry = RequestHead) != NULL) {
  1169. RequestHead = RequestHead->Next;
  1170. LocalFree(entry);
  1171. }
  1172. break;
  1173. default:
  1174. break;
  1175. }
  1176. return(TRUE);
  1177. } // DllEntryPoint