ping.c File Reference

#include "lwip/opt.h"
#include "lwip/mem.h"
#include "lwip/raw.h"
#include "lwip/icmp.h"
#include "lwip/netif.h"
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include "lwip/inet.h"
#include "lwip/inet_chksum.h"
#include "ping.h"
#include "timer.h"
#include "wl_util.h"
#include "util.h"
#include "getopt.h"

Go to the source code of this file.

Data Structures

struct  ping_info_t

Defines

#define PING_ID   0xAFAF
#define PING_REPLY   (1 << 0)

Functions

cmd_state_t cmd_ping (int argc, char *argv[], void *ctx)
static int init_ping_info (int argc, char *argv[], struct ping_info_t *ping_info)
static void ping_finalize (struct ping_info_t *ping_info)
static void ping_prepare_echo (struct icmp_echo_hdr *iecho, struct ping_info_t *ping_info)
 Prepare a echo ICMP request.
static u8_t ping_recv (void *arg, struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *addr)
static void ping_send (struct raw_pcb *raw, struct ping_info_t *ping_info)
void ping_set_callback (ping_complete_cb_t cb, void *ctx)
void ping_stop (uint32_t *tx_cnt, uint32_t *rx_cnt)
static void print_stats (struct ping_info_t *ping_info)

Variables

static struct ping_info_t INFO


Define Documentation

#define PING_ID   0xAFAF

Definition at line 49 of file ping.c.

Referenced by ping_prepare_echo(), and ping_recv().

#define PING_REPLY   (1 << 0)

Definition at line 69 of file ping.c.

Referenced by cmd_ping(), and ping_recv().


Function Documentation

cmd_state_t cmd_ping ( int  argc,
char *  argv[],
void *  ctx 
)

Definition at line 248 of file ping.c.

References CMD_DONE, CMD_INPROGRESS, ping_info_t::count, ping_info_t::data_size, ping_info_t::deadline, ping_info_t::destination, ping_info_t::first_tx_tm, ping_info_t::flags, INFO, init_ping_info(), ping_info_t::interval, ip2str(), ping_info_t::last_rx_tm, ping_info_t::last_tx_tm, ping_info_t::num_tx, pcb, ping_finalize(), ping_recv(), PING_REPLY, ping_send(), printk(), ping_info_t::quiet, ping_info_t::size, ping_info_t::timeout, and timer_get_ms().

Referenced by wl_init_complete_cb().

00249 {
00250         static enum {
00251                 INIT,
00252                 PING,
00253                 WAIT_REPLY
00254         } state = INIT;
00255 
00256         struct ping_info_t *ping_info = &INFO;
00257         static struct raw_pcb *pcb;
00258         
00259         switch (state) {
00260         case INIT:
00261                 if (init_ping_info(argc, argv, ping_info) != 0) {
00262                         printk("Usage: ping [-c count] [-i interval] "  \
00263                                "[-s packetsize]\n            " \
00264                                "[-w deadline] [-q] destination\n");
00265                         return CMD_DONE;
00266                 }
00267 
00268                 if (!(pcb = raw_new(IP_PROTO_ICMP))) {
00269                         printk("could not allocate pcb\n");
00270                         state = INIT;
00271                         return CMD_DONE;
00272                 }
00273                 raw_recv(pcb, ping_recv, ping_info);
00274                 raw_bind(pcb, IP_ADDR_ANY);
00275 
00276                 printk("PING %s %d(%d) bytes of data\n",
00277                        ip2str(ping_info->destination),
00278                        ping_info->data_size,
00279                        ping_info->size);
00280                 state = PING;
00281                 /* fall through */
00282                 
00283         case PING:
00284                 if (!netif_is_up(netif_default)) {
00285                         printk("netif is down\n");
00286                         raw_remove(pcb);
00287                         state = INIT;
00288                         return CMD_DONE;
00289                 }
00290                 
00291                 if (ping_info->count && ping_info->num_tx == ping_info->count) {
00292                         ping_finalize(ping_info);
00293                         raw_remove(pcb);
00294                         state = INIT;
00295                         return CMD_DONE;
00296                 }
00297 
00298                 
00299                 if (timer_get_ms() < ping_info->last_rx_tm + ping_info->interval) {
00300                         return CMD_INPROGRESS;
00301                 }
00302                 ping_send(pcb, ping_info);
00303                         
00304                 state = WAIT_REPLY;
00305                 return CMD_INPROGRESS;
00306                 
00307         case WAIT_REPLY:
00308                 if (ping_info->flags & PING_REPLY) {
00309                         ping_info->flags &= (~PING_REPLY);
00310                         state = PING;
00311                         return CMD_INPROGRESS;
00312                 }
00313 
00314                 if (timer_get_ms() >
00315                     ping_info->last_tx_tm + ping_info->timeout) {
00316                         if (!ping_info->quiet)
00317                                 printk("timeout from %s\n",
00318                                        ip2str(ping_info->destination));
00319                         state = PING;
00320                         return CMD_INPROGRESS;
00321                 }
00322 
00323                 if (ping_info->deadline &&
00324                     timer_get_ms() >
00325                     ping_info->first_tx_tm + ping_info->deadline * 1000) {
00326                         ping_finalize(ping_info);
00327                         raw_remove(pcb);
00328                         state = INIT;
00329                         return CMD_DONE;
00330                 }
00331 
00332                 return CMD_INPROGRESS;
00333         }
00334 
00335         /* unreachable */
00336         Assert(0);
00337     return CMD_DONE;
00338 }

