The standard layer 3 ping utility can use the record route (RR) option of IP to collect route data for sent ping messages (ping -R). This patch introduces comparable functionality for batman-adv ICMP messages.
The patch adds a second batman ICMP packet format (icmp_packet_rr) such that up to 17 MAC addresses can be recorded (sufficient for up to 8 hops per direction). When no RR is wanted, the old icmp_packet without the RR overhead can be sent.
batctl is extended to recognize the -R option for the ping subcommand. The output should be the same as for the standard iputils ping program. For this, the destination host is printed two times.
Signed-off-by: Daniel Seither post@tiwoc.de --- Index: batman-adv-kernelland/types.h =================================================================== --- batman-adv-kernelland/types.h (revision 1573) +++ batman-adv-kernelland/types.h (working copy) @@ -106,7 +106,7 @@
struct device_packet { struct list_head list; - struct icmp_packet icmp_packet; + struct icmp_packet_rr icmp_packet; };
struct hna_local_entry { Index: batman-adv-kernelland/packet.h =================================================================== --- batman-adv-kernelland/packet.h (revision 1573) +++ batman-adv-kernelland/packet.h (working copy) @@ -26,6 +26,7 @@ #define BAT_UNICAST 0x03 #define BAT_BCAST 0x04 #define BAT_VIS 0x05 +#define BAT_ICMP_RR 0x06
/* this file is included by batctl which needs these defines */ #define COMPAT_VERSION 9 @@ -71,6 +72,23 @@ uint8_t uid; } __attribute__((packed));
+#define BAT_RR_LEN 16 + +/* icmp_packet_rr must start with all fields from imcp_packet + as this is assumed by code that handles ICMP packets */ +struct icmp_packet_rr { + uint8_t packet_type; + uint8_t version; /* batman version field */ + uint8_t msg_type; /* see ICMP message types above */ + uint8_t ttl; + uint8_t dst[6]; + uint8_t orig[6]; + uint16_t seqno; + uint8_t uid; + uint8_t rr_cur; + uint8_t rr[BAT_RR_LEN][ETH_ALEN]; +} __attribute__((packed)); + struct unicast_packet { uint8_t packet_type; uint8_t version; /* batman version field */ Index: batman-adv-kernelland/device.c =================================================================== --- batman-adv-kernelland/device.c (revision 1573) +++ batman-adv-kernelland/device.c (working copy) @@ -165,6 +165,7 @@ struct device_packet *device_packet; int error; unsigned long flags; + size_t packet_len = sizeof(struct icmp_packet);
if ((file->f_flags & O_NONBLOCK) && (device_client->queue_len == 0)) return -EAGAIN; @@ -190,15 +191,18 @@
spin_unlock_irqrestore(&device_client->lock, flags);
+ if (device_packet->icmp_packet.packet_type == BAT_ICMP_RR) + packet_len = sizeof(struct icmp_packet_rr); + error = __copy_to_user(buf, &device_packet->icmp_packet, - sizeof(struct icmp_packet)); + packet_len);
kfree(device_packet);
if (error) return error;
- return sizeof(struct icmp_packet); + return packet_len; }
ssize_t bat_device_write(struct file *file, const char __user *buff, @@ -206,28 +210,42 @@ { struct device_client *device_client = (struct device_client *)file->private_data; - struct icmp_packet icmp_packet; + struct icmp_packet_rr icmp_packet; struct orig_node *orig_node; struct batman_if *batman_if; uint8_t dstaddr[ETH_ALEN]; unsigned long flags; + size_t packet_len = sizeof(struct icmp_packet); + int with_rr = 0;
if (len < sizeof(struct icmp_packet)) { bat_dbg(DBG_BATMAN, "batman-adv:Error - can't send packet from char device: invalid packet size\n"); return -EINVAL; }
- if (!access_ok(VERIFY_READ, buff, sizeof(struct icmp_packet))) + if (len >= sizeof(struct icmp_packet_rr)) { + with_rr = 1; + packet_len = sizeof(struct icmp_packet_rr); + } + + if (!access_ok(VERIFY_READ, buff, packet_len)) return -EFAULT;
- if (__copy_from_user(&icmp_packet, buff, sizeof(icmp_packet))) + if (__copy_from_user(&icmp_packet, buff, packet_len)) return -EFAULT;
- if (icmp_packet.packet_type != BAT_ICMP) { - bat_dbg(DBG_BATMAN, "batman-adv:Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n"); + if (icmp_packet.packet_type != BAT_ICMP + && icmp_packet.packet_type != BAT_ICMP_RR) { + bat_dbg(DBG_BATMAN, "batman-adv:Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP or BAT_ICMP_RR)\n"); return -EINVAL; }
+ if (!with_rr && icmp_packet.packet_type == BAT_ICMP_RR) { + bat_dbg(DBG_BATMAN, "batman-adv:Error - can't send packet from " + "char device: invalid packet size for BAT_ICMP_RR\n"); + return -EINVAL; + } + if (icmp_packet.msg_type != ECHO_REQUEST) { bat_dbg(DBG_BATMAN, "batman-adv:Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n"); return -EINVAL; @@ -269,8 +287,14 @@ batman_if->net_dev->dev_addr, ETH_ALEN);
+ if (with_rr) { + memcpy(icmp_packet.rr, + batman_if->net_dev->dev_addr, + ETH_ALEN); + } + send_raw_packet((unsigned char *)&icmp_packet, - sizeof(struct icmp_packet), + packet_len, batman_if, dstaddr);
goto out; @@ -298,11 +322,15 @@ }
void bat_device_add_packet(struct device_client *device_client, - struct icmp_packet *icmp_packet) + struct icmp_packet_rr *icmp_packet) { struct device_packet *device_packet; unsigned long flags; + size_t packet_len = sizeof(struct icmp_packet);
+ if (icmp_packet->packet_type == BAT_ICMP_RR) + packet_len = sizeof(struct icmp_packet_rr); + device_packet = kmalloc(sizeof(struct device_packet), GFP_KERNEL);
if (!device_packet) @@ -310,7 +338,7 @@
INIT_LIST_HEAD(&device_packet->list); memcpy(&device_packet->icmp_packet, icmp_packet, - sizeof(struct icmp_packet)); + packet_len);
spin_lock_irqsave(&device_client->lock, flags);
@@ -339,7 +367,7 @@ wake_up(&device_client->queue_wait); }
-void bat_device_receive_packet(struct icmp_packet *icmp_packet) +void bat_device_receive_packet(struct icmp_packet_rr *icmp_packet) { struct device_client *hash = device_client_hash[icmp_packet->uid];
Index: batman-adv-kernelland/device.h =================================================================== --- batman-adv-kernelland/device.h (revision 1573) +++ batman-adv-kernelland/device.h (working copy) @@ -32,5 +32,5 @@ size_t len, loff_t *off); unsigned int bat_device_poll(struct file *file, poll_table *wait); void bat_device_add_packet(struct device_client *device_client, - struct icmp_packet *icmp_packet); -void bat_device_receive_packet(struct icmp_packet *icmp_packet); + struct icmp_packet_rr *icmp_packet); +void bat_device_receive_packet(struct icmp_packet_rr *icmp_packet); Index: batman-adv-kernelland/hard-interface.c =================================================================== --- batman-adv-kernelland/hard-interface.c (revision 1573) +++ batman-adv-kernelland/hard-interface.c (working copy) @@ -479,6 +479,7 @@
/* batman icmp packet */ case BAT_ICMP: + case BAT_ICMP_RR: ret = recv_icmp_packet(skb); break;
Index: batman-adv-kernelland/routing.c =================================================================== --- batman-adv-kernelland/routing.c (revision 1573) +++ batman-adv-kernelland/routing.c (working copy) @@ -709,15 +709,16 @@ static int recv_my_icmp_packet(struct sk_buff *skb) { struct orig_node *orig_node; - struct icmp_packet *icmp_packet; + struct icmp_packet_rr *icmp_packet; struct ethhdr *ethhdr; struct sk_buff *skb_old; struct batman_if *batman_if; int ret; unsigned long flags; uint8_t dstaddr[ETH_ALEN]; + int packet_len = sizeof(struct icmp_packet);
- icmp_packet = (struct icmp_packet *) skb->data; + icmp_packet = (struct icmp_packet_rr *) skb->data; ethhdr = (struct ethhdr *) skb_mac_header(skb);
/* add data to device queue */ @@ -726,6 +727,9 @@ return NET_RX_DROP; }
+ if (icmp_packet->packet_type == BAT_ICMP_RR) + packet_len = sizeof(struct icmp_packet_rr); + /* answer echo request (ping) */ /* get routing information */ spin_lock_irqsave(&orig_hash_lock, flags); @@ -745,12 +749,12 @@
/* create a copy of the skb, if needed, to modify it. */ skb_old = NULL; - if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { + if (!skb_clone_writable(skb, packet_len)) { skb_old = skb; skb = skb_copy(skb, GFP_ATOMIC); if (!skb) return NET_RX_DROP; - icmp_packet = (struct icmp_packet *) skb->data; + icmp_packet = (struct icmp_packet_rr *) skb->data; kfree_skb(skb_old); }
@@ -778,6 +782,7 @@ int ret; unsigned long flags; uint8_t dstaddr[ETH_ALEN]; + int len = sizeof(struct icmp_packet);
icmp_packet = (struct icmp_packet *)skb->data; ethhdr = (struct ethhdr *)skb_mac_header(skb); @@ -789,6 +794,9 @@ return NET_RX_DROP; }
+ if (icmp_packet->packet_type == BAT_ICMP_RR) + len = sizeof(struct icmp_packet_rr); + /* get routing information */ spin_lock_irqsave(&orig_hash_lock, flags); orig_node = ((struct orig_node *) @@ -806,7 +814,7 @@ spin_unlock_irqrestore(&orig_hash_lock, flags);
/* create a copy of the skb, if needed, to modify it. */ - if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { + if (!skb_clone_writable(skb, len)) { skb_old = skb; skb = skb_copy(skb, GFP_ATOMIC); if (!skb) @@ -832,7 +840,7 @@
int recv_icmp_packet(struct sk_buff *skb) { - struct icmp_packet *icmp_packet; + struct icmp_packet_rr *icmp_packet; struct ethhdr *ethhdr; struct orig_node *orig_node; struct sk_buff *skb_old; @@ -860,8 +868,23 @@ if (!is_my_mac(ethhdr->h_dest)) return NET_RX_DROP;
- icmp_packet = (struct icmp_packet *) skb->data; + icmp_packet = (struct icmp_packet_rr *) skb->data;
+ if (icmp_packet->packet_type == BAT_ICMP_RR) { + hdr_size = sizeof(struct icmp_packet_rr); + + /* drop packet if it has not necessary minimum size */ + if (skb_headlen(skb) < hdr_size) + return NET_RX_DROP; + + /* add record route information if not full */ + if (icmp_packet->rr_cur < BAT_RR_LEN) { + memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), + ethhdr->h_dest, ETH_ALEN); + icmp_packet->rr_cur++; + } + } + /* packet for me */ if (is_my_mac(icmp_packet->dst)) return recv_my_icmp_packet(skb); @@ -888,12 +911,12 @@ spin_unlock_irqrestore(&orig_hash_lock, flags);
/* create a copy of the skb, if needed, to modify it. */ - if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { + if (!skb_clone_writable(skb, hdr_size)) { skb_old = skb; skb = skb_copy(skb, GFP_ATOMIC); if (!skb) return NET_RX_DROP; - icmp_packet = (struct icmp_packet *) skb->data; + icmp_packet = (struct icmp_packet_rr *) skb->data; kfree_skb(skb_old); }
Index: batctl/ping.c =================================================================== --- batctl/ping.c (revision 1573) +++ batctl/ping.c (working copy) @@ -48,6 +48,7 @@ printf(" \t -h print this help\n"); printf(" \t -i interval in seconds\n"); printf(" \t -t timeout in seconds\n"); + printf(" \t -R record route\n"); }
void sig_handler(int sig) @@ -64,20 +65,22 @@
int ping(int argc, char **argv) { - struct icmp_packet icmp_packet_out, icmp_packet_in; + struct icmp_packet_rr icmp_packet_out, icmp_packet_in; struct timeval tv; - struct ether_addr *dst_mac = NULL; - struct bat_host *bat_host; + struct ether_addr *dst_mac = NULL, *rr_mac = NULL; + struct bat_host *bat_host, *rr_host; ssize_t read_len; fd_set read_socket; int ret = EXIT_FAILURE, ping_fd = 0, res, optchar, found_args = 1; - int loop_count = -1, loop_interval = 1, timeout = 1; + int loop_count = -1, loop_interval = 1, timeout = 1, rr = 0, i; unsigned int seq_counter = 0, packets_out = 0, packets_in = 0, packets_loss; - char *dst_string, *mac_string; + char *dst_string, *mac_string, *rr_string; double time_delta; float min = 0.0, max = 0.0, avg = 0.0; + uint8_t last_rr_cur = 0, last_rr[BAT_RR_LEN][ETH_ALEN]; + size_t packet_len;
- while ((optchar = getopt(argc, argv, "hc:i:t:")) != -1) { + while ((optchar = getopt(argc, argv, "hc:i:t:R")) != -1) { switch (optchar) { case 'c': loop_count = strtol(optarg, NULL , 10); @@ -100,6 +103,10 @@ timeout = 1; found_args += ((*((char*)(optarg - 1)) == optchar ) ? 1 : 2); break; + case 'R': + rr = 1; + found_args++; + break; default: ping_usage(); return EXIT_FAILURE; @@ -141,6 +148,8 @@ goto out; }
+ packet_len = sizeof(struct icmp_packet); + memcpy(&icmp_packet_out.dst, dst_mac, ETH_ALEN); icmp_packet_out.packet_type = BAT_ICMP; icmp_packet_out.version = COMPAT_VERSION; @@ -148,8 +157,15 @@ icmp_packet_out.ttl = 50; icmp_packet_out.seqno = 0;
+ if (rr) { + icmp_packet_out.packet_type = BAT_ICMP_RR; + packet_len = sizeof(struct icmp_packet_rr); + icmp_packet_out.rr_cur = 1; + memset(&icmp_packet_out.rr, 0, BAT_RR_LEN * ETH_ALEN); + } + printf("PING %s (%s) %zu(%zu) bytes of data\n", dst_string, mac_string, - sizeof(icmp_packet_out), sizeof(icmp_packet_out) + 28); + packet_len, packet_len + 28);
while (!is_aborted) { if (loop_count == 0) @@ -160,7 +176,7 @@
icmp_packet_out.seqno = htons(++seq_counter);
- if (write(ping_fd, (char *)&icmp_packet_out, sizeof(icmp_packet_out)) < 0) { + if (write(ping_fd, (char *)&icmp_packet_out, packet_len) < 0) { printf("Error - can't write to batman adv kernel file '%s': %s\n", BAT_DEVICE, strerror(errno)); goto sleep; } @@ -188,26 +204,55 @@ if (res < 0) goto sleep;
- read_len = read(ping_fd, (char *)&icmp_packet_in, sizeof(icmp_packet_in)); + read_len = read(ping_fd, (char *)&icmp_packet_in, packet_len);
if (read_len < 0) { printf("Error - can't read from batman adv kernel file '%s': %s\n", BAT_DEVICE, strerror(errno)); goto sleep; }
- if ((size_t)read_len < sizeof(icmp_packet_in)) { + if ((size_t)read_len < packet_len) { printf("Warning - dropping received packet as it is smaller than expected (%zu): %zd\n", - sizeof(icmp_packet_in), read_len); + packet_len, read_len); goto sleep; }
switch (icmp_packet_in.msg_type) { case ECHO_REPLY: time_delta = end_timer(); - printf("%zd bytes from %s icmp_seq=%hu ttl=%d time=%.2f ms\n", + printf("%zd bytes from %s icmp_seq=%hu ttl=%d time=%.2f ms", read_len, dst_string, ntohs(icmp_packet_in.seqno), icmp_packet_in.ttl, time_delta);
+ if (icmp_packet_in.packet_type == BAT_ICMP_RR) { + if (last_rr_cur == icmp_packet_in.rr_cur + && !memcmp(last_rr, icmp_packet_in.rr, BAT_RR_LEN * ETH_ALEN)) { + + printf("\t(same route)\n"); + + } else { + printf("\nRR: "); + for (i = 0; i < BAT_RR_LEN + && i < icmp_packet_in.rr_cur; i++) { + + rr_mac = (struct ether_addr *)&icmp_packet_in.rr[i]; + rr_host = bat_hosts_find_by_mac((char *)rr_mac); + if (rr_host) + rr_string = rr_host->name; + else + rr_string = ether_ntoa_long(rr_mac); + printf("\t%s\n", rr_string); + if (memcmp(rr_mac, dst_mac, ETH_ALEN) == 0) + printf("\t%s\n", rr_string); + } + printf("\n"); + + last_rr_cur = icmp_packet_in.rr_cur; + memcpy(last_rr, icmp_packet_in.rr, BAT_RR_LEN * ETH_ALEN); + } + } else + printf("\n"); + if ((time_delta < min) || (min == 0.0)) min = time_delta; if (time_delta > max)
Hey,
The standard layer 3 ping utility can use the record route (RR) option of IP to collect route data for sent ping messages (ping -R). This patch introduces comparable functionality for batman-adv ICMP messages.
I don't think we need another packet type for this. I reworked your patches a bit. As soon as you checked if you like it this way I will commit them.
Note: I split them into 2 patches because batman-adv & batctl reside in different branches. On top of that syncing distinct patches with the git repos is much less painful. :)
Cheers, Marek
The standard layer 3 ping utility can use the record route (RR) option of IP to collect route data for sent ping messages (ping -R). This patch introduces comparable functionality for batman-adv ICMP messages.
The patch adds a second batman ICMP packet format (icmp_packet_rr) such that up to 17 MAC addresses can be recorded (sufficient for up to 8 hops per direction). When no RR is wanted, the old icmp_packet without the RR overhead can be sent.
Signed-off-by: Daniel Seither post@tiwoc.de Signed-off-by: Marek Lindner lindner_marek@yahoo.de --- batman-adv-kernelland/device.c | 42 ++++++++++++++++++++++--------------- batman-adv-kernelland/device.h | 6 +++- batman-adv-kernelland/packet.h | 17 +++++++++++++++ batman-adv-kernelland/routing.c | 44 +++++++++++++++++++++++++------------- batman-adv-kernelland/types.h | 3 +- 5 files changed, 77 insertions(+), 35 deletions(-)
diff --git a/batman-adv-kernelland/device.c b/batman-adv-kernelland/device.c index df51f1c..0c3c0b3 100644 --- a/batman-adv-kernelland/device.c +++ b/batman-adv-kernelland/device.c @@ -163,6 +163,7 @@ ssize_t bat_device_read(struct file *file, char __user *buf, size_t count, struct device_client *device_client = (struct device_client *)file->private_data; struct device_packet *device_packet; + size_t packet_len; int error; unsigned long flags;
@@ -191,14 +192,15 @@ ssize_t bat_device_read(struct file *file, char __user *buf, size_t count, spin_unlock_irqrestore(&device_client->lock, flags);
error = __copy_to_user(buf, &device_packet->icmp_packet, - sizeof(struct icmp_packet)); + device_packet->icmp_len);
+ packet_len = device_packet->icmp_len; kfree(device_packet);
if (error) return error;
- return sizeof(struct icmp_packet); + return packet_len; }
ssize_t bat_device_write(struct file *file, const char __user *buff, @@ -206,9 +208,10 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, { struct device_client *device_client = (struct device_client *)file->private_data; - struct icmp_packet icmp_packet; + struct icmp_packet_rr icmp_packet; struct orig_node *orig_node; struct batman_if *batman_if; + size_t packet_len = sizeof(struct icmp_packet); uint8_t dstaddr[ETH_ALEN]; unsigned long flags;
@@ -217,10 +220,13 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, return -EINVAL; }
- if (!access_ok(VERIFY_READ, buff, sizeof(struct icmp_packet))) + if (len >= sizeof(struct icmp_packet_rr)) + packet_len = sizeof(struct icmp_packet_rr); + + if (!access_ok(VERIFY_READ, buff, packet_len)) return -EFAULT;
- if (__copy_from_user(&icmp_packet, buff, sizeof(icmp_packet))) + if (__copy_from_user(&icmp_packet, buff, packet_len)) return -EFAULT;
if (icmp_packet.packet_type != BAT_ICMP) { @@ -238,7 +244,7 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, if (icmp_packet.version != COMPAT_VERSION) { icmp_packet.msg_type = PARAMETER_PROBLEM; icmp_packet.ttl = COMPAT_VERSION; - bat_device_add_packet(device_client, &icmp_packet); + bat_device_add_packet(device_client, &icmp_packet, packet_len); goto out; }
@@ -265,13 +271,13 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, if (batman_if->if_active != IF_ACTIVE) goto dst_unreach;
- memcpy(icmp_packet.orig, - batman_if->net_dev->dev_addr, - ETH_ALEN); + memcpy(icmp_packet.orig, batman_if->net_dev->dev_addr, ETH_ALEN); + + if (packet_len == sizeof(struct icmp_packet_rr)) + memcpy(icmp_packet.rr, batman_if->net_dev->dev_addr, ETH_ALEN);
send_raw_packet((unsigned char *)&icmp_packet, - sizeof(struct icmp_packet), - batman_if, dstaddr); + packet_len, batman_if, dstaddr);
goto out;
@@ -279,7 +285,7 @@ unlock: spin_unlock_irqrestore(&orig_hash_lock, flags); dst_unreach: icmp_packet.msg_type = DESTINATION_UNREACHABLE; - bat_device_add_packet(device_client, &icmp_packet); + bat_device_add_packet(device_client, &icmp_packet, packet_len); out: return len; } @@ -298,7 +304,8 @@ unsigned int bat_device_poll(struct file *file, poll_table *wait) }
void bat_device_add_packet(struct device_client *device_client, - struct icmp_packet *icmp_packet) + struct icmp_packet_rr *icmp_packet, + size_t icmp_len) { struct device_packet *device_packet; unsigned long flags; @@ -309,8 +316,8 @@ void bat_device_add_packet(struct device_client *device_client, return;
INIT_LIST_HEAD(&device_packet->list); - memcpy(&device_packet->icmp_packet, icmp_packet, - sizeof(struct icmp_packet)); + memcpy(&device_packet->icmp_packet, icmp_packet, icmp_len); + device_packet->icmp_len = icmp_len;
spin_lock_irqsave(&device_client->lock, flags);
@@ -339,10 +346,11 @@ void bat_device_add_packet(struct device_client *device_client, wake_up(&device_client->queue_wait); }
-void bat_device_receive_packet(struct icmp_packet *icmp_packet) +void bat_device_receive_packet(struct icmp_packet_rr *icmp_packet, + size_t icmp_len) { struct device_client *hash = device_client_hash[icmp_packet->uid];
if (hash) - bat_device_add_packet(hash, icmp_packet); + bat_device_add_packet(hash, icmp_packet, icmp_len); } diff --git a/batman-adv-kernelland/device.h b/batman-adv-kernelland/device.h index 46c0f44..7a9394b 100644 --- a/batman-adv-kernelland/device.h +++ b/batman-adv-kernelland/device.h @@ -32,5 +32,7 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, size_t len, loff_t *off); unsigned int bat_device_poll(struct file *file, poll_table *wait); void bat_device_add_packet(struct device_client *device_client, - struct icmp_packet *icmp_packet); -void bat_device_receive_packet(struct icmp_packet *icmp_packet); + struct icmp_packet_rr *icmp_packet, + size_t icmp_len); +void bat_device_receive_packet(struct icmp_packet_rr *icmp_packet, + size_t icmp_len); diff --git a/batman-adv-kernelland/packet.h b/batman-adv-kernelland/packet.h index 1c8e6c8..c8b973f 100644 --- a/batman-adv-kernelland/packet.h +++ b/batman-adv-kernelland/packet.h @@ -71,6 +71,23 @@ struct icmp_packet { uint8_t uid; } __attribute__((packed));
+#define BAT_RR_LEN 16 + +/* icmp_packet_rr must start with all fields from imcp_packet + as this is assumed by code that handles ICMP packets */ +struct icmp_packet_rr { + uint8_t packet_type; + uint8_t version; /* batman version field */ + uint8_t msg_type; /* see ICMP message types above */ + uint8_t ttl; + uint8_t dst[6]; + uint8_t orig[6]; + uint16_t seqno; + uint8_t uid; + uint8_t rr_cur; + uint8_t rr[BAT_RR_LEN][ETH_ALEN]; +} __attribute__((packed)); + struct unicast_packet { uint8_t packet_type; uint8_t version; /* batman version field */ diff --git a/batman-adv-kernelland/routing.c b/batman-adv-kernelland/routing.c index a3adc7f..47d5757 100644 --- a/batman-adv-kernelland/routing.c +++ b/batman-adv-kernelland/routing.c @@ -706,10 +706,10 @@ int recv_bat_packet(struct sk_buff *skb, return NET_RX_SUCCESS; }
-static int recv_my_icmp_packet(struct sk_buff *skb) +static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) { struct orig_node *orig_node; - struct icmp_packet *icmp_packet; + struct icmp_packet_rr *icmp_packet; struct ethhdr *ethhdr; struct sk_buff *skb_old; struct batman_if *batman_if; @@ -717,12 +717,12 @@ static int recv_my_icmp_packet(struct sk_buff *skb) unsigned long flags; uint8_t dstaddr[ETH_ALEN];
- icmp_packet = (struct icmp_packet *) skb->data; - ethhdr = (struct ethhdr *) skb_mac_header(skb); + icmp_packet = (struct icmp_packet_rr *)skb->data; + ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* add data to device queue */ if (icmp_packet->msg_type != ECHO_REQUEST) { - bat_device_receive_packet(icmp_packet); + bat_device_receive_packet(icmp_packet, icmp_len); return NET_RX_DROP; }
@@ -745,12 +745,12 @@ static int recv_my_icmp_packet(struct sk_buff *skb)
/* create a copy of the skb, if needed, to modify it. */ skb_old = NULL; - if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { + if (!skb_clone_writable(skb, icmp_len)) { skb_old = skb; skb = skb_copy(skb, GFP_ATOMIC); if (!skb) return NET_RX_DROP; - icmp_packet = (struct icmp_packet *) skb->data; + icmp_packet = (struct icmp_packet_rr *)skb->data; kfree_skb(skb_old); }
@@ -768,7 +768,7 @@ static int recv_my_icmp_packet(struct sk_buff *skb) return ret; }
-static int recv_icmp_ttl_exceeded(struct sk_buff *skb) +static int recv_icmp_ttl_exceeded(struct sk_buff *skb, size_t icmp_len) { struct orig_node *orig_node; struct icmp_packet *icmp_packet; @@ -806,7 +806,7 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb) spin_unlock_irqrestore(&orig_hash_lock, flags);
/* create a copy of the skb, if needed, to modify it. */ - if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { + if (!skb_clone_writable(skb, icmp_len)) { skb_old = skb; skb = skb_copy(skb, GFP_ATOMIC); if (!skb) @@ -832,7 +832,7 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb)
int recv_icmp_packet(struct sk_buff *skb) { - struct icmp_packet *icmp_packet; + struct icmp_packet_rr *icmp_packet; struct ethhdr *ethhdr; struct orig_node *orig_node; struct sk_buff *skb_old; @@ -842,6 +842,12 @@ int recv_icmp_packet(struct sk_buff *skb) unsigned long flags; uint8_t dstaddr[ETH_ALEN];
+ /** + * we truncate all incoming icmp packets if they don't match our size + */ + if (skb_headlen(skb) >= sizeof(struct icmp_packet_rr)) + hdr_size = sizeof(struct icmp_packet_rr); + /* drop packet if it has not necessary minimum size */ if (skb_headlen(skb) < hdr_size) return NET_RX_DROP; @@ -860,15 +866,23 @@ int recv_icmp_packet(struct sk_buff *skb) if (!is_my_mac(ethhdr->h_dest)) return NET_RX_DROP;
- icmp_packet = (struct icmp_packet *) skb->data; + icmp_packet = (struct icmp_packet_rr *)skb->data; + + /* add record route information if not full */ + if ((hdr_size == sizeof(struct icmp_packet_rr)) && + (icmp_packet->rr_cur < BAT_RR_LEN)) { + memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), + ethhdr->h_dest, ETH_ALEN); + icmp_packet->rr_cur++; + }
/* packet for me */ if (is_my_mac(icmp_packet->dst)) - return recv_my_icmp_packet(skb); + return recv_my_icmp_packet(skb, hdr_size);
/* TTL exceeded */ if (icmp_packet->ttl < 2) - return recv_icmp_ttl_exceeded(skb); + return recv_icmp_ttl_exceeded(skb, hdr_size);
ret = NET_RX_DROP;
@@ -888,12 +902,12 @@ int recv_icmp_packet(struct sk_buff *skb) spin_unlock_irqrestore(&orig_hash_lock, flags);
/* create a copy of the skb, if needed, to modify it. */ - if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { + if (!skb_clone_writable(skb, hdr_size)) { skb_old = skb; skb = skb_copy(skb, GFP_ATOMIC); if (!skb) return NET_RX_DROP; - icmp_packet = (struct icmp_packet *) skb->data; + icmp_packet = (struct icmp_packet_rr *)skb->data; kfree_skb(skb_old); }
diff --git a/batman-adv-kernelland/types.h b/batman-adv-kernelland/types.h index d9cb5d1..a82b52d 100644 --- a/batman-adv-kernelland/types.h +++ b/batman-adv-kernelland/types.h @@ -106,7 +106,8 @@ struct device_client {
struct device_packet { struct list_head list; - struct icmp_packet icmp_packet; + size_t icmp_len; + struct icmp_packet_rr icmp_packet; };
struct hna_local_entry {
batctl is extended to recognize the -R option for the ping subcommand. The output should be the same as for the standard iputils ping program. For this, the destination host is printed twice.
Signed-off-by: Daniel Seither post@tiwoc.de --- batctl/ping.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 60 insertions(+), 13 deletions(-)
diff --git a/batctl/ping.c b/batctl/ping.c index c14141c..0352870 100644 --- a/batctl/ping.c +++ b/batctl/ping.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: * * Andreas Langer a.langer@q-dsl.de, Marek Lindner lindner_marek@yahoo.de @@ -48,6 +48,7 @@ void ping_usage(void) printf(" \t -h print this help\n"); printf(" \t -i interval in seconds\n"); printf(" \t -t timeout in seconds\n"); + printf(" \t -R record route\n"); }
void sig_handler(int sig) @@ -64,20 +65,22 @@ void sig_handler(int sig)
int ping(int argc, char **argv) { - struct icmp_packet icmp_packet_out, icmp_packet_in; + struct icmp_packet_rr icmp_packet_out, icmp_packet_in; struct timeval tv; - struct ether_addr *dst_mac = NULL; - struct bat_host *bat_host; + struct ether_addr *dst_mac = NULL, *rr_mac = NULL; + struct bat_host *bat_host, *rr_host; ssize_t read_len; fd_set read_socket; int ret = EXIT_FAILURE, ping_fd = 0, res, optchar, found_args = 1; - int loop_count = -1, loop_interval = 1, timeout = 1; + int loop_count = -1, loop_interval = 1, timeout = 1, rr = 0, i; unsigned int seq_counter = 0, packets_out = 0, packets_in = 0, packets_loss; - char *dst_string, *mac_string; + char *dst_string, *mac_string, *rr_string; double time_delta; float min = 0.0, max = 0.0, avg = 0.0; + uint8_t last_rr_cur = 0, last_rr[BAT_RR_LEN][ETH_ALEN]; + size_t packet_len;
- while ((optchar = getopt(argc, argv, "hc:i:t:")) != -1) { + while ((optchar = getopt(argc, argv, "hc:i:t:R")) != -1) { switch (optchar) { case 'c': loop_count = strtol(optarg, NULL , 10); @@ -100,6 +103,10 @@ int ping(int argc, char **argv) timeout = 1; found_args += ((*((char*)(optarg - 1)) == optchar ) ? 1 : 2); break; + case 'R': + rr = 1; + found_args++; + break; default: ping_usage(); return EXIT_FAILURE; @@ -141,6 +148,8 @@ int ping(int argc, char **argv) goto out; }
+ packet_len = sizeof(struct icmp_packet); + memcpy(&icmp_packet_out.dst, dst_mac, ETH_ALEN); icmp_packet_out.packet_type = BAT_ICMP; icmp_packet_out.version = COMPAT_VERSION; @@ -148,8 +157,15 @@ int ping(int argc, char **argv) icmp_packet_out.ttl = 50; icmp_packet_out.seqno = 0;
+ if (rr) { + packet_len = sizeof(struct icmp_packet_rr); + icmp_packet_out.rr_cur = 1; + memset(&icmp_packet_out.rr, 0, BAT_RR_LEN * ETH_ALEN); + memset(last_rr, 0, BAT_RR_LEN * ETH_ALEN); + } + printf("PING %s (%s) %zu(%zu) bytes of data\n", dst_string, mac_string, - sizeof(icmp_packet_out), sizeof(icmp_packet_out) + 28); + packet_len, packet_len + 28);
while (!is_aborted) { if (loop_count == 0) @@ -160,7 +176,7 @@ int ping(int argc, char **argv)
icmp_packet_out.seqno = htons(++seq_counter);
- if (write(ping_fd, (char *)&icmp_packet_out, sizeof(icmp_packet_out)) < 0) { + if (write(ping_fd, (char *)&icmp_packet_out, packet_len) < 0) { printf("Error - can't write to batman adv kernel file '%s': %s\n", BAT_DEVICE, strerror(errno)); goto sleep; } @@ -188,26 +204,57 @@ int ping(int argc, char **argv) if (res < 0) goto sleep;
- read_len = read(ping_fd, (char *)&icmp_packet_in, sizeof(icmp_packet_in)); + read_len = read(ping_fd, (char *)&icmp_packet_in, packet_len);
if (read_len < 0) { printf("Error - can't read from batman adv kernel file '%s': %s\n", BAT_DEVICE, strerror(errno)); goto sleep; }
- if ((size_t)read_len < sizeof(icmp_packet_in)) { + if ((size_t)read_len < packet_len) { printf("Warning - dropping received packet as it is smaller than expected (%zu): %zd\n", - sizeof(icmp_packet_in), read_len); + packet_len, read_len); goto sleep; }
switch (icmp_packet_in.msg_type) { case ECHO_REPLY: time_delta = end_timer(); - printf("%zd bytes from %s icmp_seq=%hu ttl=%d time=%.2f ms\n", + printf("%zd bytes from %s icmp_seq=%hu ttl=%d time=%.2f ms", read_len, dst_string, ntohs(icmp_packet_in.seqno), icmp_packet_in.ttl, time_delta);
+ if (read_len == sizeof(struct icmp_packet_rr)) { + if (last_rr_cur == icmp_packet_in.rr_cur + && !memcmp(last_rr, icmp_packet_in.rr, BAT_RR_LEN * ETH_ALEN)) { + + printf("\t(same route)"); + + } else { + printf("\nRR: "); + + for (i = 0; i < BAT_RR_LEN + && i < icmp_packet_in.rr_cur; i++) { + + rr_mac = (struct ether_addr *)&icmp_packet_in.rr[i]; + rr_host = bat_hosts_find_by_mac((char *)rr_mac); + if (rr_host) + rr_string = rr_host->name; + else + rr_string = ether_ntoa_long(rr_mac); + printf("\t%s\n", rr_string); + + if (memcmp(rr_mac, dst_mac, ETH_ALEN) == 0) + printf("\t%s\n", rr_string); + } + + last_rr_cur = icmp_packet_in.rr_cur; + memcpy(last_rr, icmp_packet_in.rr, BAT_RR_LEN * ETH_ALEN); + } + } + + printf("\n"); + if ((time_delta < min) || (min == 0.0)) min = time_delta; if (time_delta > max)
Marek Lindner schrieb:
I don't think we need another packet type for this. I reworked your patches a bit. As soon as you checked if you like it this way I will commit them.
Okay, please commit the patches :)
Daniel
On Tuesday 16 February 2010 22:53:08 Daniel Seither wrote:
Okay, please commit the patches :)
There are in (1574 + 1575). Thanks again for this good work. Don't hesitate to send more if you want. :-)
Cheers, Marek
b.a.t.m.a.n@lists.open-mesh.org