4 * Francois Gouget, 1999, based on the work of
5 * RW Hall, 1999, based on public domain code PING.C by Mike Muus (1983)
6 * and later works (c) 1989 Regents of Univ. of California - see copyright
7 * notice at end of source-code.
8 * Copyright 2015 Sebastian Lackner
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * - Systems like FreeBSD don't seem to support the IP_TTL option and maybe others.
27 * But using IP_HDRINCL and building the IP header by hand might work.
28 * - Not all IP options are supported.
29 * - Are ICMP handles real handles, i.e. inheritable and all? There might be some
30 * more work to do here, including server side stuff with synchronization.
31 * - This API should probably be thread safe. Is it really?
32 * - Using the winsock functions has not been tested.
35 #include "iphlpapi_private.h"
37 /* Set up endianness macros for the ip and ip_icmp BSD headers */
39 #define BIG_ENDIAN 4321
42 #define LITTLE_ENDIAN 1234
45 #ifdef WORDS_BIGENDIAN
46 #define BYTE_ORDER BIG_ENDIAN
48 #define BYTE_ORDER LITTLE_ENDIAN
50 #endif /* BYTE_ORDER */
52 #define u_int16_t WORD
53 #define u_int32_t DWORD
55 /* These are BSD headers. We use these here because they are needed on
56 * libc5 Linux systems. On other platforms they are usually simply more
57 * complete than the native stuff, and cause less portability problems
58 * so we use them anyway.
64 WINE_DEFAULT_DEBUG_CHANNEL(icmp
);
65 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
70 IP_OPTION_INFORMATION default_opts
;
73 #define IP_OPTS_UNKNOWN 0
74 #define IP_OPTS_DEFAULT 1
75 #define IP_OPTS_CUSTOM 2
77 /* The sequence number is unique process wide, so that all threads
78 * have a distinct sequence number.
80 static LONG icmp_sequence
=0;
82 static int in_cksum(u_short
*addr
, int len
)
95 *(u_char
*)(&answer
) = *(u_char
*)w
;
99 sum
= (sum
>> 16) + (sum
& 0xffff);
111 /***********************************************************************
112 * Icmp6CreateFile (IPHLPAPI.@)
114 HANDLE WINAPI
Icmp6CreateFile(VOID
)
121 if (WSAStartup(MAKEWORD(2, 2), &wsaData
) != ERROR_SUCCESS
)
123 ERR_(winediag
)("Failed to use ICMPV6 (network ping), this requires special permissions.\n");
124 return INVALID_HANDLE_VALUE
;
128 sid
=socket(AF_INET6
,SOCK_RAW
,IPPROTO_ICMPV6
);
132 /* Mac OS X supports non-privileged ICMP via SOCK_DGRAM type. */
133 sid
=socket(AF_INET6
,SOCK_DGRAM
,IPPROTO_ICMPV6
);
137 ERR_(winediag
)("Failed to use ICMPV6 (network ping), this requires special permissions.\n");
138 SetLastError(ERROR_ACCESS_DENIED
);
139 return INVALID_HANDLE_VALUE
;
142 icp
=HeapAlloc(GetProcessHeap(), 0, sizeof(*icp
));
150 SetLastError(IP_NO_RESOURCES
);
151 return INVALID_HANDLE_VALUE
;
154 icp
->default_opts
.OptionsSize
=IP_OPTS_UNKNOWN
;
159 /***********************************************************************
160 * Icmp6SendEcho2 (IPHLPAPI.@)
162 DWORD WINAPI
Icmp6SendEcho2(
165 PIO_APC_ROUTINE ApcRoutine
,
167 struct sockaddr_in6
* SourceAddress
,
168 struct sockaddr_in6
* DestinationAddress
,
171 PIP_OPTION_INFORMATION RequestOptions
,
177 FIXME("(%p, %p, %p, %p, %p, %p, %p, %d, %p, %p, %d, %d): stub\n", IcmpHandle
, Event
,
178 ApcRoutine
, ApcContext
, SourceAddress
, DestinationAddress
, RequestData
,
179 RequestSize
, RequestOptions
, ReplyBuffer
, ReplySize
, Timeout
);
180 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
185 /***********************************************************************
186 * IcmpCreateFile (IPHLPAPI.@)
188 HANDLE WINAPI
IcmpCreateFile(VOID
)
198 if (WSAStartup(MAKEWORD(2, 2), &wsaData
) != ERROR_SUCCESS
)
200 ERR_(winediag
)("Failed to use ICMPV6 (network ping), this requires special permissions.\n");
201 return INVALID_HANDLE_VALUE
;
204 sid
=socket(AF_INET
,SOCK_RAW
,IPPROTO_ICMP
);
207 ERR_(winediag
)("Failed to use ICMP (network ping), this requires special permissions.\n");
208 SetLastError(ERROR_ACCESS_DENIED
);
209 return INVALID_HANDLE_VALUE
;
214 /* Mac OS X supports non-privileged ICMP via SOCK_DGRAM type. */
215 sid
=socket(AF_INET
,SOCK_DGRAM
,IPPROTO_ICMP
);
217 if (sid
< 0 && !once
++) {
218 FIXME_(winediag
)("Failed to use ICMP (network ping), this requires special permissions.\n");
219 FIXME_(winediag
)("Falling back to system 'ping' command as a workaround.\n");
223 icp
=HeapAlloc(GetProcessHeap(), 0, sizeof(*icp
));
229 if (sid
>= 0) close(sid
);
231 SetLastError(IP_NO_RESOURCES
);
232 return INVALID_HANDLE_VALUE
;
235 icp
->default_opts
.OptionsSize
=IP_OPTS_UNKNOWN
;
240 /***********************************************************************
241 * IcmpCloseHandle (IPHLPAPI.@)
243 BOOL WINAPI
IcmpCloseHandle(HANDLE IcmpHandle
)
245 icmp_t
* icp
=(icmp_t
*)IcmpHandle
;
246 // REACTOS: Added a check for NULL handle, CORE-10707
247 if (IcmpHandle
==INVALID_HANDLE_VALUE
|| IcmpHandle
==NULL
) {
248 /* FIXME: in fact win98 seems to ignore the handle value !!! */
249 SetLastError(ERROR_INVALID_HANDLE
);
254 shutdown(icp
->sid
,2);
256 if (icp
->sid
>= 0) close(icp
->sid
);
258 HeapFree(GetProcessHeap (), 0, icp
);
266 static DWORD
system_icmp(
267 IPAddr DestinationAddress
,
270 PIP_OPTION_INFORMATION RequestOptions
,
277 ICMP_ECHO_REPLY
*reply
= ReplyBuffer
;
278 char ntoa_buffer
[16]; /* 4*3 digits + 3 '.' + 1 '\0' */
279 char size_buffer
[6]; /* 5 digits + '\0' */
280 char tos_buffer
[4]; /* 3 digits + '\0' */
281 char ttl_buffer
[4]; /* 3 digits + '\0' */
282 char time_buffer
[11]; /* 10 digits + '\0' */
283 int i
, pos
, res
, status
, argc
;
284 const char *argv
[20];
291 /* Assemble the ping commandline */
293 argv
[argc
++] = "ping";
294 argv
[argc
++] = "-c"; /* only send a single ping */
296 argv
[argc
++] = "-n"; /* numeric output only */
297 argv
[argc
++] = "-s"; /* request size */
298 sprintf(size_buffer
, "%u", (RequestSize
>= 16) ? RequestSize
: 16);
299 argv
[argc
++] = size_buffer
;
300 argv
[argc
++] = "-W"; /* timeout */
302 /* The linux 'ping' utlity expects a time in seconds */
303 Timeout
= (Timeout
+ 999) / 1000;
305 sprintf(time_buffer
, "%u", Timeout
);
306 argv
[argc
++] = time_buffer
;
311 argv
[argc
++] = "-Q"; /* tos option */
313 argv
[argc
++] = "-z"; /* tos option */
315 sprintf(tos_buffer
, "%u", RequestOptions
->Tos
);
316 argv
[argc
++] = tos_buffer
;
318 /* TTL can only be specified for multicast addresses on FreeBSD/MacOS */
319 argv
[argc
++] = "-t"; /* ttl option */
320 sprintf(ttl_buffer
, "%u", RequestOptions
->Ttl
);
321 argv
[argc
++] = ttl_buffer
;
325 addr
.s_addr
= DestinationAddress
;
326 if (!(ptr
= inet_ntoa(addr
)))
328 SetLastError(ERROR_INVALID_PARAMETER
);
331 strcpy(ntoa_buffer
, ptr
);
332 argv
[argc
++] = ntoa_buffer
;
335 /* Dump commandline for debugging purposes */
336 TRACE("Ping commandline: ");
337 for (i
= 0; i
< argc
; i
++)
339 TRACE("%s ", debugstr_a(argv
[i
]));
343 /* Prefill the reply struct with fallback values */
344 memset(reply
, 0, sizeof(*reply
));
345 reply
->Address
= DestinationAddress
;
346 reply
->RoundTripTime
= 40;
347 reply
->Options
.Ttl
= 120;
349 /* Create communication pipes */
351 if (pipe2(pipe_out
, O_CLOEXEC
) < 0)
354 if (pipe(pipe_out
) < 0)
356 SetLastError(ERROR_OUTOFMEMORY
);
359 fcntl(pipe_out
[0], F_SETFD
, FD_CLOEXEC
);
360 fcntl(pipe_out
[1], F_SETFD
, FD_CLOEXEC
);
363 /* Fork child process */
369 SetLastError(ERROR_OUTOFMEMORY
);
376 static char lang_env
[] = "LANG=C";
378 dup2(pipe_out
[1], 1);
385 execvp(argv
[0], (char **)argv
);
391 /* Wait for child and read output */
395 if (pos
>= sizeof(buf
) - 1)
397 ERR("line too long, dropping buffer\n");
401 /* read next block */
404 res
= read(pipe_out
[0], &buf
[pos
], (sizeof(buf
) - 1) - pos
);
406 while (res
< 0 && errno
== EINTR
);
409 ERR("read failed: %s\n", strerror(errno
));
416 eol
= memchr(buf
, '\n', pos
);
420 TRACE("Received line: %s\n", debugstr_a(buf
));
422 /* Interpret address */
423 if ((ptr
= strstr(buf
, "from ")))
426 if (sscanf(ptr
+ 5, "%u.%u.%u.%u", &a
, &b
, &c
, &d
) >= 4)
428 reply
->Address
= a
| (b
<< 8) | (c
<< 16) | (d
<< 24);
429 addr
.s_addr
= reply
->Address
;
430 TRACE("Got address %s\n", inet_ntoa(addr
));
435 if ((ptr
= strstr(buf
, "ttl=")))
438 if (sscanf(ptr
+ 4, "%u", &val
) >= 1)
440 reply
->Options
.Ttl
= val
;
441 TRACE("Got ttl %u\n", val
);
446 if ((ptr
= strstr(buf
, "time=")))
449 if (sscanf(ptr
+ 5, "%f", &val
) >= 1)
451 reply
->RoundTripTime
= (unsigned int)(val
+ 0.5);
452 TRACE("Got rtt = %u\n", reply
->RoundTripTime
);
456 memmove(buf
, eol
+ 1, pos
- (eol
+ 1 - buf
));
457 pos
-= (eol
+ 1 - buf
);
463 /* reap the child process */
466 wpid
= waitpid(pid
, &status
, 0);
468 while (wpid
< 0 && errno
== EINTR
);
470 /* fill out remaining struct fields */
471 if (wpid
>= 0 && WIFEXITED(status
) && WEXITSTATUS(status
) == 0)
473 if (ReplySize
< RequestSize
+ sizeof(*reply
))
475 reply
->Status
= IP_BUF_TOO_SMALL
;
482 reply
->DataSize
= RequestSize
;
483 reply
->Data
= (char *)reply
+ sizeof(*reply
);
484 memcpy(reply
->Data
, RequestData
, RequestSize
);
489 SetLastError(IP_REQ_TIMED_OUT
);
492 ERR("no fork support on this platform\n");
493 SetLastError(ERROR_NOT_SUPPORTED
);
502 _Out_ IPAddr
* Address
505 PMIB_IPADDRTABLE pIpAddrTable
;
509 if (GetIpAddrTable(NULL
, &dwSize
, FALSE
) != ERROR_INSUFFICIENT_BUFFER
)
513 pIpAddrTable
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
515 if (GetIpAddrTable(pIpAddrTable
, &dwSize
, FALSE
) == NO_ERROR
)
519 for (i
= 0; i
< (*pIpAddrTable
).dwNumEntries
; i
++)
521 if ((*pIpAddrTable
).table
[i
].dwIndex
== Index
)
523 *Address
= (IPAddr
)(*pIpAddrTable
).table
[i
].dwAddr
;
529 HeapFree(GetProcessHeap(), 0, pIpAddrTable
);
533 /***********************************************************************
534 * IcmpSendEcho (IPHLPAPI.@)
536 DWORD WINAPI
IcmpSendEcho(
538 IPAddr DestinationAddress
,
541 PIP_OPTION_INFORMATION RequestOptions
,
547 icmp_t
* icp
=(icmp_t
*)IcmpHandle
;
548 unsigned char* reqbuf
;
551 struct icmp_echo_reply
* ier
;
552 struct ip
* ip_header
;
553 struct icmp
* icmp_header
;
559 struct timeval timeout
;
563 DWORD send_time
,recv_time
;
564 struct sockaddr_in addr
;
566 unsigned short id
,seq
,cksum
;
569 if (IcmpHandle
==INVALID_HANDLE_VALUE
) {
570 /* FIXME: in fact win98 seems to ignore the handle value !!! */
571 SetLastError(ERROR_INVALID_HANDLE
);
575 if (ReplySize
<sizeof(ICMP_ECHO_REPLY
)) {
576 SetLastError(ERROR_INVALID_PARAMETER
);
580 if (ReplySize
-RequestSize
<sizeof(ICMP_ECHO_REPLY
)) {
581 SetLastError(IP_GENERAL_FAILURE
);
586 SetLastError(ERROR_INVALID_PARAMETER
);
590 if (Timeout
== 0 || Timeout
== -1) {
591 SetLastError(ERROR_INVALID_PARAMETER
);
594 /* check the request size against SO_MAX_MSG_SIZE using getsockopt */
596 if (!DestinationAddress
) {
597 SetLastError(ERROR_INVALID_NETNAME
);
603 WARN("using system ping command since SOCK_RAW was not supported.\n");
604 return system_icmp(DestinationAddress
, RequestData
, RequestSize
,
605 RequestOptions
, ReplyBuffer
, ReplySize
, Timeout
);
608 /* Prepare the request */
610 id
= GetCurrentProcessId() & 0xFFFF;
612 id
=getpid() & 0xFFFF;
614 seq
=InterlockedIncrement(&icmp_sequence
) & 0xFFFF;
617 if (RequestData
&& RequestSize
> 0)
618 reqsize
+= RequestSize
;
619 reqbuf
=HeapAlloc(GetProcessHeap(), 0, reqsize
);
621 SetLastError(ERROR_OUTOFMEMORY
);
625 icmp_header
=(struct icmp
*)reqbuf
;
626 icmp_header
->icmp_type
=ICMP_ECHO
;
627 icmp_header
->icmp_code
=0;
628 icmp_header
->icmp_cksum
=0;
629 icmp_header
->icmp_id
=id
;
630 icmp_header
->icmp_seq
=seq
;
631 if (RequestData
&& RequestSize
> 0)
632 memcpy(reqbuf
+ICMP_MINLEN
, RequestData
, RequestSize
);
633 icmp_header
->icmp_cksum
=cksum
=in_cksum((u_short
*)reqbuf
,reqsize
);
635 addr
.sin_family
=AF_INET
;
636 addr
.sin_addr
.s_addr
=DestinationAddress
;
639 if (RequestOptions
!=NULL
) {
641 if (icp
->default_opts
.OptionsSize
==IP_OPTS_UNKNOWN
) {
643 /* Before we mess with the options, get the default values */
645 getsockopt(icp
->sid
,IPPROTO_IP
,IP_TTL
,(char *)&val
,&len
);
646 icp
->default_opts
.Ttl
=val
;
649 getsockopt(icp
->sid
,IPPROTO_IP
,IP_TOS
,(char *)&val
,&len
);
650 icp
->default_opts
.Tos
=val
;
651 /* FIXME: missing: handling of IP 'flags', and all the other options */
654 val
=RequestOptions
->Ttl
;
655 setsockopt(icp
->sid
,IPPROTO_IP
,IP_TTL
,(char *)&val
,sizeof(val
));
656 val
=RequestOptions
->Tos
;
657 setsockopt(icp
->sid
,IPPROTO_IP
,IP_TOS
,(char *)&val
,sizeof(val
));
658 /* FIXME: missing: handling of IP 'flags', and all the other options */
660 icp
->default_opts
.OptionsSize
=IP_OPTS_CUSTOM
;
661 } else if (icp
->default_opts
.OptionsSize
==IP_OPTS_CUSTOM
) {
664 /* Restore the default options */
665 val
=icp
->default_opts
.Ttl
;
666 setsockopt(icp
->sid
,IPPROTO_IP
,IP_TTL
,(char *)&val
,sizeof(val
));
667 val
=icp
->default_opts
.Tos
;
668 setsockopt(icp
->sid
,IPPROTO_IP
,IP_TOS
,(char *)&val
,sizeof(val
));
669 /* FIXME: missing: handling of IP 'flags', and all the other options */
671 icp
->default_opts
.OptionsSize
=IP_OPTS_DEFAULT
;
674 /* Get ready for receiving the reply
675 * Do it before we send the request to minimize the risk of introducing delays
679 FD_SET(icp
->sid
,&fdr
);
680 timeout
.tv_sec
=Timeout
/1000;
681 timeout
.tv_usec
=(Timeout
% 1000)*1000;
686 addrlen
=sizeof(addr
);
688 endbuf
=((char *) ReplyBuffer
)+ReplySize
;
689 maxlen
=sizeof(struct ip
)+ICMP_MINLEN
+RequestSize
;
691 /* Send the packet */
692 TRACE("Sending %d bytes (RequestSize=%d) to %s\n", reqsize
, RequestSize
, inet_ntoa(addr
.sin_addr
));
695 unsigned char* buf
=(unsigned char*)reqbuf
;
697 printf("Output buffer:\n");
698 for (i
=0;i
<reqsize
;i
++)
699 printf("%2x,", buf
[i
]);
704 send_time
= GetTickCount();
705 res
=sendto(icp
->sid
, (const char*)reqbuf
, reqsize
, 0, (struct sockaddr
*)&addr
, sizeof(addr
));
706 HeapFree(GetProcessHeap (), 0, reqbuf
);
711 ZeroMemory(&ier
->Address
, sizeof(ier
->Address
));
713 if (GetBestInterface(addr
.sin_addr
.s_addr
, &dwBestIfIndex
) == NO_ERROR
&&
714 GetIPv4ByIndex(dwBestIfIndex
, &IP4Addr
))
716 memcpy(&ier
->Address
, &IP4Addr
, sizeof(IP4Addr
));
719 if (WSAGetLastError()==WSAEMSGSIZE
)
720 ier
->Status
= IP_PACKET_TOO_BIG
;
722 switch (WSAGetLastError()) {
724 ier
->Status
= IP_DEST_NET_UNREACHABLE
;
726 case WSAEHOSTUNREACH
:
727 ier
->Status
= IP_DEST_HOST_UNREACHABLE
;
730 TRACE("unknown error: errno=%d\n",WSAGetLastError());
731 ier
->Status
= IP_GENERAL_FAILURE
;
732 ZeroMemory(&ier
->Address
, sizeof(ier
->Address
));
739 ip_header
=HeapAlloc(GetProcessHeap(), 0, maxlen
);
740 ip_header_len
=0; /* because gcc was complaining */
742 while ((res
=select(icp
->sid
+1,&fdr
,NULL
,NULL
,&timeout
))>0) {
744 while (poll(&fdr
,1,Timeout
)>0) {
746 recv_time
= GetTickCount();
747 res
=recvfrom(icp
->sid
, (char*)ip_header
, maxlen
, 0, (struct sockaddr
*)&addr
,(int*)&addrlen
);
748 TRACE("received %d bytes from %s\n",res
, inet_ntoa(addr
.sin_addr
));
749 ier
->Status
=IP_REQ_TIMED_OUT
;
753 /* Check whether we should ignore this packet */
754 if ((ip_header
->ip_p
==IPPROTO_ICMP
) && (res
>=sizeof(struct ip
)+ICMP_MINLEN
)) {
755 ip_header_len
=ip_header
->ip_hl
<< 2;
756 icmp_header
=(struct icmp
*)(((char*)ip_header
)+ip_header_len
);
757 TRACE("received an ICMP packet of type,code=%d,%d\n",icmp_header
->icmp_type
,icmp_header
->icmp_code
);
758 if (icmp_header
->icmp_type
==ICMP_ECHOREPLY
) {
759 if ((icmp_header
->icmp_id
==id
) && (icmp_header
->icmp_seq
==seq
))
760 ier
->Status
=IP_SUCCESS
;
762 switch (icmp_header
->icmp_type
) {
764 switch (icmp_header
->icmp_code
) {
765 case ICMP_UNREACH_HOST
:
766 #ifdef ICMP_UNREACH_HOST_UNKNOWN
767 case ICMP_UNREACH_HOST_UNKNOWN
:
769 #ifdef ICMP_UNREACH_ISOLATED
770 case ICMP_UNREACH_ISOLATED
:
772 #ifdef ICMP_UNREACH_HOST_PROHIB
773 case ICMP_UNREACH_HOST_PROHIB
:
775 #ifdef ICMP_UNREACH_TOSHOST
776 case ICMP_UNREACH_TOSHOST
:
778 ier
->Status
=IP_DEST_HOST_UNREACHABLE
;
780 case ICMP_UNREACH_PORT
:
781 ier
->Status
=IP_DEST_PORT_UNREACHABLE
;
783 case ICMP_UNREACH_PROTOCOL
:
784 ier
->Status
=IP_DEST_PROT_UNREACHABLE
;
786 case ICMP_UNREACH_SRCFAIL
:
787 ier
->Status
=IP_BAD_ROUTE
;
790 ier
->Status
=IP_DEST_NET_UNREACHABLE
;
794 if (icmp_header
->icmp_code
==ICMP_TIMXCEED_REASS
)
795 ier
->Status
=IP_TTL_EXPIRED_REASSEM
;
797 ier
->Status
=IP_TTL_EXPIRED_TRANSIT
;
800 ier
->Status
=IP_PARAM_PROBLEM
;
802 case ICMP_SOURCEQUENCH
:
803 ier
->Status
=IP_SOURCE_QUENCH
;
806 if (ier
->Status
!=IP_REQ_TIMED_OUT
) {
807 struct ip
* rep_ip_header
;
808 struct icmp
* rep_icmp_header
;
809 /* The ICMP header size of all the packets we accept is the same */
810 rep_ip_header
=(struct ip
*)(((char*)icmp_header
)+ICMP_MINLEN
);
811 rep_icmp_header
=(struct icmp
*)(((char*)rep_ip_header
)+(rep_ip_header
->ip_hl
<< 2));
813 /* Make sure that this is really a reply to our packet */
814 if (ip_header_len
+ICMP_MINLEN
+(rep_ip_header
->ip_hl
<< 2)+ICMP_MINLEN
>ip_header
->ip_len
) {
815 ier
->Status
=IP_REQ_TIMED_OUT
;
816 } else if ((rep_icmp_header
->icmp_type
!=ICMP_ECHO
) ||
817 (rep_icmp_header
->icmp_code
!=0) ||
818 (rep_icmp_header
->icmp_id
!=id
) ||
819 /* windows doesn't check this checksum, else tracert */
820 /* behind a Linux 2.2 masquerading firewall would fail*/
821 /* (rep_icmp_header->icmp_cksum!=cksum) || */
822 (rep_icmp_header
->icmp_seq
!=seq
)) {
823 /* This was not a reply to one of our packets after all */
824 TRACE("skipping type,code=%d,%d id,seq=%d,%d cksum=%d\n",
825 rep_icmp_header
->icmp_type
,rep_icmp_header
->icmp_code
,
826 rep_icmp_header
->icmp_id
,rep_icmp_header
->icmp_seq
,
827 rep_icmp_header
->icmp_cksum
);
828 TRACE("expected type,code=8,0 id,seq=%d,%d cksum=%d\n",
831 ier
->Status
=IP_REQ_TIMED_OUT
;
837 if (ier
->Status
==IP_REQ_TIMED_OUT
) {
838 /* This packet was not for us.
839 * Decrease the timeout so that we don't enter an endless loop even
840 * if we get flooded with ICMP packets that are not for us.
843 int t
= Timeout
- (recv_time
- send_time
);
845 timeout
.tv_sec
= t
/ 1000;
846 timeout
.tv_usec
= (t
% 1000) * 1000;
848 FD_SET(icp
->sid
, &fdr
);
850 DWORD t
= (recv_time
- send_time
);
851 if (Timeout
> t
) Timeout
-= t
;
856 /* This is a reply to our packet */
857 memcpy(&ier
->Address
,&ip_header
->ip_src
,sizeof(IPAddr
));
858 /* Status is already set */
859 ier
->RoundTripTime
= recv_time
- send_time
;
860 ier
->DataSize
=res
-ip_header_len
-ICMP_MINLEN
;
862 ier
->Data
=endbuf
-ier
->DataSize
;
863 memmove(ier
->Data
,((char*)ip_header
)+ip_header_len
+ICMP_MINLEN
,ier
->DataSize
);
864 ier
->Options
.Ttl
=ip_header
->ip_ttl
;
865 ier
->Options
.Tos
=ip_header
->ip_tos
;
866 ier
->Options
.Flags
=ip_header
->ip_off
>> 13;
867 ier
->Options
.OptionsSize
=ip_header_len
-sizeof(struct ip
);
868 if (ier
->Options
.OptionsSize
!=0) {
869 ier
->Options
.OptionsData
=(unsigned char *) ier
->Data
-ier
->Options
.OptionsSize
;
870 /* FIXME: We are supposed to rearrange the option's 'source route' data */
871 memmove(ier
->Options
.OptionsData
,((char*)ip_header
)+ip_header_len
,ier
->Options
.OptionsSize
);
872 endbuf
=(char*)ier
->Options
.OptionsData
;
874 ier
->Options
.OptionsData
=NULL
;
878 /* Prepare for the next packet */
881 /* Check out whether there is more but don't wait this time */
891 FD_SET(icp
->sid
,&fdr
);
894 HeapFree(GetProcessHeap(), 0, ip_header
);
895 res
=ier
-(ICMP_ECHO_REPLY
*)ReplyBuffer
;
898 ier
->Status
= IP_REQ_TIMED_OUT
;
899 SetLastError(IP_REQ_TIMED_OUT
);
901 TRACE("received %d replies\n",res
);
905 /***********************************************************************
906 * IcmpSendEcho2 (IPHLPAPI.@)
908 DWORD WINAPI
IcmpSendEcho2(
911 PIO_APC_ROUTINE ApcRoutine
,
913 IPAddr DestinationAddress
,
916 PIP_OPTION_INFORMATION RequestOptions
,
922 TRACE("(%p, %p, %p, %p, %08x, %p, %d, %p, %p, %d, %d): stub\n", IcmpHandle
,
923 Event
, ApcRoutine
, ApcContext
, DestinationAddress
, RequestData
,
924 RequestSize
, RequestOptions
, ReplyBuffer
, ReplySize
, Timeout
);
928 FIXME("unsupported for events\n");
933 FIXME("unsupported for APCs\n");
936 return IcmpSendEcho(IcmpHandle
, DestinationAddress
, RequestData
,
937 RequestSize
, RequestOptions
, ReplyBuffer
, ReplySize
, Timeout
);
940 /***********************************************************************
941 * IcmpSendEcho2Ex (IPHLPAPI.@)
943 DWORD WINAPI
IcmpSendEcho2Ex(
946 PIO_APC_ROUTINE ApcRoutine
,
948 IPAddr SourceAddress
,
949 IPAddr DestinationAddress
,
952 PIP_OPTION_INFORMATION RequestOptions
,
958 TRACE("(%p, %p, %p, %p, %08x, %08x, %p, %d, %p, %p, %d, %d): stub\n", IcmpHandle
,
959 Event
, ApcRoutine
, ApcContext
, SourceAddress
, DestinationAddress
, RequestData
,
960 RequestSize
, RequestOptions
, ReplyBuffer
, ReplySize
, Timeout
);
964 FIXME("unsupported for events\n");
969 FIXME("unsupported for APCs\n");
974 FIXME("unsupported for source addresses\n");
978 return IcmpSendEcho(IcmpHandle
, DestinationAddress
, RequestData
,
979 RequestSize
, RequestOptions
, ReplyBuffer
, ReplySize
, Timeout
);
983 * Copyright (c) 1989 The Regents of the University of California.
984 * All rights reserved.
986 * This code is derived from software contributed to Berkeley by
989 * Redistribution and use in source and binary forms, with or without
990 * modification, are permitted provided that the following conditions
992 * 1. Redistributions of source code must retain the above copyright
993 * notice, this list of conditions and the following disclaimer.
994 * 2. Redistributions in binary form must reproduce the above copyright
995 * notice, this list of conditions and the following disclaimer in the
996 * documentation and/or other materials provided with the distribution.
997 * 3. Neither the name of the University nor the names of its contributors
998 * may be used to endorse or promote products derived from this software
999 * without specific prior written permission.
1001 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1002 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1003 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1004 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1005 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1006 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1007 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1008 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1009 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1010 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF