From: Samuel Mendoza-Jonas Date: Wed, 9 May 2018 01:18:57 +0000 (+1000) Subject: discover: Support IPv6 addresses X-Git-Tag: v1.9.0~56 X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=commitdiff_plain;h=f5fb1751ec92110669a039bb0de209bffe74538a;hp=02a66447edbc43e6baf4c1a1221a251b5f2536b8 discover: Support IPv6 addresses Support handling IPv6 addresses from user events and call the udhcpc6 client in addition to the udhcpc client. Signed-off-by: Samuel Mendoza-Jonas --- diff --git a/discover/device-handler.c b/discover/device-handler.c index 72dda75..69bc050 100644 --- a/discover/device-handler.c +++ b/discover/device-handler.c @@ -1374,10 +1374,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(); @@ -1475,32 +1480,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 5a3b0b4..2057525 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", @@ -334,7 +350,21 @@ static void configure_interface_dhcp(struct network *network, "-O", "reboottime", "-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, }; @@ -345,24 +375,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 7f63d43..ee282bb 100644 --- a/discover/user-event.c +++ b/discover/user-event.c @@ -390,7 +390,9 @@ static int user_event_dhcp(struct user_event *uev, struct event *event) uint8_t hwaddr[MAC_ADDR_SIZE]; - if (!event_get_param(event, "mac") || !event_get_param(event, "ip")) + if (!event_get_param(event, "mac")) + return -1; + if (!event_get_param(event, "ip") && !event_get_param(event, "ipv6")) return -1; sscanf(event_get_param(event, "mac"), @@ -398,8 +400,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);