|  | @@ -271,6 +271,9 @@ struct settings * find_child_settings ( struct settings *parent,
 | 
		
	
		
			
			| 271 | 271 |  					const char *name ) {
 | 
		
	
		
			
			| 272 | 272 |  	struct settings *settings;
 | 
		
	
		
			
			| 273 | 273 |  
 | 
		
	
		
			
			|  | 274 | +	/* Find target parent settings block */
 | 
		
	
		
			
			|  | 275 | +	parent = settings_target ( parent );
 | 
		
	
		
			
			|  | 276 | +
 | 
		
	
		
			
			| 274 | 277 |  	/* Treat empty name as meaning "this block" */
 | 
		
	
		
			
			| 275 | 278 |  	if ( ! *name )
 | 
		
	
		
			
			| 276 | 279 |  		return parent;
 | 
		
	
	
		
			
			|  | @@ -278,7 +281,7 @@ struct settings * find_child_settings ( struct settings *parent,
 | 
		
	
		
			
			| 278 | 281 |  	/* Look for child with matching name */
 | 
		
	
		
			
			| 279 | 282 |  	list_for_each_entry ( settings, &parent->children, siblings ) {
 | 
		
	
		
			
			| 280 | 283 |  		if ( strcmp ( settings->name, name ) == 0 )
 | 
		
	
		
			
			| 281 |  | -			return settings;
 | 
		
	
		
			
			|  | 284 | +			return settings_target ( settings );
 | 
		
	
		
			
			| 282 | 285 |  	}
 | 
		
	
		
			
			| 283 | 286 |  
 | 
		
	
		
			
			| 284 | 287 |  	return NULL;
 | 
		
	
	
		
			
			|  | @@ -299,6 +302,9 @@ static struct settings * autovivify_child_settings ( struct settings *parent,
 | 
		
	
		
			
			| 299 | 302 |  	} *new_child;
 | 
		
	
		
			
			| 300 | 303 |  	struct settings *settings;
 | 
		
	
		
			
			| 301 | 304 |  
 | 
		
	
		
			
			|  | 305 | +	/* Find target parent settings block */
 | 
		
	
		
			
			|  | 306 | +	parent = settings_target ( parent );
 | 
		
	
		
			
			|  | 307 | +
 | 
		
	
		
			
			| 302 | 308 |  	/* Return existing settings, if existent */
 | 
		
	
		
			
			| 303 | 309 |  	if ( ( settings = find_child_settings ( parent, name ) ) != NULL )
 | 
		
	
		
			
			| 304 | 310 |  		return settings;
 | 
		
	
	
		
			
			|  | @@ -330,6 +336,10 @@ const char * settings_name ( struct settings *settings ) {
 | 
		
	
		
			
			| 330 | 336 |  	static char buf[16];
 | 
		
	
		
			
			| 331 | 337 |  	char tmp[ sizeof ( buf ) ];
 | 
		
	
		
			
			| 332 | 338 |  
 | 
		
	
		
			
			|  | 339 | +	/* Find target settings block */
 | 
		
	
		
			
			|  | 340 | +	settings = settings_target ( settings );
 | 
		
	
		
			
			|  | 341 | +
 | 
		
	
		
			
			|  | 342 | +	/* Construct name */
 | 
		
	
		
			
			| 333 | 343 |  	for ( buf[2] = buf[0] = 0 ; settings ; settings = settings->parent ) {
 | 
		
	
		
			
			| 334 | 344 |  		memcpy ( tmp, buf, sizeof ( tmp ) );
 | 
		
	
		
			
			| 335 | 345 |  		snprintf ( buf, sizeof ( buf ), ".%s%s", settings->name, tmp );
 | 
		
	
	
		
			
			|  | @@ -359,20 +369,11 @@ parse_settings_name ( const char *name,
 | 
		
	
		
			
			| 359 | 369 |  
 | 
		
	
		
			
			| 360 | 370 |  	/* Parse each name component in turn */
 | 
		
	
		
			
			| 361 | 371 |  	while ( remainder ) {
 | 
		
	
		
			
			| 362 |  | -		struct net_device *netdev;
 | 
		
	
		
			
			| 363 |  | -
 | 
		
	
		
			
			| 364 | 372 |  		subname = remainder;
 | 
		
	
		
			
			| 365 | 373 |  		remainder = strchr ( subname, '.' );
 | 
		
	
		
			
			| 366 | 374 |  		if ( remainder )
 | 
		
	
		
			
			| 367 | 375 |  			*(remainder++) = '\0';
 | 
		
	
		
			
			| 368 |  | -
 | 
		
	
		
			
			| 369 |  | -		/* Special case "netX" root settings block */
 | 
		
	
		
			
			| 370 |  | -		if ( ( subname == name_copy ) && ! strcmp ( subname, "netX" ) &&
 | 
		
	
		
			
			| 371 |  | -		     ( ( netdev = last_opened_netdev() ) != NULL ) )
 | 
		
	
		
			
			| 372 |  | -			settings = get_child ( settings, netdev->name );
 | 
		
	
		
			
			| 373 |  | -		else
 | 
		
	
		
			
			| 374 |  | -			settings = get_child ( settings, subname );
 | 
		
	
		
			
			| 375 |  | -
 | 
		
	
		
			
			|  | 376 | +		settings = get_child ( settings, subname );
 | 
		
	
		
			
			| 376 | 377 |  		if ( ! settings )
 | 
		
	
		
			
			| 377 | 378 |  			break;
 | 
		
	
		
			
			| 378 | 379 |  	}
 | 
		
	
	
		
			
			|  | @@ -460,10 +461,11 @@ int register_settings ( struct settings *settings, struct settings *parent,
 | 
		
	
		
			
			| 460 | 461 |  			const char *name ) {
 | 
		
	
		
			
			| 461 | 462 |  	struct settings *old_settings;
 | 
		
	
		
			
			| 462 | 463 |  
 | 
		
	
		
			
			| 463 |  | -	/* NULL parent => add to settings root */
 | 
		
	
		
			
			|  | 464 | +	/* Sanity check */
 | 
		
	
		
			
			| 464 | 465 |  	assert ( settings != NULL );
 | 
		
	
		
			
			| 465 |  | -	if ( parent == NULL )
 | 
		
	
		
			
			| 466 |  | -		parent = &settings_root;
 | 
		
	
		
			
			|  | 466 | +
 | 
		
	
		
			
			|  | 467 | +	/* Find target parent settings block */
 | 
		
	
		
			
			|  | 468 | +	parent = settings_target ( parent );
 | 
		
	
		
			
			| 467 | 469 |  
 | 
		
	
		
			
			| 468 | 470 |  	/* Apply settings block name */
 | 
		
	
		
			
			| 469 | 471 |  	settings->name = name;
 | 
		
	
	
		
			
			|  | @@ -523,6 +525,26 @@ void unregister_settings ( struct settings *settings ) {
 | 
		
	
		
			
			| 523 | 525 |   ******************************************************************************
 | 
		
	
		
			
			| 524 | 526 |   */
 | 
		
	
		
			
			| 525 | 527 |  
 | 
		
	
		
			
			|  | 528 | +/**
 | 
		
	
		
			
			|  | 529 | + * Redirect to target settings block
 | 
		
	
		
			
			|  | 530 | + *
 | 
		
	
		
			
			|  | 531 | + * @v settings		Settings block, or NULL
 | 
		
	
		
			
			|  | 532 | + * @ret settings	Underlying settings block
 | 
		
	
		
			
			|  | 533 | + */
 | 
		
	
		
			
			|  | 534 | +struct settings * settings_target ( struct settings *settings ) {
 | 
		
	
		
			
			|  | 535 | +
 | 
		
	
		
			
			|  | 536 | +	/* NULL settings implies the global settings root */
 | 
		
	
		
			
			|  | 537 | +	if ( ! settings )
 | 
		
	
		
			
			|  | 538 | +		settings = &settings_root;
 | 
		
	
		
			
			|  | 539 | +
 | 
		
	
		
			
			|  | 540 | +	/* Redirect to underlying settings block, if applicable */
 | 
		
	
		
			
			|  | 541 | +	if ( settings->op->redirect )
 | 
		
	
		
			
			|  | 542 | +		return settings->op->redirect ( settings );
 | 
		
	
		
			
			|  | 543 | +
 | 
		
	
		
			
			|  | 544 | +	/* Otherwise, return this settings block */
 | 
		
	
		
			
			|  | 545 | +	return settings;
 | 
		
	
		
			
			|  | 546 | +}
 | 
		
	
		
			
			|  | 547 | +
 | 
		
	
		
			
			| 526 | 548 |  /**
 | 
		
	
		
			
			| 527 | 549 |   * Check applicability of setting
 | 
		
	
		
			
			| 528 | 550 |   *
 | 
		
	
	
		
			
			|  | @@ -532,6 +554,10 @@ void unregister_settings ( struct settings *settings ) {
 | 
		
	
		
			
			| 532 | 554 |   */
 | 
		
	
		
			
			| 533 | 555 |  int setting_applies ( struct settings *settings, struct setting *setting ) {
 | 
		
	
		
			
			| 534 | 556 |  
 | 
		
	
		
			
			|  | 557 | +	/* Find target settings block */
 | 
		
	
		
			
			|  | 558 | +	settings = settings_target ( settings );
 | 
		
	
		
			
			|  | 559 | +
 | 
		
	
		
			
			|  | 560 | +	/* Check applicability of setting */
 | 
		
	
		
			
			| 535 | 561 |  	return ( settings->op->applies ?
 | 
		
	
		
			
			| 536 | 562 |  		 settings->op->applies ( settings, setting ) : 1 );
 | 
		
	
		
			
			| 537 | 563 |  }
 | 
		
	
	
		
			
			|  | @@ -549,9 +575,8 @@ int store_setting ( struct settings *settings, struct setting *setting,
 | 
		
	
		
			
			| 549 | 575 |  		    const void *data, size_t len ) {
 | 
		
	
		
			
			| 550 | 576 |  	int rc;
 | 
		
	
		
			
			| 551 | 577 |  
 | 
		
	
		
			
			| 552 |  | -	/* NULL settings implies storing into the global settings root */
 | 
		
	
		
			
			| 553 |  | -	if ( ! settings )
 | 
		
	
		
			
			| 554 |  | -		settings = &settings_root;
 | 
		
	
		
			
			|  | 578 | +	/* Find target settings block */
 | 
		
	
		
			
			|  | 579 | +	settings = settings_target ( settings );
 | 
		
	
		
			
			| 555 | 580 |  
 | 
		
	
		
			
			| 556 | 581 |  	/* Fail if tag does not apply to this settings block */
 | 
		
	
		
			
			| 557 | 582 |  	if ( ! setting_applies ( settings, setting ) )
 | 
		
	
	
		
			
			|  | @@ -609,9 +634,8 @@ static int fetch_setting_and_origin ( struct settings *settings,
 | 
		
	
		
			
			| 609 | 634 |  	if ( origin )
 | 
		
	
		
			
			| 610 | 635 |  		*origin = NULL;
 | 
		
	
		
			
			| 611 | 636 |  
 | 
		
	
		
			
			| 612 |  | -	/* NULL settings implies starting at the global settings root */
 | 
		
	
		
			
			| 613 |  | -	if ( ! settings )
 | 
		
	
		
			
			| 614 |  | -		settings = &settings_root;
 | 
		
	
		
			
			|  | 637 | +	/* Find target settings block */
 | 
		
	
		
			
			|  | 638 | +	settings = settings_target ( settings );
 | 
		
	
		
			
			| 615 | 639 |  
 | 
		
	
		
			
			| 616 | 640 |  	/* Sanity check */
 | 
		
	
		
			
			| 617 | 641 |  	if ( ! settings->op->fetch )
 | 
		
	
	
		
			
			|  | @@ -971,6 +995,11 @@ int fetch_uuid_setting ( struct settings *settings, struct setting *setting,
 | 
		
	
		
			
			| 971 | 995 |   * @v settings		Settings block
 | 
		
	
		
			
			| 972 | 996 |   */
 | 
		
	
		
			
			| 973 | 997 |  void clear_settings ( struct settings *settings ) {
 | 
		
	
		
			
			|  | 998 | +
 | 
		
	
		
			
			|  | 999 | +	/* Find target settings block */
 | 
		
	
		
			
			|  | 1000 | +	settings = settings_target ( settings );
 | 
		
	
		
			
			|  | 1001 | +
 | 
		
	
		
			
			|  | 1002 | +	/* Clear settings, if applicable */
 | 
		
	
		
			
			| 974 | 1003 |  	if ( settings->op->clear )
 | 
		
	
		
			
			| 975 | 1004 |  		settings->op->clear ( settings );
 | 
		
	
		
			
			| 976 | 1005 |  }
 | 
		
	
	
		
			
			|  | @@ -1230,9 +1259,7 @@ int setting_name ( struct settings *settings, struct setting *setting,
 | 
		
	
		
			
			| 1230 | 1259 |  		   char *buf, size_t len ) {
 | 
		
	
		
			
			| 1231 | 1260 |  	const char *name;
 | 
		
	
		
			
			| 1232 | 1261 |  
 | 
		
	
		
			
			| 1233 |  | -	if ( ! settings )
 | 
		
	
		
			
			| 1234 |  | -		settings = &settings_root;
 | 
		
	
		
			
			| 1235 |  | -
 | 
		
	
		
			
			|  | 1262 | +	settings = settings_target ( settings );
 | 
		
	
		
			
			| 1236 | 1263 |  	name = settings_name ( settings );
 | 
		
	
		
			
			| 1237 | 1264 |  	return snprintf ( buf, len, "%s%s%s:%s", name, ( name[0] ? "/" : "" ),
 | 
		
	
		
			
			| 1238 | 1265 |  			  setting->name, setting->type->name );
 |