mirror of
https://github.com/ipxe/ipxe
synced 2025-12-13 23:41:45 +03:00
[ipv6] Allow settings to comprise arbitrary subsets of NDP options
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -636,7 +636,7 @@ struct ndp_settings {
|
|||||||
/** Length of NDP options */
|
/** Length of NDP options */
|
||||||
size_t len;
|
size_t len;
|
||||||
/** NDP options */
|
/** NDP options */
|
||||||
union ndp_option option[0];
|
union ndp_option options[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
/** NDP settings scope */
|
/** NDP settings scope */
|
||||||
@@ -647,9 +647,11 @@ static const struct settings_scope ndp_settings_scope;
|
|||||||
*
|
*
|
||||||
* @v type NDP option type
|
* @v type NDP option type
|
||||||
* @v offset Starting offset of data
|
* @v offset Starting offset of data
|
||||||
|
* @v len Length of data (or 0 to use all remaining data)
|
||||||
* @ret tag NDP tag
|
* @ret tag NDP tag
|
||||||
*/
|
*/
|
||||||
#define NDP_TAG( type, offset ) ( ( (offset) << 8 ) | (type) )
|
#define NDP_TAG( type, offset, len ) \
|
||||||
|
( ( (len) << 16 ) | ( (offset) << 8 ) | (type) )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract NDP tag type
|
* Extract NDP tag type
|
||||||
@@ -657,7 +659,7 @@ static const struct settings_scope ndp_settings_scope;
|
|||||||
* @v tag NDP tag
|
* @v tag NDP tag
|
||||||
* @ret type NDP option type
|
* @ret type NDP option type
|
||||||
*/
|
*/
|
||||||
#define NDP_TAG_TYPE( tag ) ( (tag) & 0xff )
|
#define NDP_TAG_TYPE( tag ) ( ( (tag) >> 0 ) & 0xff )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract NDP tag offset
|
* Extract NDP tag offset
|
||||||
@@ -665,7 +667,23 @@ static const struct settings_scope ndp_settings_scope;
|
|||||||
* @v tag NDP tag
|
* @v tag NDP tag
|
||||||
* @ret offset Starting offset of data
|
* @ret offset Starting offset of data
|
||||||
*/
|
*/
|
||||||
#define NDP_TAG_OFFSET( tag ) ( (tag) >> 8 )
|
#define NDP_TAG_OFFSET( tag ) ( ( (tag) >> 8 ) & 0xff )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract NDP tag length
|
||||||
|
*
|
||||||
|
* @v tag NDP tag
|
||||||
|
* @ret len Length of data (or 0 to use all remaining data)
|
||||||
|
*/
|
||||||
|
#define NDP_TAG_LEN( tag ) ( ( (tag) >> 16 ) & 0xff )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract NDP tag instance
|
||||||
|
*
|
||||||
|
* @v tag NDP tag
|
||||||
|
* @ret instance Instance
|
||||||
|
*/
|
||||||
|
#define NDP_TAG_INSTANCE( tag ) ( ( (tag) >> 24 ) & 0xff )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check applicability of NDP setting
|
* Check applicability of NDP setting
|
||||||
@@ -698,44 +716,58 @@ static int ndp_fetch ( struct settings *settings,
|
|||||||
container_of ( settings->parent, struct net_device,
|
container_of ( settings->parent, struct net_device,
|
||||||
settings.settings );
|
settings.settings );
|
||||||
union ndp_option *option;
|
union ndp_option *option;
|
||||||
unsigned int type = NDP_TAG_TYPE ( setting->tag );
|
unsigned int tag_type;
|
||||||
unsigned int offset = NDP_TAG_OFFSET ( setting->tag );
|
unsigned int tag_offset;
|
||||||
size_t remaining;
|
unsigned int tag_len;
|
||||||
|
unsigned int tag_instance;
|
||||||
|
size_t offset;
|
||||||
size_t option_len;
|
size_t option_len;
|
||||||
size_t payload_len;
|
void *option_data;
|
||||||
|
|
||||||
|
/* Parse setting tag */
|
||||||
|
tag_type = NDP_TAG_TYPE ( setting->tag );
|
||||||
|
tag_offset = NDP_TAG_OFFSET ( setting->tag );
|
||||||
|
tag_len = NDP_TAG_LEN ( setting->tag );
|
||||||
|
tag_instance = NDP_TAG_INSTANCE ( setting->tag );
|
||||||
|
|
||||||
/* Scan through NDP options for requested type. We can assume
|
/* Scan through NDP options for requested type. We can assume
|
||||||
* that the options are well-formed, otherwise they would have
|
* that the options are well-formed, otherwise they would have
|
||||||
* been rejected prior to being stored.
|
* been rejected prior to being stored.
|
||||||
*/
|
*/
|
||||||
option = ndpset->option;
|
for ( offset = 0 ; offset < ndpset->len ; offset += option_len ) {
|
||||||
remaining = ndpset->len;
|
|
||||||
while ( remaining ) {
|
|
||||||
|
|
||||||
/* Calculate option length */
|
/* Calculate option length */
|
||||||
|
option = ( ( ( void * ) ndpset->options ) + offset );
|
||||||
option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
|
option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
|
||||||
|
|
||||||
/* If this is the requested option, return it */
|
/* Skip options that do not match this tag */
|
||||||
if ( option->header.type == type ) {
|
if ( option->header.type != tag_type )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Skip previous instances of this option */
|
||||||
|
if ( tag_instance-- != 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if ( offset > option_len ) {
|
if ( ( tag_offset + tag_len ) > option_len ) {
|
||||||
DBGC ( netdev, "NDP %s option %d too short\n",
|
DBGC ( netdev, "NDP %s option %d too short\n",
|
||||||
netdev->name, type );
|
netdev->name, tag_type );
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
payload_len = ( option_len - offset );
|
if ( ! tag_len )
|
||||||
|
tag_len = ( option_len - tag_offset );
|
||||||
|
option_data = ( ( ( void * ) option ) + tag_offset );
|
||||||
|
|
||||||
/* Copy data to output buffer */
|
/* Copy data to output buffer */
|
||||||
if ( len > payload_len )
|
if ( len > tag_len )
|
||||||
len = payload_len;
|
len = tag_len;
|
||||||
memcpy ( data, ( ( ( void * ) option ) + offset ), len);
|
memcpy ( data, option_data, len );
|
||||||
return payload_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Move to next option */
|
/* Default to hex if no type is specified */
|
||||||
option = ( ( ( void * ) option ) + option_len );
|
if ( ! setting->type )
|
||||||
remaining -= option_len;
|
setting->type = &setting_type_hex;
|
||||||
|
|
||||||
|
return tag_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
@@ -751,12 +783,12 @@ static struct settings_operations ndp_settings_operations = {
|
|||||||
* Register NDP settings
|
* Register NDP settings
|
||||||
*
|
*
|
||||||
* @v netdev Network device
|
* @v netdev Network device
|
||||||
* @v option NDP options
|
* @v options NDP options
|
||||||
* @v len Length of options
|
* @v len Length of options
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int ndp_register_settings ( struct net_device *netdev,
|
static int ndp_register_settings ( struct net_device *netdev,
|
||||||
union ndp_option *option, size_t len ) {
|
union ndp_option *options, size_t len ) {
|
||||||
struct settings *parent = netdev_settings ( netdev );
|
struct settings *parent = netdev_settings ( netdev );
|
||||||
struct ndp_settings *ndpset;
|
struct ndp_settings *ndpset;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -771,7 +803,7 @@ static int ndp_register_settings ( struct net_device *netdev,
|
|||||||
settings_init ( &ndpset->settings, &ndp_settings_operations,
|
settings_init ( &ndpset->settings, &ndp_settings_operations,
|
||||||
&ndpset->refcnt, &ndp_settings_scope );
|
&ndpset->refcnt, &ndp_settings_scope );
|
||||||
ndpset->len = len;
|
ndpset->len = len;
|
||||||
memcpy ( ndpset->option, option, len );
|
memcpy ( ndpset->options, options, len );
|
||||||
|
|
||||||
/* Register settings */
|
/* Register settings */
|
||||||
if ( ( rc = register_settings ( &ndpset->settings, parent,
|
if ( ( rc = register_settings ( &ndpset->settings, parent,
|
||||||
@@ -789,7 +821,7 @@ const struct setting ndp_dns6_setting __setting ( SETTING_IP6_EXTRA, dns6 ) = {
|
|||||||
.name = "dns6",
|
.name = "dns6",
|
||||||
.description = "DNS server",
|
.description = "DNS server",
|
||||||
.tag = NDP_TAG ( NDP_OPT_RDNSS,
|
.tag = NDP_TAG ( NDP_OPT_RDNSS,
|
||||||
offsetof ( struct ndp_rdnss_option, addresses ) ),
|
offsetof ( struct ndp_rdnss_option, addresses ), 0 ),
|
||||||
.type = &setting_type_ipv6,
|
.type = &setting_type_ipv6,
|
||||||
.scope = &ndp_settings_scope,
|
.scope = &ndp_settings_scope,
|
||||||
};
|
};
|
||||||
@@ -799,7 +831,7 @@ const struct setting ndp_dnssl_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
|
|||||||
.name = "dnssl",
|
.name = "dnssl",
|
||||||
.description = "DNS search list",
|
.description = "DNS search list",
|
||||||
.tag = NDP_TAG ( NDP_OPT_DNSSL,
|
.tag = NDP_TAG ( NDP_OPT_DNSSL,
|
||||||
offsetof ( struct ndp_dnssl_option, names ) ),
|
offsetof ( struct ndp_dnssl_option, names ), 0 ),
|
||||||
.type = &setting_type_dnssl,
|
.type = &setting_type_dnssl,
|
||||||
.scope = &ndp_settings_scope,
|
.scope = &ndp_settings_scope,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user