> +#include <net-lwip.h>
> +#include <time.h>
> +
> +#define PING_DELAY_MS 1000
> +#define PING_TIMEOUT_MS 10000
> +/* Additional data size to include in the packet */
> +#define PING_DATA_SIZE 32
> +/* Ping identifier - must fit on a u16_t */
> +#define PING_ID 0xAFAF
> +
> +static const ip_addr_t *ping_target;
> +static struct raw_pcb *ping_pcb;
> +static u16_t ping_seq_num;

As a general note, u8_t u16_t etc are lwip constructs.
Can we not use them and instead use the original definition?
uint8_t etc. I am not sure introducing another define is what we want. Tom?

> +static bool ping_target_alive;
> +
> +static u8_t ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p,
> +                   const ip_addr_t *addr)
> +{
> +     struct icmp_echo_hdr *iecho;
> +
> +     if (addr->addr != ping_target->addr)
> +             return 0;
> +
> +     if ((p->tot_len >= (IP_HLEN + sizeof(struct icmp_echo_hdr))) &&
> +         pbuf_remove_header(p, IP_HLEN) == 0) {
> +             iecho = (struct icmp_echo_hdr *)p->payload;
> +
> +             if ((iecho->id == PING_ID) &&
> +                 (iecho->seqno == lwip_htons(ping_seq_num))) {
> +                     ping_target_alive = true;
> +                     printf("host %s is alive\n", ipaddr_ntoa(addr));
> +                     pbuf_free(p);
> +                     return 1; /* eat the packet */
> +             }
> +             /* not eaten, restore original packet */
> +             pbuf_add_header(p, IP_HLEN);
> +     }
> +
> +     return 0; /* don't eat the packet */
> +}
> +
> +static int ping_raw_init(void)
> +{
> +     ping_pcb = raw_new(IP_PROTO_ICMP);
> +     if (!ping_pcb)
> +             return -ENOMEM;
> +
> +     raw_recv(ping_pcb, ping_recv, NULL);

Instead of defining a global variable ping_target_alive can we instead pass
the ptr of void *recv_arg? We can then fill in that private ptr with the
status

> +     raw_bind(ping_pcb, IP_ADDR_ANY);
> +
> +     return 0;
> +}
> +
> +static void ping_raw_stop(void)
> +{
> +     if (ping_pcb != NULL) {
> +             raw_remove(ping_pcb);
> +             ping_pcb = NULL;
> +     }
> +}
> +
> +static void ping_prepare_echo(struct icmp_echo_hdr *iecho, u16_t len)
> +{
> +     size_t i;
> +     size_t data_len = len - sizeof(struct icmp_echo_hdr);
> +
> +     ICMPH_TYPE_SET(iecho, ICMP_ECHO);
> +     ICMPH_CODE_SET(iecho, 0);
> +     iecho->chksum = 0;
> +     iecho->id = PING_ID;
> +     iecho->seqno = lwip_htons(++ping_seq_num);
> +
> +     /* Fill the additional data buffer with some data */
> +     for(i = 0; i < data_len; i++) {
> +             ((char *)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
> +     }

is this additional data used? And if they are shouldn't we care about
endianess?

> +
> +     iecho->chksum = inet_chksum(iecho, len);
> +}
> +
> +static void ping_send_icmp(struct raw_pcb *raw, const ip_addr_t *addr)
> +{
> +     struct pbuf *p;
> +     struct icmp_echo_hdr *iecho;
> +     size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
> +
> +     p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM);
> +     if (!p)
> +             return;
> +
> +     if ((p->len == p->tot_len) && (p->next == NULL)) {
> +             iecho = (struct icmp_echo_hdr *)p->payload;
> +             ping_prepare_echo(iecho, (u16_t)ping_size);
> +             raw_sendto(raw, p, addr);
> +     }
> +
> +     pbuf_free(p);
> +}
> +
> +static void ping_send(void *arg)
> +{
> +     struct raw_pcb *pcb = (struct raw_pcb *)arg;
> +
> +     ping_send_icmp(pcb, ping_target);
> +     sys_timeout(PING_DELAY_MS, ping_send, ping_pcb);
> +}
> +
> +static int ping_loop(const ip_addr_t* addr)
> +{
> +     ulong start;
> +     int ret;
> +
> +     printf("Using %s device\n", eth_get_name());
> +
> +     ret = ping_raw_init();
> +     if (ret < 0)
> +             return ret;
> +     ping_target = addr;
> +
> +     start = get_timer(0);
> +     ping_send(ping_pcb);
> +
> +     do {
> +             eth_rx();

eth_rx() has a ret value. Don't we have to check it here?

> +             if (ping_target_alive)
> +                     break;
> +             sys_check_timeouts();
> +             if (ctrlc()) {
> +                     printf("\nAbort\n");
> +                     break;
> +             }
> +     } while (get_timer(start) < PING_TIMEOUT_MS);
> +
> +     sys_untimeout(ping_send, ping_pcb);
> +     ping_raw_stop();
> +     ping_target = NULL;
> +
> +     if (ping_target_alive) {
> +             ping_target_alive = false;
> +             return 0;
> +     }
> +     printf("ping failed; host %s is not alive\n", ipaddr_ntoa(addr));
> +     return -1;
> +}
> +
> +int do_ping(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
> +{
> +     ip_addr_t addr;
> +
> +     if (argc < 2)
> +             return CMD_RET_USAGE;
> +
> +     if (!ipaddr_aton(argv[1], &addr))
> +             return CMD_RET_USAGE;
> +
> +     if (ping_loop(&addr) < 0)
> +             return CMD_RET_FAILURE;
> +
> +     return CMD_RET_SUCCESS;
> +}
> --
> 2.40.1
>

Regards
/Ilias

Reply via email to