1/** 2 * \file ping.c 3 * \brief 4 */ 5 6 7/* 8 * Copyright (c) 2017 ETH Zurich. 9 * All rights reserved. 10 * 11 * This file is distributed under the terms in the attached LICENSE file. 12 * If you do not find this file, copies can be found by writing to: 13 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 14 */ 15 16 17#include <barrelfish/barrelfish.h> 18 19#include <lwip/ip.h> 20#include <lwip/udp.h> 21#include <lwip/pbuf.h> 22 23#include <lwip/mem.h> 24#include <lwip/raw.h> 25#include <lwip/icmp.h> 26#include <lwip/netif.h> 27#include <lwip/sys.h> 28#include <lwip/timeouts.h> 29#include <lwip/inet_chksum.h> 30#include <lwip/prot/ip4.h> 31 32#include <net/net.h> 33 34static ip_addr_t ping_addr; 35 36static struct raw_pcb *ping_pcb; 37 38#define PING_TIMEOUT 1000 39#define PING_DELAY 1000 40#define PING_ID 0xBFBF 41 42uint16_t ping_data_size = 64; 43 44static uint16_t ping_seq_num = 0; 45 46 47struct result 48{ 49 cycles_t t_start; 50 cycles_t t_end; 51 uint8_t received; 52}; 53 54#define PING_RESULT_MAX 512 55 56struct result results[PING_RESULT_MAX]; 57 58 59 60 61#include <barrelfish/sys_debug.h> 62static cycles_t tsc_per_us = 0; 63static inline uint64_t cycles_to_us(struct result *res) 64{ 65 if (tsc_per_us == 0) { 66 sys_debug_get_tsc_per_ms(&tsc_per_us); 67 tsc_per_us /= 1000; 68 } 69 70 return (res->t_end - res->t_start) / (tsc_per_us); 71} 72 73static uint8_t 74ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) 75{ 76 struct icmp_echo_hdr *iecho; 77 78 if ((p->tot_len >= (PBUF_IP_HLEN + sizeof(struct icmp_echo_hdr))) && 79 pbuf_header(p, -PBUF_IP_HLEN) == 0) { 80 iecho = (struct icmp_echo_hdr *)p->payload; 81 82 uint16_t seq = lwip_ntohs(iecho->seqno); 83 84 if ((iecho->id == PING_ID) && (iecho->seqno == lwip_htons(ping_seq_num))) { 85 if (results[seq & (PING_RESULT_MAX - 1)].t_end != 0) { 86 debug_printf("t_end is non null???"); 87 } 88 results[seq & (PING_RESULT_MAX - 1)].t_end = rdtsc(); 89 results[seq & (PING_RESULT_MAX - 1)].received = 1; 90 91 char ip_str[16] = {0}; 92 93 strncpy(ip_str, ip4addr_ntoa(addr), sizeof(ip_str)); 94 95 printf("%u bytes from %s: icmp_seq=%u, ttl=%u time=%lu us (%lu)\n", 96 ping_data_size, ip_str, seq, 97 42, cycles_to_us(&results[seq & (PING_RESULT_MAX - 1)]), 98 results[seq & (PING_RESULT_MAX - 1)].t_end - results[seq & (PING_RESULT_MAX - 1)].t_start); 99 100 101 102 pbuf_free(p); 103 return 1; /* eat the packet */ 104 } 105 /* not eaten, restore original packet */ 106 pbuf_header(p, PBUF_IP_HLEN); 107 } 108 109 return 0; /* don't eat the packet */ 110} 111 112static void 113ping_send(struct raw_pcb *raw, ip_addr_t *addr) 114{ 115 struct pbuf *p; 116 struct icmp_echo_hdr *iecho; 117 size_t ping_size = sizeof(struct icmp_echo_hdr) + ping_data_size; 118 119 p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM); 120 if (!p) { 121 return; 122 } 123 if ((p->len == p->tot_len) && (p->next == NULL)) { 124 iecho = (struct icmp_echo_hdr *)p->payload; 125 126 ICMPH_TYPE_SET(iecho, ICMP_ECHO); 127 ICMPH_CODE_SET(iecho, 0); 128 iecho->chksum = 0; 129 iecho->id = PING_ID; 130 iecho->seqno = lwip_htons(++ping_seq_num); 131 132 /* fill the additional data buffer with some data */ 133 for(uint16_t i = 0; i < ping_data_size; i++) { 134 ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; 135 } 136 137 iecho->chksum = inet_chksum(iecho, ping_size); 138 139 results[ping_seq_num & (PING_RESULT_MAX - 1)].t_end = 0; 140 results[ping_seq_num & (PING_RESULT_MAX - 1)].received = 0; 141 results[ping_seq_num & (PING_RESULT_MAX - 1)].t_start = rdtsc(); 142 143 raw_sendto(raw, p, addr); 144 } 145 pbuf_free(p); 146} 147 148static void 149ping_timeout(void *arg) 150{ 151 struct raw_pcb *pcb = (struct raw_pcb*)arg; 152 153 LWIP_ASSERT("ping_timeout: no pcb given!", pcb != NULL); 154 155 if (!results[ping_seq_num & (PING_RESULT_MAX - 1)].received) { 156 printf("Timeout.\n"); 157 } 158 159 ping_send(pcb, &ping_addr); 160 161 sys_timeout(PING_DELAY, ping_timeout, pcb); 162} 163 164 165int main(int argc, char *argv[]) 166{ 167 errval_t err; 168 169 debug_printf("PING started.\n"); 170 171 /* parse ip */ 172 173 if (argc != 2 || !ip4addr_aton(argv[1], &ping_addr)) { 174 USER_PANIC("Invalid address supplied: %s\n", argv[1]); 175 } 176 177 debug_printf("PING with IP %s.\n", argv[1]); 178 179 /* connect to the network */ 180 err = networking_init_default(); 181 if (err_is_fail(err)) { 182 USER_PANIC_ERR(err, "Failed to initialize the network"); 183 } 184 185 debug_printf("PING network initialized.\n"); 186 187 ping_pcb = raw_new(IP_PROTO_ICMP); 188 if (ping_pcb == NULL) { 189 USER_PANIC("could not get a new raw pcb"); 190 } 191 192 debug_printf("PING pcb created.\n"); 193 194 raw_recv(ping_pcb, ping_recv, NULL); 195 raw_bind(ping_pcb, IP_ADDR_ANY); 196 sys_timeout(PING_DELAY, ping_timeout, ping_pcb); 197 198 199 200 while(1) { 201 //event_dispatch_non_block(get_default_waitset()); 202 networking_poll(); 203 } 204 205 debug_printf("UDP ECHO termiated.\n"); 206 207 return 0; 208} 209 210 211