static int init_ping_info ( int  argc,
char *  argv[],
struct ping_info_t ping_info 
) [static]

Definition at line 169 of file ping.c.

References cb, ping_info_t::complete_cb, ping_info_t::count, ping_info_t::ctx, ctx, ping_info_t::data_size, ping_info_t::deadline, ping_info_t::destination, ping_info_t::interval, ping_info_t::quiet, ping_info_t::size, str2ip(), ping_info_t::timeout, timer_get_ms(), and TRUE.

Referenced by cmd_ping().

00170 {
00171         int c;
00172         ping_complete_cb_t cb;
00173         void *ctx;
00174 
00175         cb = ping_info->complete_cb;
00176         ctx = ping_info->ctx;
00177         memset(ping_info, 0, sizeof(struct ping_info_t));
00178         ping_info->complete_cb = cb;
00179         ping_info->ctx = ctx;
00180 
00181         ping_info->deadline = 0;
00182         ping_info->interval = 1000;
00183         ping_info->timeout = 3000;
00184         ping_info->data_size = 32;
00185         ping_info->count = 3;
00186         ping_info->destination =
00187                 netif_default ? netif_default->gw : ip_addr_any;
00188 
00189         optind = 1;
00190         while ((c = getopt(argc, argv, "c:i:s:w:q")) != -1) {
00191                 switch (c) {
00192                 case 'c':
00193                         ping_info->count = atoi(optarg);
00194                         break;
00195                         
00196                 case 'i':
00197                         ping_info->interval = atoi(optarg);
00198                         break;
00199                         
00200                 case 's':
00201                         ping_info->data_size = atoi(optarg);
00202                         break;
00203 
00204                 case 'q':
00205                         ping_info->quiet = TRUE;
00206                         break;
00207 
00208                 case 'w':
00209                         ping_info->deadline = atoi(optarg);
00210                         break;
00211                 }
00212         }
00213 
00214         ping_info->size = sizeof(struct icmp_echo_hdr) + ping_info->data_size;
00215 
00216         if (optind >= argc)
00217                 return -1;
00218 
00219         ping_info->destination = str2ip(argv[optind]);
00220         if (!ping_info->destination.addr)
00221                 return -1;
00222                 
00223 
00224         ping_info->last_rx_tm = timer_get_ms();
00225 
00226         return 0;
00227 }

static void ping_finalize ( struct ping_info_t ping_info  )  [static]

Definition at line 241 of file ping.c.

References ping_info_t::complete_cb, ping_info_t::ctx, ping_info_t::num_rx, ping_info_t::num_tx, and print_stats().

Referenced by cmd_ping().

00241                                                          {
00242         print_stats(ping_info);
00243         if (ping_info->complete_cb) {
00244                 ping_info->complete_cb(ping_info->num_tx, ping_info->num_rx, ping_info->ctx);
00245         }
00246 }

static void ping_prepare_echo ( struct icmp_echo_hdr *  iecho,
struct ping_info_t ping_info 
) [static]

Prepare a echo ICMP request.

Definition at line 75 of file ping.c.

References ping_info_t::data_size, PING_ID, ping_info_t::seq_num, and ping_info_t::size.

Referenced by ping_send().

00077 {
00078         int i;
00079 
00080         ICMPH_TYPE_SET(iecho,ICMP_ECHO);
00081         ICMPH_CODE_SET(iecho, 0);
00082         iecho->chksum = 0;
00083         iecho->id     = PING_ID;
00084         iecho->seqno  = htons(++ping_info->seq_num);
00085         iecho->chksum = 0;
00086 
00087         /* fill the additional data buffer with some data */
00088         for(i = 0; i < ping_info->data_size; i++) {
00089                 ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = i;
00090         }
00091 
00092         iecho->chksum = inet_chksum(iecho, ping_info->size);
00093 }

static u8_t ping_recv ( void *  arg,
struct raw_pcb *  pcb,
struct pbuf *  p,
struct ip_addr *  addr 
) [static]

Definition at line 96 of file ping.c.

