|  | @@ -25,6 +25,7 @@
 | 
		
	
		
			
			| 25 | 25 |  #include <errno.h>
 | 
		
	
		
			
			| 26 | 26 |  #include <assert.h>
 | 
		
	
		
			
			| 27 | 27 |  #include <gpxe/in.h>
 | 
		
	
		
			
			|  | 28 | +#include <gpxe/vsprintf.h>
 | 
		
	
		
			
			| 28 | 29 |  #include <gpxe/settings.h>
 | 
		
	
		
			
			| 29 | 30 |  
 | 
		
	
		
			
			| 30 | 31 |  /** @file
 | 
		
	
	
		
			
			|  | @@ -45,6 +46,8 @@ static struct config_setting config_settings[0]
 | 
		
	
		
			
			| 45 | 46 |  static struct config_setting config_settings_end[0]
 | 
		
	
		
			
			| 46 | 47 |  	__table_end ( struct config_setting, config_settings );
 | 
		
	
		
			
			| 47 | 48 |  
 | 
		
	
		
			
			|  | 49 | +struct config_setting_type config_setting_type_hex __config_setting_type;
 | 
		
	
		
			
			|  | 50 | +
 | 
		
	
		
			
			| 48 | 51 |  /**
 | 
		
	
		
			
			| 49 | 52 |   * Find configuration setting type
 | 
		
	
		
			
			| 50 | 53 |   *
 | 
		
	
	
		
			
			|  | @@ -108,9 +111,16 @@ find_or_build_config_setting ( const char *name,
 | 
		
	
		
			
			| 108 | 111 |  	memset ( setting, 0, sizeof ( *setting ) );
 | 
		
	
		
			
			| 109 | 112 |  	setting->name = name;
 | 
		
	
		
			
			| 110 | 113 |  	setting->tag = strtoul ( name, &separator, 10 );
 | 
		
	
		
			
			| 111 |  | -	if ( *separator != '.' )
 | 
		
	
		
			
			| 112 |  | -		return NULL;
 | 
		
	
		
			
			| 113 |  | -	setting->type = find_config_setting_type ( separator + 1 );
 | 
		
	
		
			
			|  | 114 | +	switch ( *separator ) {
 | 
		
	
		
			
			|  | 115 | +	case '.' :
 | 
		
	
		
			
			|  | 116 | +		setting->type = find_config_setting_type ( separator + 1 );
 | 
		
	
		
			
			|  | 117 | +		break;
 | 
		
	
		
			
			|  | 118 | +	case '\0' :
 | 
		
	
		
			
			|  | 119 | +		setting->type = &config_setting_type_hex;
 | 
		
	
		
			
			|  | 120 | +		break;
 | 
		
	
		
			
			|  | 121 | +	default :
 | 
		
	
		
			
			|  | 122 | +		break;
 | 
		
	
		
			
			|  | 123 | +	}
 | 
		
	
		
			
			| 114 | 124 |  	if ( ! setting->type )
 | 
		
	
		
			
			| 115 | 125 |  		return NULL;
 | 
		
	
		
			
			| 116 | 126 |  	return setting;
 | 
		
	
	
		
			
			|  | @@ -340,11 +350,41 @@ static int set_int ( struct config_context *context,
 | 
		
	
		
			
			| 340 | 350 |   * @ret rc		Return status code
 | 
		
	
		
			
			| 341 | 351 |   */ 
 | 
		
	
		
			
			| 342 | 352 |  static int set_int8 ( struct config_context *context,
 | 
		
	
		
			
			| 343 |  | -			   struct config_setting *setting,
 | 
		
	
		
			
			| 344 |  | -			   const char *value ) {
 | 
		
	
		
			
			|  | 353 | +		      struct config_setting *setting,
 | 
		
	
		
			
			|  | 354 | +		      const char *value ) {
 | 
		
	
		
			
			| 345 | 355 |  	return set_int ( context, setting, value, 1 );
 | 
		
	
		
			
			| 346 | 356 |  }
 | 
		
	
		
			
			| 347 | 357 |  
 | 
		
	
		
			
			|  | 358 | +/**
 | 
		
	
		
			
			|  | 359 | + * Set value of 16-bit integer setting
 | 
		
	
		
			
			|  | 360 | + *
 | 
		
	
		
			
			|  | 361 | + * @v context		Configuration context
 | 
		
	
		
			
			|  | 362 | + * @v setting		Configuration setting
 | 
		
	
		
			
			|  | 363 | + * @v value		Setting value (as a string)
 | 
		
	
		
			
			|  | 364 | + * @v size		Size of integer (in bytes)
 | 
		
	
		
			
			|  | 365 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 366 | + */ 
 | 
		
	
		
			
			|  | 367 | +static int set_int16 ( struct config_context *context,
 | 
		
	
		
			
			|  | 368 | +		       struct config_setting *setting,
 | 
		
	
		
			
			|  | 369 | +		       const char *value ) {
 | 
		
	
		
			
			|  | 370 | +	return set_int ( context, setting, value, 2 );
 | 
		
	
		
			
			|  | 371 | +}
 | 
		
	
		
			
			|  | 372 | +
 | 
		
	
		
			
			|  | 373 | +/**
 | 
		
	
		
			
			|  | 374 | + * Set value of 32-bit integer setting
 | 
		
	
		
			
			|  | 375 | + *
 | 
		
	
		
			
			|  | 376 | + * @v context		Configuration context
 | 
		
	
		
			
			|  | 377 | + * @v setting		Configuration setting
 | 
		
	
		
			
			|  | 378 | + * @v value		Setting value (as a string)
 | 
		
	
		
			
			|  | 379 | + * @v size		Size of integer (in bytes)
 | 
		
	
		
			
			|  | 380 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 381 | + */ 
 | 
		
	
		
			
			|  | 382 | +static int set_int32 ( struct config_context *context,
 | 
		
	
		
			
			|  | 383 | +		       struct config_setting *setting,
 | 
		
	
		
			
			|  | 384 | +		       const char *value ) {
 | 
		
	
		
			
			|  | 385 | +	return set_int ( context, setting, value, 4 );
 | 
		
	
		
			
			|  | 386 | +}
 | 
		
	
		
			
			|  | 387 | +
 | 
		
	
		
			
			| 348 | 388 |  /** An 8-bit integer configuration setting */
 | 
		
	
		
			
			| 349 | 389 |  struct config_setting_type config_setting_type_int8 __config_setting_type = {
 | 
		
	
		
			
			| 350 | 390 |  	.name = "int8",
 | 
		
	
	
		
			
			|  | @@ -353,6 +393,92 @@ struct config_setting_type config_setting_type_int8 __config_setting_type = {
 | 
		
	
		
			
			| 353 | 393 |  	.set = set_int8,
 | 
		
	
		
			
			| 354 | 394 |  };
 | 
		
	
		
			
			| 355 | 395 |  
 | 
		
	
		
			
			|  | 396 | +/** A 16-bit integer configuration setting */
 | 
		
	
		
			
			|  | 397 | +struct config_setting_type config_setting_type_int16 __config_setting_type = {
 | 
		
	
		
			
			|  | 398 | +	.name = "int16",
 | 
		
	
		
			
			|  | 399 | +	.description = "16-bit integer",
 | 
		
	
		
			
			|  | 400 | +	.show = show_int,
 | 
		
	
		
			
			|  | 401 | +	.set = set_int16,
 | 
		
	
		
			
			|  | 402 | +};
 | 
		
	
		
			
			|  | 403 | +
 | 
		
	
		
			
			|  | 404 | +/** A 32-bit integer configuration setting */
 | 
		
	
		
			
			|  | 405 | +struct config_setting_type config_setting_type_int32 __config_setting_type = {
 | 
		
	
		
			
			|  | 406 | +	.name = "int32",
 | 
		
	
		
			
			|  | 407 | +	.description = "32-bit integer",
 | 
		
	
		
			
			|  | 408 | +	.show = show_int,
 | 
		
	
		
			
			|  | 409 | +	.set = set_int32,
 | 
		
	
		
			
			|  | 410 | +};
 | 
		
	
		
			
			|  | 411 | +
 | 
		
	
		
			
			|  | 412 | +/**
 | 
		
	
		
			
			|  | 413 | + * Set value of hex-string setting
 | 
		
	
		
			
			|  | 414 | + *
 | 
		
	
		
			
			|  | 415 | + * @v context		Configuration context
 | 
		
	
		
			
			|  | 416 | + * @v setting		Configuration setting
 | 
		
	
		
			
			|  | 417 | + * @v value		Setting value (as a string)
 | 
		
	
		
			
			|  | 418 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 419 | + */ 
 | 
		
	
		
			
			|  | 420 | +static int set_hex ( struct config_context *context,
 | 
		
	
		
			
			|  | 421 | +		     struct config_setting *setting,
 | 
		
	
		
			
			|  | 422 | +		     const char *value ) {
 | 
		
	
		
			
			|  | 423 | +	struct dhcp_option *option;
 | 
		
	
		
			
			|  | 424 | +	char *ptr = ( char * ) value;
 | 
		
	
		
			
			|  | 425 | +	uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
 | 
		
	
		
			
			|  | 426 | +	unsigned int len = 0;
 | 
		
	
		
			
			|  | 427 | +
 | 
		
	
		
			
			|  | 428 | +	while ( 1 ) {
 | 
		
	
		
			
			|  | 429 | +		bytes[len++] = strtoul ( ptr, &ptr, 16 );
 | 
		
	
		
			
			|  | 430 | +		switch ( *ptr ) {
 | 
		
	
		
			
			|  | 431 | +		case '\0' :
 | 
		
	
		
			
			|  | 432 | +			option = set_dhcp_option ( context->options,
 | 
		
	
		
			
			|  | 433 | +						   setting->tag, bytes, len );
 | 
		
	
		
			
			|  | 434 | +			if ( ! option )
 | 
		
	
		
			
			|  | 435 | +				return -ENOSPC;
 | 
		
	
		
			
			|  | 436 | +			return 0;
 | 
		
	
		
			
			|  | 437 | +		case ':' :
 | 
		
	
		
			
			|  | 438 | +			ptr++;
 | 
		
	
		
			
			|  | 439 | +			break;
 | 
		
	
		
			
			|  | 440 | +		default :
 | 
		
	
		
			
			|  | 441 | +			return -EINVAL;
 | 
		
	
		
			
			|  | 442 | +		}
 | 
		
	
		
			
			|  | 443 | +	}
 | 
		
	
		
			
			|  | 444 | +}
 | 
		
	
		
			
			|  | 445 | +
 | 
		
	
		
			
			|  | 446 | +/**
 | 
		
	
		
			
			|  | 447 | + * Show value of hex-string setting
 | 
		
	
		
			
			|  | 448 | + *
 | 
		
	
		
			
			|  | 449 | + * @v context		Configuration context
 | 
		
	
		
			
			|  | 450 | + * @v setting		Configuration setting
 | 
		
	
		
			
			|  | 451 | + * @v buf		Buffer to contain value
 | 
		
	
		
			
			|  | 452 | + * @v len		Length of buffer
 | 
		
	
		
			
			|  | 453 | + * @ret len		Length of formatted value, or negative error
 | 
		
	
		
			
			|  | 454 | + */
 | 
		
	
		
			
			|  | 455 | +static int show_hex ( struct config_context *context,
 | 
		
	
		
			
			|  | 456 | +		      struct config_setting *setting,
 | 
		
	
		
			
			|  | 457 | +		      char *buf, size_t len ) {
 | 
		
	
		
			
			|  | 458 | +	struct dhcp_option *option;
 | 
		
	
		
			
			|  | 459 | +	int used = 0;
 | 
		
	
		
			
			|  | 460 | +	int i;
 | 
		
	
		
			
			|  | 461 | +
 | 
		
	
		
			
			|  | 462 | +	option = find_dhcp_option ( context->options, setting->tag );
 | 
		
	
		
			
			|  | 463 | +	if ( ! option )
 | 
		
	
		
			
			|  | 464 | +		return -ENODATA;
 | 
		
	
		
			
			|  | 465 | +
 | 
		
	
		
			
			|  | 466 | +	for ( i = 0 ; i < option->len ; i++ ) {
 | 
		
	
		
			
			|  | 467 | +		used += ssnprintf ( ( buf + used ), ( len - used ),
 | 
		
	
		
			
			|  | 468 | +				    "%s%02x", ( used ? ":" : "" ),
 | 
		
	
		
			
			|  | 469 | +				    option->data.bytes[i] );
 | 
		
	
		
			
			|  | 470 | +	}
 | 
		
	
		
			
			|  | 471 | +	return used;
 | 
		
	
		
			
			|  | 472 | +}
 | 
		
	
		
			
			|  | 473 | +
 | 
		
	
		
			
			|  | 474 | +/** A hex-string configuration setting */
 | 
		
	
		
			
			|  | 475 | +struct config_setting_type config_setting_type_hex __config_setting_type = {
 | 
		
	
		
			
			|  | 476 | +	.name = "hex",
 | 
		
	
		
			
			|  | 477 | +	.description = "Hex string",
 | 
		
	
		
			
			|  | 478 | +	.show = show_hex,
 | 
		
	
		
			
			|  | 479 | +	.set = set_hex,
 | 
		
	
		
			
			|  | 480 | +};
 | 
		
	
		
			
			|  | 481 | +
 | 
		
	
		
			
			| 356 | 482 |  /** Some basic setting definitions */
 | 
		
	
		
			
			| 357 | 483 |  struct config_setting basic_config_settings[] __config_setting = {
 | 
		
	
		
			
			| 358 | 484 |  	{
 |