[v2,5/9] discover: Support IPv6 addresses

Message ID 20180524044742.25889-6-sam@mendozajonas.com
State Accepted
Headers show
Series
  • IPv6 Support
Related show

Commit Message

Samuel Mendoza-Jonas May 24, 2018, 4:47 a.m.
Support handling IPv6 addresses from user events and call the udhcpc6
client in addition to the udhcpc client.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 discover/device-handler.c | 51 +++++++++++++++--------
 discover/network.c        | 86 ++++++++++++++++++++++++++++++---------
 discover/user-event.c     |  8 +++-
 3 files changed, 106 insertions(+), 39 deletions(-)

Patch

diff --git a/discover/device-handler.c b/discover/device-handler.c
index 569e652..4164409 100644
--- a/discover/device-handler.c
+++ b/discover/device-handler.c
@@ -1167,10 +1167,15 @@  int device_handler_dhcp(struct device_handler *handler,
 		struct discover_device *dev, struct event *event)
 {
 	struct discover_context *ctx;
+	const char *ip;
+
+	if (event_get_param(event, "ipv6"))
+		ip = event_get_param(event, "ipv6");
+	else
+		ip = event_get_param(event, "ip");
 
 	device_handler_status_dev_info(handler, dev,
-			_("Processing DHCP lease response (ip: %s)"),
-			event_get_param(event, "ip"));
+			_("Processing DHCP lease response (ip: %s)"), ip);
 
 	pending_network_jobs_start();
 