References ping_info_t::flags, ip2str(), ping_info_t::last_rx_tm, ping_info_t::last_tx_tm, ping_info_t::num_rx, PING_ID, PING_REPLY, printk(), ping_info_t::quiet, ping_info_t::seq_num, and timer_get_ms().

Referenced by cmd_ping().

00098 {
00099         struct icmp_echo_hdr *iecho;
00100         struct ip_hdr *ip = p->payload;
00101         struct ping_info_t* ping_info = (struct ping_info_t*) arg;
00102         uint32_t us;
00103 
00104         if (pbuf_header( p, -PBUF_IP_HLEN)==0) {
00105                 iecho = p->payload;
00106 
00107                 if ((iecho->id == PING_ID) &&
00108                     (iecho->seqno == htons(ping_info->seq_num))) {
00109                         ping_info->last_rx_tm = timer_get_ms();
00110                         ping_info->num_rx++;
00111                         us = 1000 *
00112                                 (ping_info->last_rx_tm - ping_info->last_tx_tm);
00113 
00114                         if (!ping_info->quiet)
00115                                 printk("%d bytes from %s: icmp_seq=%d ttl=%d " \
00116                                        "time=%d.%03d ms\n",
00117                                        p->tot_len, ip2str(ip->src),
00118                                        iecho->seqno,
00119                                        IPH_TTL(ip),
00120                                        us / 1000, us % 1000);
00121                         
00122                         /* do some ping result processing */
00123                         ping_info->flags |= PING_REPLY;
00124                 }
00125         }
00126 
00127         pbuf_free(p);
00128         return 1; /* eat the event */
00129 }

static void ping_send ( struct raw_pcb *  raw,
struct ping_info_t ping_info 
) [static]

Definition at line 131 of file ping.c.

References ping_info_t::destination, ping_info_t::first_tx_tm, ping_info_t::last_tx_tm, ping_info_t::num_tx, ping_prepare_echo(), ping_info_t::size, and timer_get_ms().

Referenced by cmd_ping().

00132 {
00133         struct pbuf *p;
00134         struct icmp_echo_hdr *iecho;
00135 
00136         if (!(p = pbuf_alloc(PBUF_IP, ping_info->size, PBUF_RAM))) {
00137                 return;
00138         }
00139         if ((p->len == p->tot_len) && (p->next == NULL)) {
00140                 iecho = p->payload;
00141 
00142                 ping_prepare_echo(iecho, ping_info);
00143                 raw_sendto(raw, p, &ping_info->destination);
00144 
00145                 if (!ping_info->first_tx_tm)
00146                         ping_info->first_tx_tm = timer_get_ms();
00147                 ping_info->last_tx_tm = timer_get_ms();
00148                 ping_info->num_tx++;
00149         }
00150         pbuf_free(p);
00151 }

void ping_set_callback ( ping_complete_cb_t  cb,
void *  ctx 
)

Definition at line 153 of file ping.c.

References ping_info_t::complete_cb, ping_info_t::ctx, and INFO.

00153                                                          {
00154         INFO.complete_cb = cb;
00155         INFO.ctx = ctx;
00156 }

void ping_stop ( uint32_t *  tx_cnt,
uint32_t *  rx_cnt 
)

Definition at line 158 of file ping.c.

References ping_info_t::count, INFO, ping_info_t::num_rx, and ping_info_t::num_tx.

00158                                                    {
00159         struct ping_info_t *ping_info = &INFO;
00160 
00161         *tx_cnt = ping_info->num_tx;
00162         *rx_cnt = ping_info->num_rx;
00163         ping_info->count = ping_info->num_tx;
00164         if ( 0 == ping_info->count ) {
00165                 ping_info->count = 1;
00166         }
00167 }

static void print_stats ( struct ping_info_t ping_info  )  [static]

Definition at line 229 of file ping.c.

References ping_info_t::destination, ping_info_t::first_tx_tm, ip2str(), ping_info_t::num_rx, ping_info_t::num_tx, printk(), and timer_get_ms().

Referenced by ping_finalize().

00230 {
00231         printk("\n--- %s ping statistics ---\n",
00232                ip2str(ping_info->destination));
00233         printk("%d packets transmitted, %d received, %d%% packet loss, "\
00234                "time %dms\n\n",
00235                ping_info->num_tx, ping_info->num_rx,
00236                100 * (ping_info->num_tx - ping_info->num_rx) /
00237                ping_info->num_tx,
00238                timer_get_ms() - ping_info->first_tx_tm);
00239 }


Variable Documentation

struct ping_info_t INFO [static]

Definition at line 72 of file ping.c.

Referenced by cmd_ping(), ping_set_callback(), and ping_stop().


Generated on Fri Feb 19 02:24:08 2010 for AVR32 - H&D by  doxygen 1.5.5