source: SVN/cambria/redboot/packages/redboot/current/src/net/ping.c @ 1

Last change on this file since 1 was 1, checked in by Tim Harvey, 2 years ago

restored latest version of files from server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 8.8 KB
Line 
1//==========================================================================
2//
3//      ping.c
4//
5//      Network utility - ping
6//
7//==========================================================================
8//####ECOSGPLCOPYRIGHTBEGIN####
9// -------------------------------------------
10// This file is part of eCos, the Embedded Configurable Operating System.
11// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12// Copyright (C) 2003 Gary Thomas
13//
14// eCos is free software; you can redistribute it and/or modify it under
15// the terms of the GNU General Public License as published by the Free
16// Software Foundation; either version 2 or (at your option) any later version.
17//
18// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19// WARRANTY; without even the implied warranty of MERCHANTABILITY or
20// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21// for more details.
22//
23// You should have received a copy of the GNU General Public License along
24// with eCos; if not, write to the Free Software Foundation, Inc.,
25// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26//
27// As a special exception, if other files instantiate templates or use macros
28// or inline functions from this file, or you compile this file and link it
29// with other works to produce a work based on this file, this file does not
30// by itself cause the resulting work to be covered by the GNU General Public
31// License. However the source code for this file must still be made available
32// in accordance with section (3) of the GNU General Public License.
33//
34// This exception does not invalidate any other reasons why a work based on
35// this file might be covered by the GNU General Public License.
36//
37// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38// at http://sources.redhat.com/ecos/ecos-license/
39// -------------------------------------------
40//####ECOSGPLCOPYRIGHTEND####
41//==========================================================================
42//#####DESCRIPTIONBEGIN####
43//
44// Author(s):    gthomas
45// Contributors: gthomas
46// Date:         2001-01-22
47// Purpose:     
48// Description: 
49//             
50// This code is part of RedBoot (tm).
51//
52//####DESCRIPTIONEND####
53//
54//==========================================================================
55
56#include <redboot.h>
57#include <net/net.h>
58
59#ifndef CYGPKG_REDBOOT_NETWORKING
60#error CYGPKG_REDBOOT_NETWORKING required!
61#else
62
63static void do_ping(int argc, char *argv[]);
64RedBoot_cmd("ping", 
65            "Network connectivity test",
66            "[-v] [-n <count>] [-l <length>] [-t <timeout>] [-r <rate>]\n"
67            "        [-i <IP_addr>] -h <IP_addr>",
68            do_ping
69    );
70
71static bool icmp_received;
72static icmp_header_t hold_hdr;
73
74static void
75handle_icmp(pktbuf_t *pkt, ip_route_t *src_route)
76{
77    icmp_header_t *icmp;
78    unsigned short cksum;
79
80    icmp = pkt->icmp_hdr;
81    if (icmp->type == ICMP_TYPE_ECHOREQUEST
82        && icmp->code == 0
83        && __sum((word *)icmp, pkt->pkt_bytes, 0) == 0) {
84
85        icmp->type = ICMP_TYPE_ECHOREPLY;
86        icmp->checksum = 0;
87        cksum = __sum((word *)icmp, pkt->pkt_bytes, 0);
88        icmp->checksum = htons(cksum);
89        __ip_send(pkt, IP_PROTO_ICMP, src_route);
90    } else if (icmp->type == ICMP_TYPE_ECHOREPLY) {
91        memcpy(&hold_hdr, icmp, sizeof(*icmp));
92        icmp_received = true;
93    }
94}
95
96static void
97do_ping(int argc, char *argv[])
98{
99    struct option_info opts[7];
100    long count, timeout, length, rate, start_time, end_time, timer, received, tries;
101    char *local_ip_addr, *host_ip_addr;
102    bool local_ip_addr_set, host_ip_addr_set, count_set, 
103        timeout_set, length_set, rate_set, verbose;
104    struct sockaddr_in local_addr, host_addr;
105    ip_addr_t hold_addr;
106    icmp_header_t *icmp;
107    pktbuf_t *pkt;
108    ip_header_t *ip;
109    unsigned short cksum;
110    ip_route_t dest_ip;
111
112    init_opts(&opts[0], 'n', true, OPTION_ARG_TYPE_NUM, 
113              (void *)&count, (bool *)&count_set, "<count> - number of packets to test");
114    init_opts(&opts[1], 't', true, OPTION_ARG_TYPE_NUM, 
115              (void *)&timeout, (bool *)&timeout_set, "<timeout> - max #ms per packet [rount trip]");
116    init_opts(&opts[2], 'i', true, OPTION_ARG_TYPE_STR, 
117              (void *)&local_ip_addr, (bool *)&local_ip_addr_set, "local IP address");
118    init_opts(&opts[3], 'h', true, OPTION_ARG_TYPE_STR, 
119              (void *)&host_ip_addr, (bool *)&host_ip_addr_set, "host name or IP address");
120    init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM, 
121              (void *)&length, (bool *)&length_set, "<length> - size of payload");
122    init_opts(&opts[5], 'v', false, OPTION_ARG_TYPE_FLG, 
123              (void *)&verbose, (bool *)0, "verbose operation");
124    init_opts(&opts[6], 'r', true, OPTION_ARG_TYPE_NUM, 
125              (void *)&rate, (bool *)&rate_set, "<rate> - time between packets");
126    if (!scan_opts(argc, argv, 1, opts, 7, (void **)0, 0, "")) {
127        diag_printf("PING - Invalid option specified\n");
128        return;
129    }   
130    // Set defaults; this has to be done _after_ the scan, since it will
131    // have destroyed all values not explicitly set.
132    if (local_ip_addr_set) {
133        if (!_gethostbyname(local_ip_addr, (in_addr_t *)&local_addr)) {
134            diag_printf("PING - Invalid local name: %s\n", local_ip_addr);
135            return;
136        }
137    } else {
138        memcpy((in_addr_t *)&local_addr, __local_ip_addr, sizeof(__local_ip_addr));
139    }
140    if (host_ip_addr_set) {
141        if (!_gethostbyname(host_ip_addr, (in_addr_t *)&host_addr)) {
142            diag_printf("PING - Invalid host name: %s\n", host_ip_addr);
143            return;
144        }
145        if (__arp_lookup((ip_addr_t *)&host_addr.sin_addr, &dest_ip) < 0) {
146            diag_printf("PING: Cannot reach server '%s' (%s)\n", 
147                        host_ip_addr, inet_ntoa((in_addr_t *)&host_addr));
148            return;
149        }
150    } else {
151        diag_printf("PING - host name or IP address required\n");
152        return;
153    }
154#define DEFAULT_LENGTH   64
155#define DEFAULT_COUNT    10
156#define DEFAULT_TIMEOUT  1000
157#define DEFAULT_RATE     1000
158    if (!rate_set) {
159        rate = DEFAULT_RATE;
160    }
161    if (!length_set) {
162        length = DEFAULT_LENGTH;
163    }
164    if ((length < 64) || (length > 1400)) {
165        diag_printf("Invalid length specified: %ld\n", length);
166        return;
167    }
168    if (!count_set) {
169        count = DEFAULT_COUNT;
170    }
171    if (!timeout_set) {
172        timeout = DEFAULT_TIMEOUT;
173    }
174    // Note: two prints here because 'inet_ntoa' returns a static pointer
175    diag_printf("Network PING - from %s",
176                inet_ntoa((in_addr_t *)&local_addr));
177    diag_printf(" to %s\n",
178                inet_ntoa((in_addr_t *)&host_addr));
179    received = 0;   
180    __icmp_install_listener(handle_icmp);
181    // Save default "local" address
182    memcpy(hold_addr, __local_ip_addr, sizeof(hold_addr));
183    for (tries = 0;  tries < count;  tries++) {
184        // The network stack uses the global variable '__local_ip_addr'
185        memcpy(__local_ip_addr, &local_addr, sizeof(__local_ip_addr));
186        // Build 'ping' request
187        if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL) {
188            // Give up if no packets - something is wrong
189            break;
190        }
191
192        icmp = pkt->icmp_hdr;
193        ip = pkt->ip_hdr;
194        pkt->pkt_bytes = length + sizeof(icmp_header_t);
195
196        icmp->type = ICMP_TYPE_ECHOREQUEST;
197        icmp->code = 0;
198        icmp->checksum = 0;
199        icmp->seqnum = htons(tries+1);
200        cksum = __sum((word *)icmp, pkt->pkt_bytes, 0);
201        icmp->checksum = htons(cksum);
202       
203        memcpy(ip->source, (in_addr_t *)&local_addr, sizeof(ip_addr_t));
204        memcpy(ip->destination, (in_addr_t *)&host_addr, sizeof(ip_addr_t));
205        ip->protocol = IP_PROTO_ICMP;
206        ip->length = htons(pkt->pkt_bytes);
207
208        __ip_send(pkt, IP_PROTO_ICMP, &dest_ip);
209        __pktbuf_free(pkt);
210
211        start_time = MS_TICKS();
212        timer = start_time + timeout;
213        icmp_received = false;
214        while (!icmp_received && (MS_TICKS_DELAY() < timer)) {           
215            if (_rb_break(1)) {
216                goto abort;
217            }
218            MS_TICKS_DELAY();
219            __enet_poll();
220        } 
221        end_time = MS_TICKS();
222
223        timer = MS_TICKS() + rate;
224        while (MS_TICKS_DELAY() < timer) {
225            if (_rb_break(1)) {
226                goto abort;
227            }
228            MS_TICKS_DELAY();
229            __enet_poll();
230        } 
231
232        if (icmp_received) {
233            received++;
234            if (verbose) {
235                diag_printf(" seq: %ld, time: %ld (ticks)\n",
236                            ntohs(hold_hdr.seqnum), end_time-start_time);
237            }
238        }
239    }
240 abort:
241    __icmp_remove_listener();
242    // Clean up
243    memcpy(__local_ip_addr, &hold_addr, sizeof(__local_ip_addr));
244    // Report
245    diag_printf("PING - received %ld of %ld expected\n", received, count);
246}
247
248#endif //CYGPKG_REDBOOT_NETWORKING
Note: See TracBrowser for help on using the repository browser.