00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "lwip/opt.h"
00032
00033 #include "lwip/mem.h"
00034 #include "lwip/raw.h"
00035 #include "lwip/icmp.h"
00036 #include "lwip/netif.h"
00037 #include "lwip/sys.h"
00038 #include "lwip/sockets.h"
00039 #include "lwip/inet.h"
00040 #include "lwip/inet_chksum.h"
00041
00042 #include "ping.h"
00043 #include "timer.h"
00044 #include "wl_util.h"
00045 #include "util.h"
00046
00047 #include "getopt.h"
00048
00049 #define PING_ID 0xAFAF
00050
00051 struct ping_info_t {
00052 struct ip_addr destination;
00053 uint32_t deadline;
00054 uint32_t interval;
00055 uint32_t timeout;
00056 uint32_t data_size;
00057 uint32_t count;
00058 uint32_t size;
00059 uint32_t first_tx_tm;
00060 uint32_t last_tx_tm;
00061 uint32_t last_rx_tm;
00062 uint32_t num_tx;
00063 uint32_t num_rx;
00064 uint32_t flags;
00065 uint16_t seq_num;
00066 Bool quiet;
00067 ping_complete_cb_t complete_cb;
00068 void *ctx;
00069 #define PING_REPLY (1 << 0)
00070 };
00071
00072 static struct ping_info_t INFO;
00073
00075 static void ping_prepare_echo(struct icmp_echo_hdr *iecho,
00076 struct ping_info_t* ping_info)
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
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 }
00094
00095
00096 static u8_t ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p,
00097 struct ip_addr *addr)
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
00123 ping_info->flags |= PING_REPLY;
00124 }
00125 }
00126
00127 pbuf_free(p);
00128 return 1;
00129 }
00130
00131 static void ping_send(struct raw_pcb *raw, struct ping_info_t* ping_info)
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 }
00152
00153 void ping_set_callback(ping_complete_cb_t cb, void *ctx) {
00154 INFO.complete_cb = cb;
00155 INFO.ctx = ctx;
00156 }
00157
00158 void ping_stop(uint32_t *tx_cnt, uint32_t *rx_cnt) {
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 }
00168
00169 static int init_ping_info(int argc, char* argv[], struct ping_info_t* ping_info)
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 }
00228
00229 static void print_stats(struct ping_info_t* ping_info)
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 }
00240
00241 static void ping_finalize(struct ping_info_t* ping_info) {
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 }
00247
00248 cmd_state_t cmd_ping(int argc, char* argv[], void* ctx)
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
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
00336 Assert(0);
00337 return CMD_DONE;
00338 }