[6/7] discover: Support IPv6 addresses

Message ID 20180509053705.3143-7-sam@mendozajonas.com
State Changes Requested
Headers show
Series
  • IPv6 Support
Related show

Commit Message

Samuel Mendoza-Jonas May 9, 2018, 5:37 a.m.
Support handling IPv6 addresses from user events and call the udhcpc6
client if configured to use IPv6 addresses.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 discover/device-handler.c | 51 ++++++++++++++++++++++++++-------------
 discover/network.c        | 40 ++++++++++++++++++++++++------
 discover/user-event.c     |  8 ++++--
 3 files changed, 73 insertions(+), 26 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..c81c5e6 100644
--- a/discover/network.c
+++ b/discover/network.c
@@ -322,10 +322,11 @@  static void configure_interface_dhcp(struct network *network,
 		struct interface *interface)
 {
 	const struct platform *platform;
+	const struct config *config = config_get();
 	char pidfile[256], id[10];
 	struct process *process;
 	int rc;
-	const char *argv[] = {
+	const char *argv_ipv4[] = {
 		pb_system_apps.udhcpc,
 		"-R",
 		"-f",
@@ -337,6 +338,20 @@  static void configure_interface_dhcp(struct network *network,
 		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", id, /* [15,16] - dhcp client identifier */
+		NULL,
+	};
+
 	device_handler_status_dev_info(network->handler, interface->dev,
 			_("Configuring with DHCP"));
 
@@ -344,15 +359,26 @@  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);
-	else
-		argv[11] = NULL;
+	if (platform && platform->dhcp_arch_id != 0xffff) {
+		if (config->network.addr_type == ADDR_IPV6)
+			snprintf(id, sizeof(id), "0x3d:%04x",
+					platform->dhcp_arch_id);
+		else
+			snprintf(id, sizeof(id), "0x5d:%04x",
+					platform->dhcp_arch_id);
+	} else {
+		argv_ipv4[11] = argv_ipv6[15] =  NULL;
+	}
 
 	process = process_create(interface);
 
-	process->path = pb_system_apps.udhcpc;
-	process->argv = argv;
+	if (config->network.addr_type == ADDR_IPV6) {
+		process->path = pb_system_apps.udhcpc6;
+		process->argv = argv_ipv6;
+	} else {
+		process->path = pb_system_apps.udhcpc;
+		process->argv = argv_ipv4;
+	}
 	process->exit_cb = udhcpc_process_exit;
 	process->data = interface;
 
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);