[v2] alfred: Request MAC resolution for IPv4 address not in ARP cache

Message ID 20181024192128.22531-1-jhaws@sdl.usu.edu (mailing list archive)
State Superseded, archived
Delegated to: Simon Wunderlich
Headers
Series [v2] alfred: Request MAC resolution for IPv4 address not in ARP cache |

Commit Message

Jonathan Haws Oct. 24, 2018, 7:21 p.m. UTC
  When using IPv4, if the remote server is not yet in the ARP cache, the
MAC resolution will fail and data appear to not be shared via alfred.
Add a routine (modified from batctl sources) to request MAC resolution
by simply sending a datagram to the discard port (UDP/9). This adds the
remote MAC to the ARP cache, resulting in successful MAC resolution.

Fixes: c7da798113a2 ("alfred: IPv4 multicast distribution support.")
Signed-off-by: Jonathan Haws <jhaws@sdl.usu.edu>
---
 util.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
  

Comments

Sven Eckelmann Oct. 25, 2018, 9:41 a.m. UTC | #1
On Mittwoch, 24. Oktober 2018 13:21:28 CEST Jonathan Haws wrote:
[...]
>  
> +       while (retries-- && !(arpreq.arp_flags & ATF_COM)) {
> +               ipv4_request_mac_resolve(addr);
> +               usleep(200000);
> +
> +               if (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0)
> +                       return -1;
> +       }
> +
>         if (arpreq.arp_flags & ATF_COM) {
>                 memcpy(mac, arpreq.arp_ha.sa_data, sizeof(*mac));
>         } else {

According to gary [1], this doesn't work because the ioctl fails for him and 
then the function returns immediately (before the while loop).

Please adjust your patch - but please don't use his code - it looks rather
ugly and also doesn't work for multiple retries. You most likely want to
drop the if-ioctl completely and then put everything in your while loop:

	while (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0 ||
	       !(arpreq.arp_flags & ATF_COM)) {
		if (retries-- <= 0)
			break;

		ipv4_request_mac_resolve(addr);
		usleep(200000);
	}

But feel to propose a different (cleaner) approach.

Kind regards,
	Sven

[1] https://lists.open-mesh.org/pipermail/b.a.t.m.a.n/2018-October/018195.html
  
Jonathan Haws Oct. 25, 2018, 1:42 p.m. UTC | #2
Ah, yes - I see the issue now. I'll update that when I get back. And I apologize for the top posting! My phone's email client doesn't do inline too well...



Sent from my Verizon, Samsung Galaxy smartphone


-------- Original message --------
From: Sven Eckelmann <sven@narfation.org>
Date: 10/25/18 3:42 AM (GMT-07:00)
To: b.a.t.m.a.n@lists.open-mesh.org
Cc: Jonathan Haws <jhaws@sdl.usu.edu>, guohuizou2000@sina.com
Subject: Re: [B.A.T.M.A.N.] [PATCH v2] alfred: Request MAC resolution for IPv4 address not in ARP cache

On Mittwoch, 24. Oktober 2018 13:21:28 CEST Jonathan Haws wrote:
[...]
>
> +       while (retries-- && !(arpreq.arp_flags & ATF_COM)) {
> +               ipv4_request_mac_resolve(addr);
> +               usleep(200000);
> +
> +               if (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0)
> +                       return -1;
> +       }
> +
>         if (arpreq.arp_flags & ATF_COM) {
>                 memcpy(mac, arpreq.arp_ha.sa_data, sizeof(*mac));
>         } else {

According to gary [1], this doesn't work because the ioctl fails for him and
then the function returns immediately (before the while loop).

Please adjust your patch - but please don't use his code - it looks rather
ugly and also doesn't work for multiple retries. You most likely want to
drop the if-ioctl completely and then put everything in your while loop:

        while (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0 ||
               !(arpreq.arp_flags & ATF_COM)) {
                if (retries-- <= 0)
                        break;

                ipv4_request_mac_resolve(addr);
                usleep(200000);
        }

But feel to propose a different (cleaner) approach.

Kind regards,
        Sven

[1] https://lists.open-mesh.org/pipermail/b.a.t.m.a.n/2018-October/018195.html
  

Patch

diff --git a/util.c b/util.c
index dd3f00f..3a0c279 100644
--- a/util.c
+++ b/util.c
@@ -30,6 +30,7 @@ 
 #include <sys/ioctl.h>
 #include <sys/time.h>
 #include <time.h>
+#include <unistd.h>
 #include "alfred.h"
 
 int time_diff(struct timespec *tv1, struct timespec *tv2,
@@ -80,11 +81,35 @@  bool is_valid_ether_addr(uint8_t addr[ETH_ALEN])
 	return true;
 }
 
+static void ipv4_request_mac_resolve(const alfred_addr *addr)
+{
+	const struct sockaddr *sockaddr;
+	struct sockaddr_in inet4;
+	size_t sockaddr_len;
+	int sock;
+	char t = 0;
+
+	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (sock < 0)
+		return;
+
+	memset(&inet4, 0, sizeof(inet4));
+	inet4.sin_family = AF_INET;
+	inet4.sin_port = htons(9);
+	inet4.sin_addr.s_addr = addr->ipv4.s_addr;
+	sockaddr = (const struct sockaddr *)&inet4;
+	sockaddr_len = sizeof(inet4);
+
+	sendto(sock, &t, sizeof(t), 0, sockaddr, sockaddr_len);
+	close(sock);
+}
+
 int ipv4_arp_request(struct interface *interface, const alfred_addr *addr,
 		     struct ether_addr *mac)
 {
 	struct arpreq arpreq;
 	struct sockaddr_in *sin;
+	int retries = 1;
 
 	memset(&arpreq, 0, sizeof(arpreq));
 	memset(mac, 0, ETH_ALEN);
@@ -99,6 +124,14 @@  int ipv4_arp_request(struct interface *interface, const alfred_addr *addr,
 	if (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0)
 		return -1;
 
+	while (retries-- && !(arpreq.arp_flags & ATF_COM)) {
+		ipv4_request_mac_resolve(addr);
+		usleep(200000);
+
+		if (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0)
+			return -1;
+	}
+
 	if (arpreq.arp_flags & ATF_COM) {
 		memcpy(mac, arpreq.arp_ha.sa_data, sizeof(*mac));
 	} else {