In order to enable an higher verbosity level of the DAT debug messages, the unicast_4addr_packet is now used to carry ARP packets generated by the DAT internal mechanism. This packet type will enable batman-adv to recognise each DAT related message and to print its source (this will help to track possibly bogus ARP entries)
Signed-off-by: Antonio Quartulli ordex@autistici.org --- distributed-arp-table.c | 129 +++++++++++++++++++++++++++++++--------------- distributed-arp-table.h | 16 +++--- soft-interface.c | 15 +++-- 3 files changed, 105 insertions(+), 55 deletions(-)
diff --git a/distributed-arp-table.c b/distributed-arp-table.c index 48e97e0..239b5c4 100644 --- a/distributed-arp-table.c +++ b/distributed-arp-table.c @@ -31,6 +31,7 @@ #include "originator.h" #include "send.h" #include "soft-interface.h" +#include "translation-table.h" #include "types.h" #include "translation-table.h" #include "unicast.h" @@ -38,10 +39,44 @@ #ifdef CONFIG_BATMAN_ADV_DEBUG
static inline void bat_dbg_arp(struct bat_priv *bat_priv, - struct sk_buff *skb, uint16_t type) { + struct sk_buff *skb, uint16_t type, + int hdr_size) { + struct unicast_4addr_packet *unicast_4addr_packet; + bat_dbg(DBG_ARP, bat_priv, "ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]\n", - ARP_HW_SRC(skb), &ARP_IP_SRC(skb), ARP_HW_DST(skb), - &ARP_IP_DST(skb)); + ARP_HW_SRC(skb, hdr_size), &ARP_IP_SRC(skb, hdr_size), + ARP_HW_DST(skb, hdr_size), &ARP_IP_DST(skb, hdr_size)); + + if (hdr_size == 0) + return; + + /* if the AP packet is encapsulated in a batman packet, let's print some + * debug messages */ + unicast_4addr_packet = (struct unicast_4addr_packet *)skb->data; + + switch (unicast_4addr_packet->u.header.packet_type) { + case BAT_UNICAST: + bat_dbg(DBG_ARP, bat_priv, "encapsulated within a UNICAST " + "packet\n"); + break; + case BAT_UNICAST_4ADDR: + bat_dbg(DBG_ARP, bat_priv, "encapsulated within a " + "UNICAST_4ADDR packet (src: %pM)\n", + unicast_4addr_packet->src); + if (unicast_4addr_packet->subtype != BAT_P_DHT_PUT || + unicast_4addr_packet->subtype != BAT_P_DHT_GET) + bat_dbg(DBG_ARP, bat_priv, "It's a DAT message\n"); + break; + case BAT_BCAST: + bat_dbg(DBG_ARP, bat_priv, "encapsulated within a BCAST packet " + "(src: %pM)\n", + ((struct bcast_packet *)unicast_4addr_packet)->orig); + break; + default: + bat_dbg(DBG_ARP, bat_priv, "encapsulated within an unknown " + "packet type (0x%x)\n", + unicast_4addr_packet->u.header.packet_type); + } }
#else @@ -184,7 +219,8 @@ static bool dht_send_data(struct bat_priv *bat_priv, struct sk_buff *skb, goto free_orig;
tmp_skb = pskb_copy(skb, GFP_ATOMIC); - if (prepare_unicast_packet(tmp_skb, cand[i].orig_node)) + if (prepare_unicast_4addr_packet(bat_priv, tmp_skb, + cand[i].orig_node)) send_skb_packet(tmp_skb, neigh_node->if_incoming, neigh_node->addr); else @@ -228,24 +264,28 @@ out:
/* Returns arphdr->ar_op if the skb contains a valid ARP packet, otherwise * returns 0 */ -static uint16_t arp_get_type(struct bat_priv *bat_priv, struct sk_buff *skb) +static uint16_t arp_get_type(struct bat_priv *bat_priv, struct sk_buff *skb, + int hdr_size) { struct arphdr *arphdr; struct ethhdr *ethhdr; uint16_t type = 0;
- if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) + /* pull the ethernet header */ + if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN))) goto out;
- ethhdr = (struct ethhdr *)skb_mac_header(skb); + ethhdr = (struct ethhdr *)(skb->data + hdr_size);
if (ethhdr->h_proto != htons(ETH_P_ARP)) goto out;
- if (unlikely(!pskb_may_pull(skb, ETH_HLEN + arp_hdr_len(skb->dev)))) + /* pull the ARP payload */ + if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN + + arp_hdr_len(skb->dev)))) goto out;
- arphdr = (struct arphdr *)(skb->data + sizeof(struct ethhdr)); + arphdr = (struct arphdr *)(skb->data + hdr_size + ETH_HLEN);
/* Check whether the ARP packet carries a valid * IP information */ @@ -263,10 +303,10 @@ static uint16_t arp_get_type(struct bat_priv *bat_priv, struct sk_buff *skb)
/* Check for bad reply/request. If the ARP message is not sane, DAT * will simply ignore it */ - if (ipv4_is_loopback(ARP_IP_SRC(skb)) || - ipv4_is_multicast(ARP_IP_SRC(skb)) || - ipv4_is_loopback(ARP_IP_DST(skb)) || - ipv4_is_multicast(ARP_IP_DST(skb))) + if (ipv4_is_loopback(ARP_IP_SRC(skb, hdr_size)) || + ipv4_is_multicast(ARP_IP_SRC(skb, hdr_size)) || + ipv4_is_loopback(ARP_IP_DST(skb, hdr_size)) || + ipv4_is_multicast(ARP_IP_DST(skb, hdr_size))) goto out;
type = ntohs(arphdr->ar_op); @@ -288,18 +328,18 @@ bool dat_snoop_outgoing_arp_request(struct bat_priv *bat_priv, struct hard_iface *primary_if = NULL; struct sk_buff *skb_new;
- type = arp_get_type(bat_priv, skb); + type = arp_get_type(bat_priv, skb, 0); /* If we get an ARP_REQUEST we have to send the unicast message to the * selected DHT candidates */ if (type != ARPOP_REQUEST) goto out;
bat_dbg(DBG_ARP, bat_priv, "Parsing outgoing ARP REQUEST\n"); - bat_dbg_arp(bat_priv, skb, type); + bat_dbg_arp(bat_priv, skb, type, 0);
- ip_src = ARP_IP_SRC(skb); - hw_src = ARP_HW_SRC(skb); - ip_dst = ARP_IP_DST(skb); + ip_src = ARP_IP_SRC(skb, 0); + hw_src = ARP_HW_SRC(skb, 0); + ip_dst = ARP_IP_DST(skb, 0);
primary_if = primary_if_get_selected(bat_priv); if (!primary_if) @@ -341,7 +381,7 @@ out: * into the local table. If found, an ARP reply is sent immediately, otherwise * the caller has to deliver the ARP request to the upper layer */ bool dat_snoop_incoming_arp_request(struct bat_priv *bat_priv, - struct sk_buff *skb) + struct sk_buff *skb, int hdr_size) { uint16_t type; uint32_t ip_src, ip_dst; @@ -351,16 +391,16 @@ bool dat_snoop_incoming_arp_request(struct bat_priv *bat_priv, struct neighbour *n = NULL; bool ret = false;
- type = arp_get_type(bat_priv, skb); + type = arp_get_type(bat_priv, skb, hdr_size); if (type != ARPOP_REQUEST) goto out;
- hw_src = ARP_HW_SRC(skb); - ip_src = ARP_IP_SRC(skb); - ip_dst = ARP_IP_DST(skb); + hw_src = ARP_HW_SRC(skb, hdr_size); + ip_src = ARP_IP_SRC(skb, hdr_size); + ip_dst = ARP_IP_DST(skb, hdr_size);
bat_dbg(DBG_ARP, bat_priv, "Parsing incoming ARP REQUEST\n"); - bat_dbg_arp(bat_priv, skb, type); + bat_dbg_arp(bat_priv, skb, type, hdr_size);
primary_if = primary_if_get_selected(bat_priv); if (!primary_if) @@ -380,7 +420,7 @@ bool dat_snoop_incoming_arp_request(struct bat_priv *bat_priv, if (!skb_new) goto out;
- unicast_send_skb(skb_new, bat_priv); + unicast_4addr_send_skb(skb_new, bat_priv);
ret = true; out: @@ -404,17 +444,17 @@ bool dat_snoop_outgoing_arp_reply(struct bat_priv *bat_priv, uint8_t *hw_src, *hw_dst; bool ret = false;
- type = arp_get_type(bat_priv, skb); + type = arp_get_type(bat_priv, skb, 0); if (type != ARPOP_REPLY) goto out;
bat_dbg(DBG_ARP, bat_priv, "Parsing outgoing ARP REPLY\n"); - bat_dbg_arp(bat_priv, skb, type); + bat_dbg_arp(bat_priv, skb, type, 0);
- hw_src = ARP_HW_SRC(skb); - ip_src = ARP_IP_SRC(skb); - hw_dst = ARP_HW_DST(skb); - ip_dst = ARP_IP_DST(skb); + hw_src = ARP_HW_SRC(skb, 0); + ip_src = ARP_IP_SRC(skb, 0); + hw_dst = ARP_HW_DST(skb, 0); + ip_dst = ARP_IP_DST(skb, 0);
arp_neigh_update(bat_priv, ip_src, hw_src); arp_neigh_update(bat_priv, ip_dst, hw_dst); @@ -431,24 +471,24 @@ out: /* This function has to be invoked on an ARP reply coming into the soft * interface from the mesh network. The local table has to be updated */ bool dat_snoop_incoming_arp_reply(struct bat_priv *bat_priv, - struct sk_buff *skb) + struct sk_buff *skb, int hdr_size) { uint16_t type; uint32_t ip_src, ip_dst; uint8_t *hw_src, *hw_dst; bool ret = false;
- type = arp_get_type(bat_priv, skb); + type = arp_get_type(bat_priv, skb, hdr_size); if (type != ARPOP_REPLY) goto out;
bat_dbg(DBG_ARP, bat_priv, "Parsing incoming ARP REPLY\n"); - bat_dbg_arp(bat_priv, skb, type); + bat_dbg_arp(bat_priv, skb, type, hdr_size);
- hw_src = ARP_HW_SRC(skb); - ip_src = ARP_IP_SRC(skb); - hw_dst = ARP_HW_DST(skb); - ip_dst = ARP_IP_DST(skb); + hw_src = ARP_HW_SRC(skb, hdr_size); + ip_src = ARP_IP_SRC(skb, hdr_size); + hw_dst = ARP_HW_DST(skb, hdr_size); + ip_dst = ARP_IP_DST(skb, hdr_size);
/* Update our internal cache with both the IP addresses we fetched from * the ARP reply */ @@ -471,20 +511,25 @@ bool arp_drop_broadcast_packet(struct bat_priv *bat_priv, /* If this packet is an ARP_REQUEST and we already have the information * that it is going to ask, we can drop the packet */ if (!forw_packet->num_packets && - (arp_get_type(bat_priv, forw_packet->skb) == + (arp_get_type(bat_priv, forw_packet->skb, + sizeof(struct bcast_packet)) == ARPOP_REQUEST)) { - n = neigh_lookup(&arp_tbl, &ARP_IP_DST(forw_packet->skb), + n = neigh_lookup(&arp_tbl, + &ARP_IP_DST(forw_packet->skb, + sizeof(struct bcast_packet)), forw_packet->if_incoming->soft_iface); /* check if we already know this neigh */ if (n && (n->nud_state & NUD_CONNECTED)) { bat_dbg(DBG_ARP, bat_priv, "ARP Request for %pI4: " "fallback prevented\n", - &ARP_IP_DST(forw_packet->skb)); + &ARP_IP_DST(forw_packet->skb, + sizeof(struct bcast_packet))); return true; }
bat_dbg(DBG_ARP, bat_priv, "ARP Request for %pI4: fallback\n", - &ARP_IP_DST(forw_packet->skb)); + &ARP_IP_DST(forw_packet->skb, + sizeof(struct bcast_packet))); } return false; } diff --git a/distributed-arp-table.h b/distributed-arp-table.h index 98fc2e1..a81b021 100644 --- a/distributed-arp-table.h +++ b/distributed-arp-table.h @@ -41,20 +41,22 @@ struct forw_packet; #define dat_addr_t uint16_t #define DAT_ADDR_MAX biggest_unsigned_int(dat_addr_t)
-#define ARP_HW_SRC(skb) ((uint8_t *)(skb->data) + sizeof(struct ethhdr) + \ - sizeof(struct arphdr)) -#define ARP_IP_SRC(skb) (*(uint32_t *)(ARP_HW_SRC(skb) + ETH_ALEN)) -#define ARP_HW_DST(skb) (ARP_HW_SRC(skb) + ETH_ALEN + 4) -#define ARP_IP_DST(skb) (*(uint32_t *)(ARP_HW_SRC(skb) + ETH_ALEN * 2 + 4)) +#define ARP_HW_SRC(skb, hdr_size) ((uint8_t *)(skb->data + hdr_size) + \ + sizeof(struct ethhdr) + sizeof(struct arphdr)) +#define ARP_IP_SRC(skb, hdr_size) (*(uint32_t *)(ARP_HW_SRC(skb, hdr_size) + \ + ETH_ALEN)) +#define ARP_HW_DST(skb, hdr_size) (ARP_HW_SRC(skb, hdr_size) + ETH_ALEN + 4) +#define ARP_IP_DST(skb, hdr_size) (*(uint32_t *)(ARP_HW_SRC(skb, hdr_size) + \ + ETH_ALEN * 2 + 4))
bool dat_snoop_outgoing_arp_request(struct bat_priv *bat_priv, struct sk_buff *skb); bool dat_snoop_incoming_arp_request(struct bat_priv *bat_priv, - struct sk_buff *skb); + struct sk_buff *skb, int hdr_size); bool dat_snoop_outgoing_arp_reply(struct bat_priv *bat_priv, struct sk_buff *skb); bool dat_snoop_incoming_arp_reply(struct bat_priv *bat_priv, - struct sk_buff *skb); + struct sk_buff *skb, int hdr_size); bool arp_drop_broadcast_packet(struct bat_priv *bat_priv, struct forw_packet *forw_packet); void arp_change_timeout(struct net_device *soft_iface, const char *name); diff --git a/soft-interface.c b/soft-interface.c index 4426e36..b21171b 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -258,6 +258,7 @@ void interface_rx(struct net_device *soft_iface, int hdr_size) { struct bat_priv *bat_priv = netdev_priv(soft_iface); + struct unicast_4addr_packet *unicast_4addr_packet; struct ethhdr *ethhdr; struct vlan_ethhdr *vhdr; short vid = -1; @@ -266,6 +267,14 @@ void interface_rx(struct net_device *soft_iface, if (!pskb_may_pull(skb, hdr_size)) goto dropped;
+ unicast_4addr_packet = (struct unicast_4addr_packet *)skb->data; + + if (dat_snoop_incoming_arp_request(bat_priv, skb, hdr_size)) + goto out; + + if (dat_snoop_incoming_arp_reply(bat_priv, skb, hdr_size)) + goto out; + skb_pull_rcsum(skb, hdr_size); skb_reset_mac_header(skb);
@@ -284,12 +293,6 @@ void interface_rx(struct net_device *soft_iface, goto dropped; }
- if (dat_snoop_incoming_arp_request(bat_priv, skb)) - goto out; - - if (dat_snoop_incoming_arp_reply(bat_priv, skb)) - goto out; - /* skb->dev & skb->pkt_type are set here */ if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) goto dropped;