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 = inet_chksum(iecho, ping_info->size);
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
00093
00094 static u8_t ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p,
00095 struct ip_addr *addr)
00096 {
00097 struct icmp_echo_hdr *iecho;
00098 struct ip_hdr *ip = p->payload;
00099 struct ping_info_t* ping_info = (struct ping_info_t*) arg;
00100 uint32_t us;
00101
00102 if (pbuf_header( p, -PBUF_IP_HLEN)==0) {
00103 iecho = p->payload;
00104
00105 if ((iecho->id == PING_ID) &&
00106 (iecho->seqno == htons(ping_info->seq_num))) {
00107 ping_info->last_rx_tm = timer_get_ms();
00108 ping_info->num_rx++;
00109 us = 1000 *
00110 (ping_info->last_rx_tm - ping_info->last_tx_tm);
00111
00112 if (!ping_info->quiet)
00113 printk("%d bytes from %s: icmp_seq=%d ttl=%d " \
00114 "time=%d.%03d ms\n",
00115 p->tot_len, ip2str(ip->src),
00116 iecho->seqno,
00117 IPH_TTL(ip),
00118 us / 1000, us % 1000);
00119
00120
00121 ping_info->flags |= PING_REPLY;
00122 }
00123 }
00124
00125 pbuf_free(p);
00126 return 1;
00127 }
00128
00129 static void ping_send(struct raw_pcb *raw, struct ping_info_t* ping_info)
00130 {
00131 struct pbuf *p;
00132 struct icmp_echo_hdr *iecho;
00133
00134 if (!(p = pbuf_alloc(PBUF_IP, ping_info->size, PBUF_RAM))) {
00135 return;
00136 }
00137 if ((p->len == p->tot_len) && (p->next == NULL)) {
00138 iecho = p->payload;
00139
00140 ping_prepare_echo(iecho, ping_info);
00141 raw_sendto(raw, p, &ping_info->destination);
00142
00143 if (!ping_info->first_tx_tm)
00144 ping_info->first_tx_tm = timer_get_ms();
00145 ping_info->last_tx_tm = timer_get_ms();
00146 ping_info->num_tx++;
00147 }
00148 pbuf_free(p);
00149 }
00150
00151 void ping_set_callback(ping_complete_cb_t cb, void *ctx) {
00152 INFO.complete_cb = cb;
00153 INFO.ctx = ctx;
00154 }
00155
00156 void ping_stop(uint32_t *tx_cnt, uint32_t *rx_cnt) {
00157 struct ping_info_t *ping_info = &INFO;
00158
00159 *tx_cnt = ping_info->num_tx;
00160 *rx_cnt = ping_info->num_rx;
00161 ping_info->count = ping_info->num_tx;
00162 if ( 0 == ping_info->count ) {
00163 ping_info->count = 1;
00164 }
00165 }
00166
00167 static int init_ping_info(int argc, char* argv[], struct ping_info_t* ping_info)
00168 {
00169 int c;
00170 ping_complete_cb_t cb;
00171 void *ctx;
00172
00173 cb = ping_info->complete_cb;
00174 ctx = ping_info->ctx;
00175 memset(ping_info, 0, sizeof(struct ping_info_t));
00176 ping_info->complete_cb = cb;
00177 ping_info->ctx = ctx;
00178
00179 ping_info->deadline = 0;
00180 ping_info->interval = 1000;
00181 ping_info->timeout = 3000;
00182 ping_info->data_size = 32;
00183 ping_info->count = 3;
00184 ping_info->destination =
00185 netif_default ? netif_default->gw : ip_addr_any;
00186
00187 optind = 1;
00188 while ((c = getopt(argc, argv, "c:i:s:w:q")) != -1) {
00189 switch (c) {
00190 case 'c':
00191 ping_info->count = atoi(optarg);
00192 break;
00193
00194 case 'i':
00195 ping_info->interval = atoi(optarg);
00196 break;
00197
00198 case 's':
00199 ping_info->data_size = atoi(optarg);
00200 break;
00201
00202 case 'q':
00203 ping_info->quiet = TRUE;
00204 break;
00205
00206 case 'w':
00207 ping_info->deadline = atoi(optarg);
00208 break;
00209 }
00210 }
00211
00212 ping_info->size = sizeof(struct icmp_echo_hdr) + ping_info->data_size;
00213
00214 if (optind >= argc)
00215 return -1;
00216
00217 ping_info->destination = str2ip(argv[optind]);
00218 if (!ping_info->destination.addr)
00219 return -1;
00220
00221
00222 ping_info->last_rx_tm = timer_get_ms();
00223
00224 return 0;
00225 }
00226
00227 static void print_stats(struct ping_info_t* ping_info)
00228 {
00229 printk("\n--- %s ping statistics ---\n",
00230 ip2str(ping_info->destination));
00231 printk("%d packets transmitted, %d received, %d%% packet loss, "\
00232 "time %dms\n\n",
00233 ping_info->num_tx, ping_info->num_rx,
00234 100 * (ping_info->num_tx - ping_info->num_rx) /
00235 ping_info->num_tx,
00236 timer_get_ms() - ping_info->first_tx_tm);
00237 }
00238
00239 static void ping_finalize(struct ping_info_t* ping_info) {
00240 print_stats(ping_info);
00241 if (ping_info->complete_cb) {
00242 ping_info->complete_cb(ping_info->num_tx, ping_info->num_rx, ping_info->ctx);
00243 }
00244 }
00245
00246 cmd_state_t cmd_ping(int argc, char* argv[], void* ctx)
00247 {
00248 static enum {
00249 INIT,
00250 PING,
00251 WAIT_REPLY
00252 } state = INIT;
00253
00254 struct ping_info_t *ping_info = &INFO;
00255 static struct raw_pcb *pcb;
00256
00257 switch (state) {
00258 case INIT:
00259 if (init_ping_info(argc, argv, ping_info) != 0) {
00260 printk("Usage: ping [-c count] [-i interval] " \
00261 "[-s packetsize]\n " \
00262 "[-w deadline] [-q] destination\n");
00263 return CMD_DONE;
00264 }
00265
00266 if (!(pcb = raw_new(IP_PROTO_ICMP))) {
00267 printk("could not allocate pcb\n");
00268 state = INIT;
00269 return CMD_DONE;
00270 }
00271 raw_recv(pcb, ping_recv, ping_info);
00272 raw_bind(pcb, IP_ADDR_ANY);
00273
00274 printk("PING %s %d(%d) bytes of data\n",
00275 ip2str(ping_info->destination),
00276 ping_info->data_size,
00277 ping_info->size);
00278 state = PING;
00279
00280
00281 case PING:
00282 if (!netif_is_up(netif_default)) {
00283 printk("netif is down\n");
00284 raw_remove(pcb);
00285 state = INIT;
00286 return CMD_DONE;
00287 }
00288
00289 if (ping_info->count && ping_info->num_tx == ping_info->count) {
00290 ping_finalize(ping_info);
00291 raw_remove(pcb);
00292 state = INIT;
00293 return CMD_DONE;
00294 }
00295
00296 if (timer_get_ms() < ping_info->last_rx_tm + ping_info->interval) {
00297 return CMD_INPROGRESS;
00298 }
00299 ping_send(pcb, ping_info);
00300
00301 state = WAIT_REPLY;
00302 return CMD_INPROGRESS;
00303
00304 case WAIT_REPLY:
00305 if (ping_info->flags & PING_REPLY) {
00306 ping_info->flags &= (~PING_REPLY);
00307 state = PING;
00308 return CMD_INPROGRESS;
00309 }
00310
00311 if (timer_get_ms() >
00312 ping_info->last_tx_tm + ping_info->timeout) {
00313 if (!ping_info->quiet)
00314 printk("timeout from %s\n",
00315 ip2str(ping_info->destination));
00316 state = PING;
00317 return CMD_INPROGRESS;
00318 }
00319
00320 if (ping_info->deadline &&
00321 timer_get_ms() >
00322 ping_info->first_tx_tm + ping_info->deadline * 1000) {
00323 ping_finalize(ping_info);
00324 raw_remove(pcb);
00325 state = INIT;
00326 return CMD_DONE;
00327 }
00328
00329 return CMD_INPROGRESS;
00330 }
00331
00332
00333 Assert(0);
00334 return CMD_DONE;
00335 }