From patchwork Sat May 26 06:06:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Huth X-Patchwork-Id: 920932 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40tCLd3YNRz9s16 for ; Sat, 26 May 2018 16:06:49 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 40tCLd29pvzDqsx for ; Sat, 26 May 2018 16:06:49 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=redhat.com (client-ip=66.187.233.73; helo=mx1.redhat.com; envelope-from=thuth@redhat.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Received: from mx1.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40tCL51gm8zDqx4 for ; Sat, 26 May 2018 16:06:21 +1000 (AEST) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 318F47A7E1; Sat, 26 May 2018 06:06:19 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-22.ams2.redhat.com [10.36.116.22]) by smtp.corp.redhat.com (Postfix) with ESMTP id 26A3E210C6C0; Sat, 26 May 2018 06:06:17 +0000 (UTC) From: Thomas Huth To: slof@lists.ozlabs.org Date: Sat, 26 May 2018 08:06:06 +0200 Message-Id: <1527314768-4797-7-git-send-email-thuth@redhat.com> In-Reply-To: <1527314768-4797-1-git-send-email-thuth@redhat.com> References: <1527314768-4797-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Sat, 26 May 2018 06:06:19 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Sat, 26 May 2018 06:06:19 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'thuth@redhat.com' RCPT:'' Subject: [SLOF] [PATCH v3 6/8] libnet: Add support for DHCPv4 options 209 and 210 X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Greg Kurz MIME-Version: 1.0 Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" There are two dedicated DHCP options for loading PXELINUX config files, option 209 (config file name) and 210 (path prefix). We should support them, too, in case some users want to configure their boot flow this way. See RFC 5071 and the following URL for more details: https://www.syslinux.org/wiki/index.php?title=PXELINUX#DHCP_options Unlike most other strings in libnet, I've chosen to not use fixed-size arrays for these two strings, but to allocate the memory via malloc here. We always have to make sure not to overflow the stack in Paflof, so adding 2 * 256 byte arrays to struct filename_ip sounded just too dangerous to me. Signed-off-by: Thomas Huth --- lib/libnet/dhcp.c | 33 +++++++++++++++++++++++++++++++ lib/libnet/netload.c | 5 ++++- lib/libnet/ping.c | 14 ++++++++----- lib/libnet/pxelinux.c | 54 ++++++++++++++++++++++++++++++++++++++------------- lib/libnet/tftp.h | 2 ++ 5 files changed, 88 insertions(+), 20 deletions(-) diff --git a/lib/libnet/dhcp.c b/lib/libnet/dhcp.c index d3e5170..85cd7c0 100644 --- a/lib/libnet/dhcp.c +++ b/lib/libnet/dhcp.c @@ -79,6 +79,8 @@ #define DHCP_TFTP_SERVER 66 #define DHCP_BOOTFILE 67 #define DHCP_CLIENT_ARCH 93 +#define DHCP_PXELINUX_CFGFILE 209 /* See RFC 5071 */ +#define DHCP_PXELINUX_PREFIX 210 #define DHCP_ENDOPT 0xFF #define DHCP_PADOPT 0x00 @@ -167,6 +169,8 @@ static uint32_t dhcp_siaddr_ip = 0; static char dhcp_filename[256]; static char dhcp_tftp_name[256]; static uint32_t dhcp_xid; +static char *pxelinux_cfgfile; +static char *pxelinux_prefix; static char * response_buffer; @@ -185,6 +189,8 @@ int32_t dhcpv4(char *ret_buffer, filename_ip_t *fn_ip) strcpy(dhcp_filename, ""); strcpy(dhcp_tftp_name, ""); + pxelinux_cfgfile = pxelinux_prefix = NULL; + response_buffer = ret_buffer; if (dhcp_attempt(fd) == 0) @@ -232,6 +238,10 @@ int32_t dhcpv4(char *ret_buffer, filename_ip_t *fn_ip) fn_ip -> server_ip = dhcp_tftp_ip; strcpy(fn_ip->filename, dhcp_filename); + fn_ip->pl_cfgfile = pxelinux_cfgfile; + fn_ip->pl_prefix = pxelinux_prefix; + pxelinux_cfgfile = pxelinux_prefix = NULL; + return 0; } @@ -456,6 +466,26 @@ static int32_t dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, offset += 4; break; + case DHCP_PXELINUX_CFGFILE: + pxelinux_cfgfile = malloc(opt_field[offset + 1] + 1); + if (pxelinux_cfgfile) { + memcpy(pxelinux_cfgfile, opt_field + offset + 2, + opt_field[offset + 1]); + pxelinux_cfgfile[opt_field[offset + 1]] = 0; + } + offset += 2 + opt_field[offset + 1]; + break; + + case DHCP_PXELINUX_PREFIX: + pxelinux_prefix = malloc(opt_field[offset + 1] + 1); + if (pxelinux_prefix) { + memcpy(pxelinux_prefix, opt_field + offset + 2, + opt_field[offset + 1]); + pxelinux_prefix[opt_field[offset + 1]] = 0; + } + offset += 2 + opt_field[offset + 1]; + break; + case DHCP_PADOPT : offset++; break; @@ -681,6 +711,9 @@ static void dhcp_send_request(int fd) opt.request_list[DHCP_ROUTER] = 1; opt.request_list[DHCP_TFTP_SERVER] = 1; opt.request_list[DHCP_BOOTFILE] = 1; + opt.request_list[DHCP_PXELINUX_CFGFILE] = 1; + opt.request_list[DHCP_PXELINUX_PREFIX] = 1; + opt.request_list[DHCP_CLIENT_ARCH] = USE_DHCPARCH; opt.flag[DHCP_CLIENT_ARCH] = USE_DHCPARCH; diff --git a/lib/libnet/netload.c b/lib/libnet/netload.c index 8a38771..4c7ac37 100644 --- a/lib/libnet/netload.c +++ b/lib/libnet/netload.c @@ -759,7 +759,8 @@ int netload(char *buffer, int len, char *args_fs, int alen) /* Do the TFTP load and print error message if necessary */ rc = 0; filename_len = strlen(fn_ip.filename); - if (filename_len > 0 && fn_ip.filename[filename_len - 1] != '/') { + if (filename_len > 0 && fn_ip.filename[filename_len - 1] != '/' && + !fn_ip.pl_cfgfile) { rc = tftp_load(&fn_ip, buffer, len, obp_tftp_args.tftp_retries); } @@ -779,5 +780,7 @@ int netload(char *buffer, int len, char *args_fs, int alen) } err_out: SLOF_free_mem(pkt_buffer, MAX_PKT_SIZE); + free(fn_ip.pl_cfgfile); + free(fn_ip.pl_prefix); return rc; } diff --git a/lib/libnet/ping.c b/lib/libnet/ping.c index edad5eb..051269f 100644 --- a/lib/libnet/ping.c +++ b/lib/libnet/ping.c @@ -115,6 +115,7 @@ int ping(char *args_fs, int alen) uint8_t own_mac[6]; uint32_t netmask; char args[256]; + int ret = -1; memset(&ping_args, 0, sizeof(struct ping_args)); @@ -164,8 +165,7 @@ int ping(char *args_fs, int alen) if (arp_failed == -1) { printf("\n DHCP: Could not get ip address\n"); - close(fn_ip.fd); - return -1; + goto free_out; } } else { @@ -210,12 +210,16 @@ int ping(char *args_fs, int alen) receive_ether(fd_device); if(pong_ipv4() == 0) { printf("success\n"); - close(fn_ip.fd); - return 0; + ret = 0; + goto free_out; } } printf("failed\n"); +free_out: + free(fn_ip.pl_cfgfile); + free(fn_ip.pl_prefix); close(fn_ip.fd); - return -1; + + return ret; } diff --git a/lib/libnet/pxelinux.c b/lib/libnet/pxelinux.c index d702811..91b3c13 100644 --- a/lib/libnet/pxelinux.c +++ b/lib/libnet/pxelinux.c @@ -57,24 +57,50 @@ static int pxelinux_load_cfg(filename_ip_t *fn_ip, uint8_t *mac, int rc, idx; char *baseptr; - /* Try to get a usable base directory from the DHCP bootfile name */ - baseptr = strrchr(fn_ip->filename, '/'); - if (!baseptr) - baseptr = fn_ip->filename; - else - ++baseptr; - /* Check that we've got enough space to store "pxelinux.cfg/" and - * the UUID (which is the longest file name) there */ - if (baseptr - fn_ip->filename > sizeof(fn_ip->filename) - 50) { - puts("Error: The bootfile string is too long for deriving the " - "pxelinux.cfg file name from it."); - return -1; + /* Did we get a usable base directory via DHCP? */ + if (fn_ip->pl_prefix) { + idx = strlen(fn_ip->pl_prefix); + /* Do we have enough space left to store a UUID file name? */ + if (idx > sizeof(fn_ip->filename) - 36) { + puts("Error: pxelinux prefix is too long!"); + return -1; + } + strcpy(fn_ip->filename, fn_ip->pl_prefix); + baseptr = &fn_ip->filename[idx]; + } else { + /* Try to get a usable base directory from the DHCP bootfile name */ + baseptr = strrchr(fn_ip->filename, '/'); + if (!baseptr) + baseptr = fn_ip->filename; + else + ++baseptr; + /* Check that we've got enough space to store "pxelinux.cfg/" + * and the UUID (which is the longest file name) there */ + if (baseptr - fn_ip->filename > sizeof(fn_ip->filename) - 50) { + puts("Error: The bootfile string is too long for " + "deriving the pxelinux.cfg file name from it."); + return -1; + } + strcpy(baseptr, "pxelinux.cfg/"); + baseptr += strlen(baseptr); } - strcpy(baseptr, "pxelinux.cfg/"); - baseptr += strlen(baseptr); puts("Trying pxelinux.cfg files..."); + /* Try to load config file according to file name in DHCP option 209 */ + if (fn_ip->pl_cfgfile) { + if (strlen(fn_ip->pl_cfgfile) + strlen(fn_ip->filename) + > sizeof(fn_ip->filename)) { + puts("Error: pxelinux.cfg prefix + filename too long!"); + return -1; + } + strcpy(baseptr, fn_ip->pl_cfgfile); + rc = pxelinux_tftp_load(fn_ip, cfgbuf, cfgbufsize - 1, retries); + if (rc > 0) { + return rc; + } + } + /* Look for config file with MAC address in its name */ sprintf(baseptr, "01-%02x-%02x-%02x-%02x-%02x-%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); diff --git a/lib/libnet/tftp.h b/lib/libnet/tftp.h index ca8029e..d2c0919 100644 --- a/lib/libnet/tftp.h +++ b/lib/libnet/tftp.h @@ -29,6 +29,8 @@ struct filename_ip { ip6_addr_t server_ip6; ip6_addr_t dns_ip6; char filename[256]; + char *pl_cfgfile; /* For PXELINUX DHCPv4 option 209. Must be free()ed */ + char *pl_prefix; /* For PXELINUX DHCPv4 option 210. Must be free()ed */ int fd; int ip_version; };