@@ -1265,32 +1270,44 @@  void device_handler_update_config(struct device_handler *handler,
 static char *device_from_addr(void *ctx, struct pb_url *url)
 {
 	char *ipaddr, *buf, *tok, *dev = NULL;
+	bool ipv6_route;
 	const char *delim = " ";
-	struct sockaddr_in *ip;
-	struct sockaddr_in si;
+	struct sockaddr_in *ipv4;
+	struct sockaddr_in6 *ipv6;
 	struct addrinfo *res;
 	struct process *p;
 	int rc;
 
-	/* Note: IPv4 only */
-	rc = inet_pton(AF_INET, url->host, &(si.sin_addr));
-	if (rc > 0) {
-		ipaddr = url->host;
-	} else {
-		/* need to turn hostname into a valid IP */
-		rc = getaddrinfo(url->host, NULL, NULL, &res);
-		if (rc) {
-			pb_debug("%s: Invalid URL\n",__func__);
-			return NULL;
-		}
+	/* Confirm url->host is either a valid hostname, or a
+	 * valid IPv4 or IPv6 address */
+	rc = getaddrinfo(url->host, NULL, NULL, &res);
+	if (rc) {
+		pb_debug("%s: Invalid URL\n",__func__);
+		return NULL;
+	}
+
+	switch (res->ai_family) {
+	case AF_INET:	/* ipv4 */
 		ipaddr = talloc_array(ctx,char,INET_ADDRSTRLEN);
-		ip = (struct sockaddr_in *) res->ai_addr;
-		inet_ntop(AF_INET, &(ip->sin_addr), ipaddr, INET_ADDRSTRLEN);
+		ipv4 = (struct sockaddr_in *) res->ai_addr;
+		inet_ntop(AF_INET, &(ipv4->sin_addr), ipaddr, INET_ADDRSTRLEN);
+		ipv6_route = false;
+		break;
+	case AF_INET6:	/* ipv6 */
+		ipaddr = talloc_array(ctx,char,INET6_ADDRSTRLEN);
+		ipv6 = (struct sockaddr_in6 *) res->ai_addr;
+		inet_ntop(AF_INET6, &(ipv6->sin6_addr), ipaddr, INET6_ADDRSTRLEN);
+		ipv6_route = true;
+		break;
+	default:	/* error */
 		freeaddrinfo(res);
+		return NULL;
 	}
+	freeaddrinfo(res);
 
 	const char *argv[] = {
 		pb_system_apps.ip,
+		ipv6_route ? "-6" : "-4",
 		"route", "show", "to", "match",
 		ipaddr,
 		NULL
diff --git a/discover/network.c b/discover/network.c
index e2cae91..7a9ae21 100644
--- a/discover/network.c
+++ b/discover/network.c
@@ -53,6 +53,7 @@  struct interface {
 
 	struct list_item list;
 	struct process *udhcpc_process;
+	struct process *udhcpc6_process;
 	struct discover_device *dev;
 	bool ready;
 };
@@ -279,6 +280,13 @@  static int interface_change(struct interface *interface, bool up)
 		process_stop_async(interface->udhcpc_process);
 		process_release(interface->udhcpc_process);
 	}
+	if (!up && interface->udhcpc6_process) {
+		/* we don't care about the callback from here */
+		interface->udhcpc6_process->exit_cb = NULL;
+		interface->udhcpc6_process->data = NULL;
+		process_stop_async(interface->udhcpc6_process);
+		process_release(interface->udhcpc6_process);
+	}
 
 	if (!up) {
 		rc = process_run_simple(interface, pb_system_apps.ip,
@@ -312,9 +320,17 @@  static int interface_down(struct interface *interface)
 static void udhcpc_process_exit(struct process *process)
 {
 	struct interface *interface = process->data;
-	pb_debug("udhcp client [pid %d] for interface %s exited, rc %d\n",
-			process->pid, interface->name, process->exit_status);
-	interface->udhcpc_process = NULL;
+
+	if (process == interface->udhcpc_process) {
+		pb_debug("udhcpc client [pid %d] for interface %s exited, rc %d\n",
+				process->pid, interface->name, process->exit_status);
+		interface->udhcpc_process = NULL;
+	} else {
+		pb_debug("udhcpc6 client [pid %d] for interface %s exited, rc %d\n",
+				process->pid, interface->name, process->exit_status);
+		interface->udhcpc6_process = NULL;
+	}
+
 	process_release(process);
 }
 
@@ -322,10 +338,10 @@  static void configure_interface_dhcp(struct network *network,
 		struct interface *interface)
 {
 	const struct platform *platform;
-	char pidfile[256], id[10];
-	struct process *process;
+	char pidfile[256], idv4[10], idv6[10];
+	struct process *p_v4, *p_v6;
 	int rc;
-	const char *argv[] = {
+	const char *argv_ipv4[] = {
 		pb_system_apps.udhcpc,
 		"-R",
 		"-f",
@@ -333,7 +349,21 @@  static void configure_interface_dhcp(struct network *network,
 		"-O", "pxepathprefix",
 		"-p", pidfile,
 		"-i", interface->name,
-		"-x", id, /* [11,12] - dhcp client identifier */
+		"-x", idv4, /* [11,12] - dhcp client identifier */
+		NULL,
+	};
+
+	const char *argv_ipv6[] = {
+		pb_system_apps.udhcpc6,
+		"-R",
+		"-f",
+		"-O", "bootfile_url",
+		"-O", "bootfile_param",
+		"-O", "pxeconffile",
+		"-O", "pxepathprefix",
+		"-p", pidfile,
+		"-i", interface->name,
+		"-x", idv6, /* [15,16] - dhcp client identifier */
 		NULL,
 	};
 
@@ -344,24 +374,40 @@  static void configure_interface_dhcp(struct network *network,
 			PIDFILE_BASE, interface->name);
 
 	platform = platform_get();
-	if (platform && platform->dhcp_arch_id != 0xffff)
-		snprintf(id, sizeof(id), "0x5d:%04x", platform->dhcp_arch_id);
+	if (platform && platform->dhcp_arch_id != 0xffff) {
+		snprintf(idv6, sizeof(idv6), "0x3d:%04x",
+				platform->dhcp_arch_id);
+		snprintf(idv4, sizeof(idv4), "0x5d:%04x",
+				platform->dhcp_arch_id);
+	} else {
+		argv_ipv4[11] = argv_ipv6[15] =  NULL;
+	}
+
+	p_v4 = process_create(interface);
+	p_v4->path = pb_system_apps.udhcpc;
+	p_v4->argv = argv_ipv4;
+	p_v4->exit_cb = udhcpc_process_exit;
+	p_v4->data = interface;
+
+	pb_log("Running DHCPv4 client\n");
+	rc = process_run_async(p_v4);
+	if (rc)
+		process_release(p_v4);
 	else
-		argv[11] = NULL;
-
-	process = process_create(interface);
-
-	process->path = pb_system_apps.udhcpc;
-	process->argv = argv;
-	process->exit_cb = udhcpc_process_exit;
-	process->data = interface;
+		interface->udhcpc_process = p_v4;
 
-	rc = process_run_async(process);
+	pb_log("Running DHCPv6 client\n");
+	p_v6 = process_create(interface);
+	p_v6->path = pb_system_apps.udhcpc6;
+	p_v6->argv = argv_ipv6;
+	p_v6->exit_cb = udhcpc_process_exit;
+	p_v6->data = interface;
 
+	rc = process_run_async(p_v6);
 	if (rc)
-		process_release(process);
+		process_release(p_v6);
 	else
-		interface->udhcpc_process = process;
+		interface->udhcpc6_process = p_v6;
 
 	return;
 }
diff --git a/discover/user-event.c b/discover/user-event.c
index 77d28c1..59e0717 100644
--- a/discover/user-event.c
+++ b/discover/user-event.c
@@ -395,8 +395,12 @@  static int user_event_dhcp(struct user_event *uev, struct event *event)
 	       hwaddr, hwaddr + 1, hwaddr + 2,
 	       hwaddr + 3, hwaddr + 4, hwaddr + 5);
 
-	system_info_set_interface_address(sizeof(hwaddr), hwaddr,
-					  event_get_param(event, "ip"));
+	if (event_get_param(event, "ipv6"))
+		system_info_set_interface_address(sizeof(hwaddr), hwaddr,
+						  event_get_param(event, "ipv6"));
+	else
+		system_info_set_interface_address(sizeof(hwaddr), hwaddr,
+						  event_get_param(event, "ip"));
 
 	dev = discover_device_create(handler, event_get_param(event, "mac"),
 					event->device);