OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / slattach / pinger.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <sys/time.h>
6 #include <errno.h>
7
8 #include <linux/socket.h>
9 #include <linux/if.h>
10 #include <linux/if_eql.h>
11 #include <linux/in.h>
12 #include <linux/ip.h>
13 #include <linux/icmp.h>
14 #include <linux/route.h>
15
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18
19 /* The following portions are extracted from the netkit-base ping sources,
20    and come under this copyright: */
21
22 /* 
23  * Copyright (c) 1989 The Regents of the University of California.
24  * All rights reserved.
25  *
26  * This code is derived from software contributed to Berkeley by
27  * Mike Muuss.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions
31  * are met:
32  * 1. Redistributions of source code must retain the above copyright
33  *    notice, this list of conditions and the following disclaimer.
34  * 2. Redistributions in binary form must reproduce the above copyright
35  *    notice, this list of conditions and the following disclaimer in the
36  *    documentation and/or other materials provided with the distribution.
37  * 3. All advertising materials mentioning features or use of this software
38  *    must display the following acknowledgement:
39  *      This product includes software developed by the University of
40  *      California, Berkeley and its contributors.
41  * 4. Neither the name of the University nor the names of its contributors
42  *    may be used to endorse or promote products derived from this software
43  *    without specific prior written permission.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  */
57
58 /*
59  * in_cksum --
60  *      Checksum routine for Internet Protocol family headers (C Version)
61  */
62 int
63 in_cksum(u_short *addr, int len)
64 {
65         register int nleft = len;
66         register u_short *w = addr;
67         register int sum = 0;
68         u_short answer = 0;
69
70         /*
71          * Our algorithm is simple, using a 32 bit accumulator (sum), we add
72          * sequential 16 bit words to it, and at the end, fold back all the
73          * carry bits from the top 16 bits into the lower 16 bits.
74          */
75         while (nleft > 1)  {
76                 sum += *w++;
77                 nleft -= 2;
78         }
79
80         /* mop up an odd byte, if necessary */
81         if (nleft == 1) {
82                 *(unsigned char *)(&answer) = *(unsigned char *)w ;
83                 sum += answer;
84         }
85
86         /* add back carry outs from top 16 bits to low 16 bits */
87         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
88         sum += (sum >> 16);                     /* add carry */
89         answer = ~sum;                          /* truncate to 16 bits */
90         return(answer);
91 }
92
93 #if defined(__GLIBC__) && (__GLIBC__ >= 2)
94 #define icmphdr                 icmp
95 #define ICMP_DEST_UNREACH       ICMP_UNREACH
96 #define ICMP_NET_UNREACH        ICMP_UNREACH_NET
97 #define ICMP_HOST_UNREACH       ICMP_UNREACH_HOST
98 #define ICMP_PORT_UNREACH       ICMP_UNREACH_PORT
99 #define ICMP_PROT_UNREACH       ICMP_UNREACH_PROTOCOL
100 #define ICMP_FRAG_NEEDED        ICMP_UNREACH_NEEDFRAG
101 #define ICMP_SR_FAILED          ICMP_UNREACH_SRCFAIL
102 #define ICMP_NET_UNKNOWN        ICMP_UNREACH_NET_UNKNOWN
103 #define ICMP_HOST_UNKNOWN       ICMP_UNREACH_HOST_UNKNOWN
104 #define ICMP_HOST_ISOLATED      ICMP_UNREACH_ISOLATED
105 #define ICMP_NET_UNR_TOS        ICMP_UNREACH_TOSNET
106 #define ICMP_HOST_UNR_TOS       ICMP_UNREACH_TOSHOST
107 #define ICMP_SOURCE_QUENCH      ICMP_SOURCEQUENCH
108 #define ICMP_REDIR_NET          ICMP_REDIRECT_NET
109 #define ICMP_REDIR_HOST         ICMP_REDIRECT_HOST
110 #define ICMP_REDIR_NETTOS       ICMP_REDIRECT_TOSNET
111 #define ICMP_REDIR_HOSTTOS      ICMP_REDIRECT_TOSHOST
112 #define ICMP_TIME_EXCEEDED      ICMP_TIMXCEED
113 #define ICMP_EXC_TTL            ICMP_TIMXCEED_INTRANS
114 #define ICMP_EXC_FRAGTIME       ICMP_TIMXCEED_REASS
115 #define ICMP_PARAMETERPROB      ICMP_PARAMPROB
116 #define ICMP_TIMESTAMP          ICMP_TSTAMP
117 #define ICMP_TIMESTAMPREPLY     ICMP_TSTAMPREPLY
118 #define ICMP_INFO_REQUEST       ICMP_IREQ
119 #define ICMP_INFO_REPLY         ICMP_IREQREPLY
120 #else
121 #define ICMP_MINLEN     28
122 #define inet_ntoa(x) inet_ntoa(*((struct in_addr *)&(x)))
123 #endif
124
125
126 #define DEFDATALEN      (64 - 8)        /* default data length */
127 #define MAXIPLEN        60
128 #define MAXICMPLEN      76
129 #define MAXPACKET       (65536 - 60 - 8)/* max packet size */
130 #define MAXWAIT         10              /* max seconds to wait for response */
131 #define NROUTES         9               /* number of record route slots */
132
133 #define A(bit)          rcvd_tbl[(bit)>>3]      /* identify byte in array */
134 #define B(bit)          (1 << ((bit) & 0x07))   /* identify bit in byte */
135 #define SET(bit)        (A(bit) |= B(bit))
136 #define CLR(bit)        (A(bit) &= (~B(bit)))
137 #define TST(bit)        (A(bit) & B(bit))
138
139 /* various options */
140 int options;
141 #define F_FLOOD         0x001
142 #define F_INTERVAL      0x002
143 #define F_NUMERIC       0x004
144 #define F_PINGFILLED    0x008
145 #define F_QUIET         0x010
146 #define F_RROUTE        0x020
147 #define F_SO_DEBUG      0x040
148 #define F_SO_DONTROUTE  0x080
149 #define F_VERBOSE       0x100
150
151 /* multicast options */
152 int moptions;
153 #define MULTICAST_NOLOOP        0x001
154 #define MULTICAST_TTL           0x002
155 #define MULTICAST_IF            0x004
156
157 #if !defined(__GLIBC__) || (__GLIBC__ < 2)
158 #define icmp_type type
159 #define icmp_code code
160 #define icmp_cksum checksum
161 #define icmp_id un.echo.id
162 #define icmp_seq un.echo.sequence
163 #define icmp_gwaddr un.gateway
164 #endif /* __GLIBC__ */
165
166 #define ip_hl ihl
167 #define ip_v version
168 #define ip_tos tos
169 #define ip_len tot_len
170 #define ip_id id
171 #define ip_off frag_off
172 #define ip_ttl ttl
173 #define ip_p protocol
174 #define ip_sum check
175 #define ip_src saddr
176 #define ip_dst daddr
177
178 int transmit_ping(int socket, int ident, int sequence, int timing, unsigned char * outpack, int datalen, struct sockaddr * whereto, int wherelen)
179 {
180         register struct icmphdr *icp;
181         register int cc;
182         int i;
183
184         icp = (struct icmphdr *)outpack;
185         icp->icmp_type = ICMP_ECHO;
186         icp->icmp_code = 0;
187         icp->icmp_cksum = 0;
188         icp->icmp_seq = sequence;
189         icp->icmp_id = ident;                   /* ID */
190
191         if (timing)
192                 (void)gettimeofday((struct timeval *)&outpack[8],
193                     (struct timezone *)NULL);
194
195         cc = datalen + 8;                       /* skips ICMP portion */
196
197         /* compute ICMP checksum here */
198         icp->icmp_cksum = in_cksum((u_short *)icp, cc);
199
200         i = sendto(socket, (char *)outpack, cc, 0, whereto,
201             wherelen);
202            
203         /*printf("sendto=%d, errno=%d\n", i, errno);*/
204             
205         return i;
206 }
207
208 int receive_ping(int socket, int ident, int seq, unsigned char * packet, int datalen, struct sockaddr * from, int * fromlen)
209 {
210         register struct icmphdr *icp;
211         struct iphdr *ip;
212         int hlen;
213         int cc;
214         int orig_fromlen = fromlen ? *fromlen : 0;
215         int packlen = datalen+28;
216         
217         if (fromlen) 
218                 *fromlen = orig_fromlen;
219         
220         cc = recvfrom(socket, (char *)packet, packlen, 0,
221             from, fromlen);
222
223         /*printf("recvfrom=%d, errno=%d\n", cc, errno);*/
224             
225         if (cc < 0)
226                 return cc;
227         
228         /* Check the IP header */
229         ip = (struct iphdr *)packet;
230         hlen = ip->ip_hl << 2;
231         if (cc < datalen + ICMP_MINLEN) {
232                 /* weird */
233                 printf("too short (wanted at least %d bytes, got %d)\n",
234                         datalen+ ICMP_MINLEN, cc);
235                 return -1;
236         }
237
238         /* Now the ICMP part */
239         cc -= hlen;
240         icp = (struct icmphdr *)(packet + hlen);
241         if (icp->icmp_type == ICMP_ECHOREPLY) {
242                 /* not really needed: any response is good enough */
243                 /*if (icp->icmp_seq != seq)
244                         return -1;*/
245                 /* this happens if more then one ping is going */
246                 if (icp->icmp_id != ident) {
247                         printf("id was wrong (wanted %d, got %d)\n",
248                                 ident, icp->icmp_id);
249                         return -1;      /* 'Twas not our ECHO */
250                 }
251                 return 0;
252         } else {
253                 /* this happens easily if something is pinging us,
254                    for example */
255                 /*printf("Not an echoreply (wanted type %d, got %d)\n",
256                         ICMP_ECHOREPLY, icp->icmp_type);*/
257                 return -1; /* Not an ECHOREPLY */
258         }
259 }
260
261 extern int done;
262
263 /* loop until timeout seconds go by without a ping response */
264 void pinger(int fd, int timeout, struct sockaddr * whereto, int wherelen)
265 {
266         int ident = getpid() & 0xffff;
267         int seq = 0;
268         int missed = 0;
269         unsigned char packet[28];
270         
271         
272         fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
273         if (fd == -1) {
274                 /*printf("couldn't get raw socket\n");*/
275                 return;
276         }
277         
278         if (timeout < 1)
279                 timeout = 1;
280                 
281         while (missed < 2) {
282                 int s;
283                 fd_set rfds;
284                 struct timeval tv;
285                 
286                 FD_ZERO(&rfds);
287                 FD_SET(fd, &rfds);
288
289                 seq++;
290                 /*printf("Sending ping, seq=%d, id=%d\n", seq, ident);*/
291                 transmit_ping(fd, ident, seq, 0, packet, 0, whereto, wherelen);
292                 
293                 tv.tv_sec = timeout;
294                 tv.tv_usec = 0;
295
296                 /* sleep till we get a response, or timeout */
297                 for (;;) {
298                         if (done)
299                                 break;
300
301                         s = select(fd+1, &rfds, 0, 0, &tv);
302                         /*printf("Got something, with %d.%06.6d seconds remaining\n",
303                                 tv.tv_sec, tv.tv_usec);*/
304
305                         if (done)
306                                 break;
307                         if (s>0) {
308                                 /* was it a useful response? */
309                                 if (receive_ping(fd, ident, seq, packet, 0, 0, 0)<0)
310                                         /* no, so keep waiting. Maybe the
311                                            response is still in the queue. */
312                                         continue;
313                                 /*printf("Got a pong\n");*/
314                                 missed = 0;
315                                 break;
316                         } else if (s==0) {
317                                 missed++;
318                                 /*printf("No response, have missed %d\n", missed);*/
319                                 break;
320                         }
321                 }
322
323                 if (done)
324                         break;
325                 /* sleep off any remaining time */
326                 select(0, 0,0,0, &tv);
327                 if (done)
328                         break;
329
330         }
331 }