From 9dbe6f4ce824aad7ffcaf8cd36be45ebe29dde25 Mon Sep 17 00:00:00 2001
From: DannyAAM <danny@saru.moe>
Date: Thu, 18 Jan 2018 23:49:28 +0800
Subject: [PATCH] add support for link without MAC (like PPPoE/PPPoA)

Signed-off-by: DannyAAM <danny@saru.moe>
---
 networking/udhcp/d6_dhcpc.c  | 43 +++++++++++++++++++++++++++++++++----------
 networking/udhcp/d6_socket.c | 27 +++++++++++++++++++++++++--
 2 files changed, 58 insertions(+), 12 deletions(-)

diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index f4562b0d4..5d456fe54 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -1131,7 +1131,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
 	int timeout; /* must be signed */
 	unsigned already_waited_sec;
 	unsigned opt;
-	int retval;
+	int retval, retval2;
+	int rand_mac = 0;
 
 	setup_common_bufsiz();
 
@@ -1205,15 +1206,15 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
 			*colon = ':'; /* restore it for NOMMU reexec */
 	}
 
-	if (d6_read_interface(client_config.interface,
+	retval2 = d6_read_interface(client_config.interface,
 			&client_config.ifindex,
 			&client6_data.ll_ip6,
-			client_config.client_mac)
-	) {
+			client_config.client_mac);
+	if (retval2 != 0 && retval2 != 1) { /* no error, or just lack of MAC is fine */
 		return 1;
 	}
 
-	/* Create client ID based on mac, set clientid_mac_ptr */
+	/* Create client ID based on mac (or random, if we don't have it), set clientid_mac_ptr */
 	{
 		struct d6_option *clientid;
 		clientid = xzalloc(2+2+2+2+6);
@@ -1222,7 +1223,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
 		clientid->data[1] = 3; /* DUID-LL */
 		clientid->data[3] = 1; /* ethernet */
 		clientid_mac_ptr = clientid->data + 2+2;
-		memcpy(clientid_mac_ptr, client_config.client_mac, 6);
+		if (retval2 == 1) { /* no MAC */
+			rand_mac = 1;
+			/* generate random MAC later (after srand) */
+		} else {
+			memcpy(clientid_mac_ptr, client_config.client_mac, 6);
+		}
 		client_config.clientid = (void*)clientid;
 	}
 
@@ -1258,6 +1264,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
 	timeout = 0;
 	already_waited_sec = 0;
 
+	/* Generate random MAC here (after srand) */
+	if (rand_mac) {
+		*(uint32_t*)clientid_mac_ptr = rand();
+		*(uint32_t*)(clientid_mac_ptr+2) = rand();
+	}
+
 	/* Main event loop. select() waits on signal pipe and possibly
 	 * on sockfd.
 	 * "continue" statements in code below jump to the top of the loop.
@@ -1308,15 +1320,26 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
 			 * or if the status of the bridge changed).
 			 * Refresh ifindex and client_mac:
 			 */
-			if (d6_read_interface(client_config.interface,
+			retval2 = d6_read_interface(client_config.interface,
 					&client_config.ifindex,
 					&client6_data.ll_ip6,
-					client_config.client_mac)
-			) {
+					client_config.client_mac);
+			if (retval2 != 0 && retval2 != 1) { /* no error, or just lack of MAC is fine */
 				goto ret0; /* iface is gone? */
 			}
 
-			memcpy(clientid_mac_ptr, client_config.client_mac, 6);
+			if (retval2 == 1) { /* no MAC */
+				if (rand_mac) {
+					/* keep original random MAC */
+				} else {
+					rand_mac = 1;
+					*(uint32_t*)clientid_mac_ptr = rand();
+					*(uint32_t*)(clientid_mac_ptr+2) = rand();
+				}
+			} else {
+				rand_mac = 0;
+				memcpy(clientid_mac_ptr, client_config.client_mac, 6);
+			}
 
 			/* We will restart the wait in any case */
 			already_waited_sec = 0;
diff --git a/networking/udhcp/d6_socket.c b/networking/udhcp/d6_socket.c
index d00c217d6..3c9712018 100644
--- a/networking/udhcp/d6_socket.c
+++ b/networking/udhcp/d6_socket.c
@@ -12,8 +12,10 @@
 
 int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_addr *nip6, uint8_t *mac)
 {
-	int retval = 3;
+	int retval = 7;
 	struct ifaddrs *ifap, *ifa;
+	struct ifreq ifr;
+	int fd;
 
 	getifaddrs(&ifap);
 
@@ -31,7 +33,8 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
 			log2("MAC %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
 			log2("ifindex %d", sll->sll_ifindex);
 			*ifindex = sll->sll_ifindex;
-			retval &= (0xf - (1<<0));
+			retval &= (0xf - (1<<0)); /* MAC */
+			retval &= (0xf - (1<<2)); /* ifindex */
 		}
 #if 0
 		if (ifa->ifa_addr->sa_family == AF_INET) {
@@ -59,13 +62,33 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
 	}
 
 	freeifaddrs(ifap);
+
+	/* failed to get ifindex getifaddrs (interface without MAC like ppp), try to get ifindex with ioctl */
+	if (retval & (1<<2)) {
+		memset(ifr, 0, sizeof(ifr));
+		fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
+
+		strncpy_IFNAMSIZ(ifr->ifr_name, interface);
+
+		if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
+			*ifindex = ifr.ifr_ifindex;
+			retval &= (0xf - (1<<2)); /* ifindex */
+		}
+
+		close(fd);
+	}
+
 	if (retval == 0)
 		return retval;
+	if (retval == (1<<0)) /* seems not very critical for just lack of MAC */
+		return retval;
 
 	if (retval & (1<<0))
 		bb_error_msg("can't get %s", "MAC");
 	if (retval & (1<<1))
 		bb_error_msg("can't get %s", "link-local IPv6 address");
+	if (retval & (1<<2))
+		bb_error_msg("can't get %s", "ifindex");
 	return -1;
 }
 
-- 
2.15.1

