[SLOF] [PATCH v2 09/11] libnet: Add support for DHCPv4 options 209 and 210

Alexey Kardashevskiy aik at ozlabs.ru
Fri May 25 16:47:03 AEST 2018


On 19/5/18 1:45 am, Thomas Huth wrote:
> 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 <thuth at redhat.com>
> ---
>  lib/libnet/dhcp.c     | 33 +++++++++++++++++++++++++++++++++
>  lib/libnet/netload.c  |  7 ++++++-
>  lib/libnet/ping.c     | 14 +++++++++-----
>  lib/libnet/pxelinux.c | 24 +++++++++++++++++++-----
>  lib/libnet/tftp.h     |  2 ++
>  5 files changed, 69 insertions(+), 11 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;


Why are not these in dhcp_options_t?



>  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 2a2a7c5..5af4e26 100644
> --- a/lib/libnet/netload.c
> +++ b/lib/libnet/netload.c
> @@ -742,7 +742,10 @@ int netload(char *buffer, int len, char *args_fs, int alen)
>  	}
>  
>  	/* Do the TFTP load and print error message if necessary */
> -	rc = tftp_load(&fn_ip, buffer, len);
> +	rc = 0;
> +	if (!fn_ip.pl_cfgfile && strlen(fn_ip.filename) > 0) {
> +		rc = tftp_load(&fn_ip, buffer, len);
> +	}
>  
>  	if (rc <= 0 && !obp_tftp_args.filename[0]) {
>  		rc = net_pxelinux_cfg_load(&fn_ip, buffer, len, own_mac);
> @@ -758,5 +761,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 0c0b42e..6c03029 100644
> --- a/lib/libnet/pxelinux.c
> +++ b/lib/libnet/pxelinux.c
> @@ -59,16 +59,30 @@ static int pxelinux_load_cfg(filename_ip_t *fn_ip, uint8_t *mac, uint8_t *uuid,
>  	cfgbuf[cfgbufsize - 1] = 0;  /* Make sure it is NUL-terminated */
>  
>  	/* Did we get a usable base directory via DHCP? */
> -	slash = strrchr(fn_ip->filename, '/');
> -	if (slash && slash - fn_ip->filename < sizeof(basedir) - 1) {
> -		slash[1] = 0;
> -		strcpy(basedir, fn_ip->filename);
> +	if (fn_ip->pl_prefix && strlen(fn_ip->pl_prefix) < sizeof(basedir)) {
> +		strcpy(basedir, fn_ip->pl_prefix);
>  	} else {
> -		strcpy(basedir, "pxelinux.cfg/");
> +		slash = strrchr(fn_ip->filename, '/');
> +		if (slash && slash - fn_ip->filename < sizeof(basedir) - 1) {
> +			slash[1] = 0;
> +			strcpy(basedir, fn_ip->filename);
> +		} else {
> +			strcpy(basedir, "pxelinux.cfg/");
> +		}
>  	}
>  
>  	printf("Trying pxelinux.cfg files...\n");
>  
> +	/* Try to load config file according to file name in DHCP option 209 */
> +	if (fn_ip->pl_cfgfile && strlen(fn_ip->pl_cfgfile)
> +	                         + strlen(basedir) < sizeof(fn_ip->filename)) {
> +		sprintf(fn_ip->filename, "%s%s", basedir, fn_ip->pl_cfgfile);
> +		rc = pxelinux_tftp_load(fn_ip, cfgbuf, cfgbufsize - 1);
> +		if (rc > 0) {
> +			return rc;
> +		}
> +	}
> +
>  	/* Try to load config file with name based on the VM UUID */
>  	if (uuid) {
>  		sprintf(fn_ip->filename, "%s%02x%02x%02x%02x-%02x%02x-"
> diff --git a/lib/libnet/tftp.h b/lib/libnet/tftp.h
> index da743d3..775700a 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;
>  	int tftp_retries;
> 


-- 
Alexey


More information about the SLOF mailing list