提交 e4cb3720 编写于 作者: D Daniel Seither 提交者: Greg Kroah-Hartman

Staging: batman-adv: record route for ICMP messages

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: NDaniel Seither <post@tiwoc.de>
Signed-off-by: NMarek Lindner <lindner_marek@yahoo.de>
[sven.eckelmann@gmx.de: Rework on top of current version]
Signed-off-by: NSven Eckelmann <sven.eckelmann@gmx.de>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 11f79dec
...@@ -32,7 +32,8 @@ ...@@ -32,7 +32,8 @@
static struct socket_client *socket_client_hash[256]; static struct socket_client *socket_client_hash[256];
static void bat_socket_add_packet(struct socket_client *socket_client, static void bat_socket_add_packet(struct socket_client *socket_client,
struct icmp_packet *icmp_packet); struct icmp_packet_rr *icmp_packet,
size_t icmp_len);
void bat_socket_init(void) void bat_socket_init(void)
{ {
...@@ -110,6 +111,7 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf, ...@@ -110,6 +111,7 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf,
struct socket_client *socket_client = struct socket_client *socket_client =
(struct socket_client *)file->private_data; (struct socket_client *)file->private_data;
struct socket_packet *socket_packet; struct socket_packet *socket_packet;
size_t packet_len;
int error; int error;
unsigned long flags; unsigned long flags;
...@@ -138,14 +140,15 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf, ...@@ -138,14 +140,15 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf,
spin_unlock_irqrestore(&socket_client->lock, flags); spin_unlock_irqrestore(&socket_client->lock, flags);
error = __copy_to_user(buf, &socket_packet->icmp_packet, error = __copy_to_user(buf, &socket_packet->icmp_packet,
sizeof(struct icmp_packet)); socket_packet->icmp_len);
packet_len = socket_packet->icmp_len;
kfree(socket_packet); kfree(socket_packet);
if (error) if (error)
return -EFAULT; return -EFAULT;
return sizeof(struct icmp_packet); return packet_len;
} }
static ssize_t bat_socket_write(struct file *file, const char __user *buff, static ssize_t bat_socket_write(struct file *file, const char __user *buff,
...@@ -153,9 +156,10 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -153,9 +156,10 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
{ {
struct socket_client *socket_client = struct socket_client *socket_client =
(struct socket_client *)file->private_data; (struct socket_client *)file->private_data;
struct icmp_packet icmp_packet; struct icmp_packet_rr icmp_packet;
struct orig_node *orig_node; struct orig_node *orig_node;
struct batman_if *batman_if; struct batman_if *batman_if;
size_t packet_len = sizeof(struct icmp_packet);
uint8_t dstaddr[ETH_ALEN]; uint8_t dstaddr[ETH_ALEN];
unsigned long flags; unsigned long flags;
...@@ -166,10 +170,13 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -166,10 +170,13 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
return -EINVAL; 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; return -EFAULT;
if (__copy_from_user(&icmp_packet, buff, sizeof(icmp_packet))) if (__copy_from_user(&icmp_packet, buff, packet_len))
return -EFAULT; return -EFAULT;
if (icmp_packet.packet_type != BAT_ICMP) { if (icmp_packet.packet_type != BAT_ICMP) {
...@@ -191,7 +198,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -191,7 +198,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
if (icmp_packet.version != COMPAT_VERSION) { if (icmp_packet.version != COMPAT_VERSION) {
icmp_packet.msg_type = PARAMETER_PROBLEM; icmp_packet.msg_type = PARAMETER_PROBLEM;
icmp_packet.ttl = COMPAT_VERSION; icmp_packet.ttl = COMPAT_VERSION;
bat_socket_add_packet(socket_client, &icmp_packet); bat_socket_add_packet(socket_client, &icmp_packet, packet_len);
goto out; goto out;
} }
...@@ -218,13 +225,13 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -218,13 +225,13 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
if (batman_if->if_status != IF_ACTIVE) if (batman_if->if_status != IF_ACTIVE)
goto dst_unreach; goto dst_unreach;
memcpy(icmp_packet.orig, memcpy(icmp_packet.orig, batman_if->net_dev->dev_addr, ETH_ALEN);
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, send_raw_packet((unsigned char *)&icmp_packet,
sizeof(struct icmp_packet), packet_len, batman_if, dstaddr);
batman_if, dstaddr);
goto out; goto out;
...@@ -232,7 +239,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -232,7 +239,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
spin_unlock_irqrestore(&orig_hash_lock, flags); spin_unlock_irqrestore(&orig_hash_lock, flags);
dst_unreach: dst_unreach:
icmp_packet.msg_type = DESTINATION_UNREACHABLE; icmp_packet.msg_type = DESTINATION_UNREACHABLE;
bat_socket_add_packet(socket_client, &icmp_packet); bat_socket_add_packet(socket_client, &icmp_packet, packet_len);
out: out:
return len; return len;
} }
...@@ -278,7 +285,8 @@ int bat_socket_setup(struct bat_priv *bat_priv) ...@@ -278,7 +285,8 @@ int bat_socket_setup(struct bat_priv *bat_priv)
} }
static void bat_socket_add_packet(struct socket_client *socket_client, static void bat_socket_add_packet(struct socket_client *socket_client,
struct icmp_packet *icmp_packet) struct icmp_packet_rr *icmp_packet,
size_t icmp_len)
{ {
struct socket_packet *socket_packet; struct socket_packet *socket_packet;
unsigned long flags; unsigned long flags;
...@@ -289,8 +297,8 @@ static void bat_socket_add_packet(struct socket_client *socket_client, ...@@ -289,8 +297,8 @@ static void bat_socket_add_packet(struct socket_client *socket_client,
return; return;
INIT_LIST_HEAD(&socket_packet->list); INIT_LIST_HEAD(&socket_packet->list);
memcpy(&socket_packet->icmp_packet, icmp_packet, memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len);
sizeof(struct icmp_packet)); socket_packet->icmp_len = icmp_len;
spin_lock_irqsave(&socket_client->lock, flags); spin_lock_irqsave(&socket_client->lock, flags);
...@@ -319,10 +327,11 @@ static void bat_socket_add_packet(struct socket_client *socket_client, ...@@ -319,10 +327,11 @@ static void bat_socket_add_packet(struct socket_client *socket_client,
wake_up(&socket_client->queue_wait); wake_up(&socket_client->queue_wait);
} }
void bat_socket_receive_packet(struct icmp_packet *icmp_packet) void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
size_t icmp_len)
{ {
struct socket_client *hash = socket_client_hash[icmp_packet->uid]; struct socket_client *hash = socket_client_hash[icmp_packet->uid];
if (hash) if (hash)
bat_socket_add_packet(hash, icmp_packet); bat_socket_add_packet(hash, icmp_packet, icmp_len);
} }
...@@ -25,4 +25,5 @@ ...@@ -25,4 +25,5 @@
void bat_socket_init(void); void bat_socket_init(void);
int bat_socket_setup(struct bat_priv *bat_priv); int bat_socket_setup(struct bat_priv *bat_priv);
void bat_socket_receive_packet(struct icmp_packet *icmp_packet); void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
size_t icmp_len);
...@@ -69,6 +69,23 @@ struct icmp_packet { ...@@ -69,6 +69,23 @@ struct icmp_packet {
uint8_t uid; uint8_t uid;
} __attribute__((packed)); } __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 { struct unicast_packet {
uint8_t packet_type; uint8_t packet_type;
uint8_t version; /* batman version field */ uint8_t version; /* batman version field */
......
...@@ -765,10 +765,10 @@ int recv_bat_packet(struct sk_buff *skb, ...@@ -765,10 +765,10 @@ int recv_bat_packet(struct sk_buff *skb,
return NET_RX_SUCCESS; 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 orig_node *orig_node;
struct icmp_packet *icmp_packet; struct icmp_packet_rr *icmp_packet;
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
struct sk_buff *skb_old; struct sk_buff *skb_old;
struct batman_if *batman_if; struct batman_if *batman_if;
...@@ -776,12 +776,12 @@ static int recv_my_icmp_packet(struct sk_buff *skb) ...@@ -776,12 +776,12 @@ static int recv_my_icmp_packet(struct sk_buff *skb)
unsigned long flags; unsigned long flags;
uint8_t dstaddr[ETH_ALEN]; uint8_t dstaddr[ETH_ALEN];
icmp_packet = (struct icmp_packet *)skb->data; icmp_packet = (struct icmp_packet_rr *)skb->data;
ethhdr = (struct ethhdr *)skb_mac_header(skb); ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* add data to device queue */ /* add data to device queue */
if (icmp_packet->msg_type != ECHO_REQUEST) { if (icmp_packet->msg_type != ECHO_REQUEST) {
bat_socket_receive_packet(icmp_packet); bat_socket_receive_packet(icmp_packet, icmp_len);
return NET_RX_DROP; return NET_RX_DROP;
} }
...@@ -803,13 +803,12 @@ static int recv_my_icmp_packet(struct sk_buff *skb) ...@@ -803,13 +803,12 @@ static int recv_my_icmp_packet(struct sk_buff *skb)
/* create a copy of the skb, if needed, to modify it. */ /* create a copy of the skb, if needed, to modify it. */
skb_old = NULL; skb_old = NULL;
if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { if (!skb_clone_writable(skb, icmp_len)) {
skb_old = skb; skb_old = skb;
skb = skb_copy(skb, GFP_ATOMIC); skb = skb_copy(skb, GFP_ATOMIC);
if (!skb) if (!skb)
return NET_RX_DROP; return NET_RX_DROP;
icmp_packet = (struct icmp_packet_rr *)skb->data;
icmp_packet = (struct icmp_packet *)skb->data;
ethhdr = (struct ethhdr *)skb_mac_header(skb); ethhdr = (struct ethhdr *)skb_mac_header(skb);
kfree_skb(skb_old); kfree_skb(skb_old);
} }
...@@ -828,7 +827,7 @@ static int recv_my_icmp_packet(struct sk_buff *skb) ...@@ -828,7 +827,7 @@ static int recv_my_icmp_packet(struct sk_buff *skb)
return ret; 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 orig_node *orig_node;
struct icmp_packet *icmp_packet; struct icmp_packet *icmp_packet;
...@@ -867,7 +866,7 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb) ...@@ -867,7 +866,7 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb)
spin_unlock_irqrestore(&orig_hash_lock, flags); spin_unlock_irqrestore(&orig_hash_lock, flags);
/* create a copy of the skb, if needed, to modify it. */ /* 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_old = skb;
skb = skb_copy(skb, GFP_ATOMIC); skb = skb_copy(skb, GFP_ATOMIC);
if (!skb) if (!skb)
...@@ -894,7 +893,7 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb) ...@@ -894,7 +893,7 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb)
int recv_icmp_packet(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 ethhdr *ethhdr;
struct orig_node *orig_node; struct orig_node *orig_node;
struct sk_buff *skb_old; struct sk_buff *skb_old;
...@@ -904,6 +903,12 @@ int recv_icmp_packet(struct sk_buff *skb) ...@@ -904,6 +903,12 @@ int recv_icmp_packet(struct sk_buff *skb)
unsigned long flags; unsigned long flags;
uint8_t dstaddr[ETH_ALEN]; 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 */ /* drop packet if it has not necessary minimum size */
if (skb_headlen(skb) < hdr_size) if (skb_headlen(skb) < hdr_size)
return NET_RX_DROP; return NET_RX_DROP;
...@@ -922,15 +927,23 @@ int recv_icmp_packet(struct sk_buff *skb) ...@@ -922,15 +927,23 @@ int recv_icmp_packet(struct sk_buff *skb)
if (!is_my_mac(ethhdr->h_dest)) if (!is_my_mac(ethhdr->h_dest))
return NET_RX_DROP; 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 */ /* packet for me */
if (is_my_mac(icmp_packet->dst)) if (is_my_mac(icmp_packet->dst))
return recv_my_icmp_packet(skb); return recv_my_icmp_packet(skb, hdr_size);
/* TTL exceeded */ /* TTL exceeded */
if (icmp_packet->ttl < 2) if (icmp_packet->ttl < 2)
return recv_icmp_ttl_exceeded(skb); return recv_icmp_ttl_exceeded(skb, hdr_size);
ret = NET_RX_DROP; ret = NET_RX_DROP;
...@@ -949,12 +962,12 @@ int recv_icmp_packet(struct sk_buff *skb) ...@@ -949,12 +962,12 @@ int recv_icmp_packet(struct sk_buff *skb)
spin_unlock_irqrestore(&orig_hash_lock, flags); spin_unlock_irqrestore(&orig_hash_lock, flags);
/* create a copy of the skb, if needed, to modify it. */ /* 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_old = skb;
skb = skb_copy(skb, GFP_ATOMIC); skb = skb_copy(skb, GFP_ATOMIC);
if (!skb) if (!skb)
return NET_RX_DROP; return NET_RX_DROP;
icmp_packet = (struct icmp_packet *)skb->data; icmp_packet = (struct icmp_packet_rr *)skb->data;
ethhdr = (struct ethhdr *)skb_mac_header(skb); ethhdr = (struct ethhdr *)skb_mac_header(skb);
kfree_skb(skb_old); kfree_skb(skb_old);
} }
......
...@@ -130,7 +130,8 @@ struct socket_client { ...@@ -130,7 +130,8 @@ struct socket_client {
struct socket_packet { struct socket_packet {
struct list_head list; struct list_head list;
struct icmp_packet icmp_packet; size_t icmp_len;
struct icmp_packet_rr icmp_packet;
}; };
struct hna_local_entry { struct hna_local_entry {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册