third_party: update ipxe.

This commit is contained in:
David Anderson 2016-08-09 00:16:25 -07:00
parent d0f6cb0348
commit bff529103e
36 changed files with 2123 additions and 400 deletions

View File

@ -1 +1 @@
c53a209a4253a99a18fe3a9330fd85c9ce2b91a6 2afd66eb55996500499eb3bcc39c66ff042679c8

File diff suppressed because one or more lines are too long

View File

@ -182,12 +182,6 @@ REQUIRE_OBJECT ( efi_image );
#ifdef IMAGE_SDI #ifdef IMAGE_SDI
REQUIRE_OBJECT ( sdi ); REQUIRE_OBJECT ( sdi );
#endif #endif
#ifdef IMAGE_PNM
REQUIRE_OBJECT ( pnm );
#endif
#ifdef IMAGE_PNG
REQUIRE_OBJECT ( png );
#endif
/* /*
* Drag in all requested commands * Drag in all requested commands

View File

@ -0,0 +1,39 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/general.h>
/** @file
*
* ASN.1 file format configuration
*
*/
PROVIDE_REQUIRING_SYMBOL();
#ifdef IMAGE_DER
REQUIRE_OBJECT ( der );
#endif
#ifdef IMAGE_PEM
REQUIRE_OBJECT ( pem );
#endif

View File

@ -0,0 +1,39 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/general.h>
/** @file
*
* Pixel buffer file format configuration
*
*/
PROVIDE_REQUIRING_SYMBOL();
#ifdef IMAGE_PNM
REQUIRE_OBJECT ( pnm );
#endif
#ifdef IMAGE_PNG
REQUIRE_OBJECT ( png );
#endif

View File

@ -111,7 +111,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
//#define IMAGE_EFI /* EFI image support */ //#define IMAGE_EFI /* EFI image support */
//#define IMAGE_SDI /* SDI image support */ //#define IMAGE_SDI /* SDI image support */
//#define IMAGE_PNM /* PNM image support */ //#define IMAGE_PNM /* PNM image support */
//#define IMAGE_PNG /* PNG image support */ #define IMAGE_PNG /* PNG image support */
#define IMAGE_DER /* DER image support */
#define IMAGE_PEM /* PEM image support */
/* /*
* Command-line commands to include * Command-line commands to include

View File

@ -481,27 +481,3 @@ int image_set_trust ( int require_trusted, int permanent ) {
return 0; return 0;
} }
/**
* Create pixel buffer from image
*
* @v image Image
* @v pixbuf Pixel buffer to fill in
* @ret rc Return status code
*/
int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ) {
int rc;
/* Check that this image can be used to create a pixel buffer */
if ( ! ( image->type && image->type->pixbuf ) )
return -ENOTSUP;
/* Try creating pixel buffer */
if ( ( rc = image->type->pixbuf ( image, pixbuf ) ) != 0 ) {
DBGC ( image, "IMAGE %s could not create pixel buffer: %s\n",
image->name, strerror ( rc ) );
return rc;
}
return 0;
}

View File

@ -30,7 +30,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <errno.h>
#include <ipxe/umalloc.h> #include <ipxe/umalloc.h>
#include <ipxe/image.h>
#include <ipxe/pixbuf.h> #include <ipxe/pixbuf.h>
/** /**
@ -82,3 +84,33 @@ struct pixel_buffer * alloc_pixbuf ( unsigned int width, unsigned int height ) {
err_alloc_pixbuf: err_alloc_pixbuf:
return NULL; return NULL;
} }
/**
* Create pixel buffer from image
*
* @v image Image
* @v pixbuf Pixel buffer to fill in
* @ret rc Return status code
*/
int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ) {
int rc;
/* Check that this image can be used to create a pixel buffer */
if ( ! ( image->type && image->type->pixbuf ) )
return -ENOTSUP;
/* Try creating pixel buffer */
if ( ( rc = image->type->pixbuf ( image, pixbuf ) ) != 0 ) {
DBGC ( image, "IMAGE %s could not create pixel buffer: %s\n",
image->name, strerror ( rc ) );
return rc;
}
return 0;
}
/* Drag in objects via image_pixbuf() */
REQUIRING_SYMBOL ( image_pixbuf );
/* Drag in pixel buffer image formats */
REQUIRE_OBJECT ( config_pixbuf );

View File

@ -331,6 +331,7 @@ struct settings * autovivify_child_settings ( struct settings *parent,
&new_child->autovivified.refcnt ); &new_child->autovivified.refcnt );
settings = &new_child->autovivified.generic.settings; settings = &new_child->autovivified.generic.settings;
register_settings ( settings, parent, new_child->name ); register_settings ( settings, parent, new_child->name );
ref_put ( settings->refcnt );
return settings; return settings;
} }
@ -451,6 +452,8 @@ static void reprioritise_settings ( struct settings *settings ) {
tmp_priority = fetch_intz_setting ( tmp, &priority_setting ); tmp_priority = fetch_intz_setting ( tmp, &priority_setting );
if ( priority > tmp_priority ) if ( priority > tmp_priority )
break; break;
if ( settings->order > tmp->order )
break;
} }
list_add_tail ( &settings->siblings, &tmp->siblings ); list_add_tail ( &settings->siblings, &tmp->siblings );
@ -1784,7 +1787,7 @@ const struct setting_type setting_type_ipv6 __setting_type = {
}; };
/** IPv6 settings scope */ /** IPv6 settings scope */
const struct settings_scope ipv6_scope; const struct settings_scope dhcpv6_scope;
/** /**
* Integer setting type indices * Integer setting type indices

View File

@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#include <ipxe/tables.h> #include <ipxe/tables.h>
#include <ipxe/image.h>
#include <ipxe/asn1.h> #include <ipxe/asn1.h>
/** @file /** @file
@ -86,6 +87,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* *
* @v cursor ASN.1 object cursor * @v cursor ASN.1 object cursor
* @v type Expected type, or ASN1_ANY * @v type Expected type, or ASN1_ANY
* @v extra Additional length not present within partial cursor
* @ret len Length of object body, or negative error * @ret len Length of object body, or negative error
* *
* The object cursor will be updated to point to the start of the * The object cursor will be updated to point to the start of the
@ -93,7 +95,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* the length of the object body (i.e. the number of bytes until the * the length of the object body (i.e. the number of bytes until the
* following object tag, if any) is returned. * following object tag, if any) is returned.
*/ */
static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) { int asn1_start ( struct asn1_cursor *cursor, unsigned int type, size_t extra ) {
unsigned int len_len; unsigned int len_len;
unsigned int len; unsigned int len;
@ -135,9 +137,9 @@ static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
cursor->data++; cursor->data++;
cursor->len--; cursor->len--;
} }
if ( cursor->len < len ) { if ( ( cursor->len + extra ) < len ) {
DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n", DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
cursor, len, cursor->len ); cursor, len, ( cursor->len + extra ) );
return -EINVAL_ASN1_LEN; return -EINVAL_ASN1_LEN;
} }
@ -158,7 +160,7 @@ static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) { int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
int len; int len;
len = asn1_start ( cursor, type ); len = asn1_start ( cursor, type, 0 );
if ( len < 0 ) { if ( len < 0 ) {
asn1_invalidate_cursor ( cursor ); asn1_invalidate_cursor ( cursor );
return len; return len;
@ -185,7 +187,7 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) { int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
int len; int len;
len = asn1_start ( cursor, type ); len = asn1_start ( cursor, type, 0 );
if ( len < 0 ) if ( len < 0 )
return len; return len;
@ -242,7 +244,7 @@ int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) {
/* Find end of object */ /* Find end of object */
memcpy ( &temp, cursor, sizeof ( temp ) ); memcpy ( &temp, cursor, sizeof ( temp ) );
len = asn1_start ( &temp, type ); len = asn1_start ( &temp, type, 0 );
if ( len < 0 ) { if ( len < 0 ) {
asn1_invalidate_cursor ( cursor ); asn1_invalidate_cursor ( cursor );
return len; return len;
@ -837,3 +839,44 @@ int asn1_wrap ( struct asn1_builder *builder, unsigned int type ) {
return 0; return 0;
} }
/**
* Extract ASN.1 object from image
*
* @v image Image
* @v offset Offset within image
* @v cursor ASN.1 cursor to fill in
* @ret next Offset to next image, or negative error
*
* The caller is responsible for eventually calling free() on the
* allocated ASN.1 cursor.
*/
int image_asn1 ( struct image *image, size_t offset,
struct asn1_cursor **cursor ) {
int next;
int rc;
/* Sanity check */
assert ( offset <= image->len );
/* Check that this image can be used to extract an ASN.1 object */
if ( ! ( image->type && image->type->asn1 ) )
return -ENOTSUP;
/* Try creating ASN.1 cursor */
next = image->type->asn1 ( image, offset, cursor );
if ( next < 0 ) {
rc = next;
DBGC ( image, "IMAGE %s could not extract ASN.1 object: %s\n",
image->name, strerror ( rc ) );
return rc;
}
return next;
}
/* Drag in objects via image_asn1() */
REQUIRING_SYMBOL ( image_asn1 );
/* Drag in ASN.1 image formats */
REQUIRE_OBJECT ( config_asn1 );

View File

@ -172,12 +172,3 @@ struct command image_trust_commands[] __command = {
.exec = imgverify_exec, .exec = imgverify_exec,
}, },
}; };
/* Drag in objects via command list */
REQUIRING_SYMBOL ( image_trust_commands );
/* Drag in objects typically required for signature verification */
REQUIRE_OBJECT ( rsa );
REQUIRE_OBJECT ( md5 );
REQUIRE_OBJECT ( sha1 );
REQUIRE_OBJECT ( sha256 );

120
third_party/ipxe/src/image/der.c vendored Normal file
View File

@ -0,0 +1,120 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/asn1.h>
#include <ipxe/der.h>
#include <ipxe/uaccess.h>
#include <ipxe/image.h>
/** @file
*
* DER-encoded ASN.1 data
*
*/
/**
* Extract ASN.1 object from image
*
* @v image DER image
* @v offset Offset within image
* @v cursor ASN.1 cursor to fill in
* @ret next Offset to next image, or negative error
*
* The caller is responsible for eventually calling free() on the
* allocated ASN.1 cursor.
*/
static int der_asn1 ( struct image *image, size_t offset __unused,
struct asn1_cursor **cursor ) {
void *data;
/* Allocate cursor and data buffer */
*cursor = malloc ( sizeof ( **cursor ) + image->len );
if ( ! *cursor )
return -ENOMEM;
data = ( ( ( void * ) *cursor ) + sizeof ( **cursor ) );
/* Populate cursor and data buffer */
(*cursor)->data = data;
(*cursor)->len = image->len;
copy_from_user ( data, image->data, 0, image->len );
return image->len;
}
/**
* Probe DER image
*
* @v image DER image
* @ret rc Return status code
*/
static int der_probe ( struct image *image ) {
struct asn1_cursor cursor;
uint8_t buf[8];
size_t extra;
size_t total;
int len;
int rc;
/* Sanity check: no realistic DER image can be smaller than this */
if ( image->len < sizeof ( buf ) )
return -ENOEXEC;
/* Prepare partial cursor */
cursor.data = buf;
cursor.len = sizeof ( buf );
copy_from_user ( buf, image->data, 0, sizeof ( buf ) );
extra = ( image->len - sizeof ( buf ) );
/* Get length of ASN.1 sequence */
len = asn1_start ( &cursor, ASN1_SEQUENCE, extra );
if ( len < 0 ) {
rc = len;
DBGC ( image, "DER %s is not valid ASN.1: %s\n",
image->name, strerror ( rc ) );
return rc;
}
/* Add length of tag and length bytes consumed by asn1_start() */
total = ( len + ( cursor.data - ( ( void * ) buf ) ) );
assert ( total <= image->len );
/* Check that image comprises a single well-formed ASN.1 object */
if ( total != image->len ) {
DBGC ( image, "DER %s is not single ASN.1\n", image->name );
return -ENOEXEC;
}
return 0;
}
/** DER image type */
struct image_type der_image_type __image_type ( PROBE_NORMAL ) = {
.name = "DER",
.probe = der_probe,
.asn1 = der_asn1,
};

208
third_party/ipxe/src/image/pem.c vendored Normal file
View File

@ -0,0 +1,208 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/asn1.h>
#include <ipxe/pem.h>
#include <ipxe/base64.h>
#include <ipxe/uaccess.h>
#include <ipxe/image.h>
/** @file
*
* PEM-encoded ASN.1 data
*
*/
/**
* Locate next line
*
* @v image PEM image
* @v offset Starting offset
* @ret next Offset to next line
*/
static size_t pem_next ( struct image *image, size_t offset ) {
off_t eol;
/* Find and skip next newline character, if any */
eol = memchr_user ( image->data, offset, '\n', ( image->len - offset ));
if ( eol < 0 )
return image->len;
return ( eol + 1 );
}
/**
* Locate boundary marker line
*
* @v image PEM image
* @v offset Starting offset
* @v marker Boundary marker
* @ret offset Offset to boundary marker line, or negative error
*/
static int pem_marker ( struct image *image, size_t offset,
const char *marker ) {
char buf[ strlen ( marker ) ];
/* Sanity check */
assert ( offset <= image->len );
/* Scan for marker at start of line */
while ( offset < image->len ) {
/* Check for marker */
if ( ( image->len - offset ) < sizeof ( buf ) )
break;
copy_from_user ( buf, image->data, offset, sizeof ( buf ) );
if ( memcmp ( buf, marker, sizeof ( buf ) ) == 0 )
return offset;
/* Move to next line */
offset = pem_next ( image, offset );
assert ( offset <= image->len );
}
return -ENOENT;
}
/**
* Extract ASN.1 object from image
*
* @v image PEM image
* @v offset Offset within image
* @v cursor ASN.1 cursor to fill in
* @ret next Offset to next image, or negative error
*
* The caller is responsible for eventually calling free() on the
* allocated ASN.1 cursor.
*/
static int pem_asn1 ( struct image *image, size_t offset,
struct asn1_cursor **cursor ) {
size_t encoded_len;
size_t decoded_max_len;
char *encoded;
void *decoded;
int begin;
int end;
int len;
int rc;
/* Locate and skip BEGIN marker */
begin = pem_marker ( image, offset, PEM_BEGIN );
if ( begin < 0 ) {
rc = begin;
DBGC ( image, "PEM %s [%#zx,%#zx) missing BEGIN marker: %s\n",
image->name, offset, image->len, strerror ( rc ) );
goto err_begin;
}
begin = pem_next ( image, begin );
/* Locate and skip END marker */
end = pem_marker ( image, begin, PEM_END );
if ( end < 0 ) {
rc = end;
DBGC ( image, "PEM %s [%#zx,%#zx) missing END marker: %s\n",
image->name, offset, image->len, strerror ( rc ) );
goto err_end;
}
encoded_len = ( end - begin );
end = pem_next ( image, end );
/* Extract Base64-encoded data */
encoded = malloc ( encoded_len + 1 /* NUL */ );
if ( ! encoded ) {
rc = -ENOMEM;
goto err_alloc_encoded;
}
copy_from_user ( encoded, image->data, begin, encoded_len );
encoded[encoded_len] = '\0';
/* Allocate cursor and data buffer */
decoded_max_len = base64_decoded_max_len ( encoded );
*cursor = malloc ( sizeof ( **cursor ) + decoded_max_len );
if ( ! *cursor ) {
rc = -ENOMEM;
goto err_alloc_decoded;
}
decoded = ( ( ( void * ) *cursor ) + sizeof ( **cursor ) );
/* Decode Base64-encoded data */
len = base64_decode ( encoded, decoded, decoded_max_len );
if ( len < 0 ) {
rc = len;
DBGC ( image, "PEM %s could not decode: %s\n",
image->name, strerror ( rc ) );
goto err_decode;
}
(*cursor)->data = decoded;
(*cursor)->len = len;
assert ( (*cursor)->len <= decoded_max_len );
/* Free Base64-encoded data */
free ( encoded );
/* Update offset and skip any unencapsulated trailer */
offset = end;
if ( pem_marker ( image, offset, PEM_BEGIN ) < 0 )
offset = image->len;
return offset;
err_decode:
free ( decoded );
err_alloc_decoded:
free ( encoded );
err_alloc_encoded:
err_end:
err_begin:
return rc;
}
/**
* Probe PEM image
*
* @v image PEM image
* @ret rc Return status code
*/
static int pem_probe ( struct image *image ) {
int rc;
/* Check that image contains a BEGIN marker */
if ( ( rc = pem_marker ( image, 0, PEM_BEGIN ) ) < 0 ) {
DBGC ( image, "PEM %s has no BEGIN marker: %s\n",
image->name, strerror ( rc ) );
return rc;
}
return 0;
}
/** PEM image type */
struct image_type pem_image_type __image_type ( PROBE_NORMAL ) = {
.name = "PEM",
.probe = pem_probe,
.asn1 = pem_asn1,
};

View File

@ -337,7 +337,8 @@ asn1_type ( const struct asn1_cursor *cursor ) {
return ( ( cursor->len >= sizeof ( *type ) ) ? *type : ASN1_END ); return ( ( cursor->len >= sizeof ( *type ) ) ? *type : ASN1_END );
} }
extern void asn1_invalidate_cursor ( struct asn1_cursor *cursor ); extern int asn1_start ( struct asn1_cursor *cursor, unsigned int type,
size_t extra );
extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ); extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type );
extern int asn1_skip_if_exists ( struct asn1_cursor *cursor, extern int asn1_skip_if_exists ( struct asn1_cursor *cursor,
unsigned int type ); unsigned int type );

16
third_party/ipxe/src/include/ipxe/der.h vendored Normal file
View File

@ -0,0 +1,16 @@
#ifndef _IPXE_DER_H
#define _IPXE_DER_H
/** @file
*
* DER image format
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/image.h>
extern struct image_type der_image_type __image_type ( PROBE_NORMAL );
#endif /* _IPXE_DER_H */

View File

@ -72,7 +72,7 @@ struct device_description {
/** A hardware device */ /** A hardware device */
struct device { struct device {
/** Name */ /** Name */
char name[32]; char name[40];
/** Driver name */ /** Driver name */
const char *driver_name; const char *driver_name;
/** Device description */ /** Device description */

View File

@ -70,6 +70,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_ansicoldef ( ERRFILE_CORE | 0x001e0000 ) #define ERRFILE_ansicoldef ( ERRFILE_CORE | 0x001e0000 )
#define ERRFILE_fault ( ERRFILE_CORE | 0x001f0000 ) #define ERRFILE_fault ( ERRFILE_CORE | 0x001f0000 )
#define ERRFILE_blocktrans ( ERRFILE_CORE | 0x00200000 ) #define ERRFILE_blocktrans ( ERRFILE_CORE | 0x00200000 )
#define ERRFILE_pixbuf ( ERRFILE_CORE | 0x00210000 )
#define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 )
#define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )
@ -276,6 +277,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_embedded ( ERRFILE_IMAGE | 0x00050000 ) #define ERRFILE_embedded ( ERRFILE_IMAGE | 0x00050000 )
#define ERRFILE_pnm ( ERRFILE_IMAGE | 0x00060000 ) #define ERRFILE_pnm ( ERRFILE_IMAGE | 0x00060000 )
#define ERRFILE_png ( ERRFILE_IMAGE | 0x00070000 ) #define ERRFILE_png ( ERRFILE_IMAGE | 0x00070000 )
#define ERRFILE_der ( ERRFILE_IMAGE | 0x00080000 )
#define ERRFILE_pem ( ERRFILE_IMAGE | 0x00090000 )
#define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 ) #define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 )
#define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 ) #define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 )

View File

@ -17,6 +17,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct uri; struct uri;
struct pixel_buffer; struct pixel_buffer;
struct asn1_cursor;
struct image_type; struct image_type;
/** An executable image */ /** An executable image */
@ -99,6 +100,19 @@ struct image_type {
* @ret rc Return status code * @ret rc Return status code
*/ */
int ( * pixbuf ) ( struct image *image, struct pixel_buffer **pixbuf ); int ( * pixbuf ) ( struct image *image, struct pixel_buffer **pixbuf );
/**
* Extract ASN.1 object from image
*
* @v image Image
* @v offset Offset within image
* @v cursor ASN.1 cursor to fill in
* @ret next Offset to next image, or negative error
*
* The caller is responsible for eventually calling free() on
* the allocated ASN.1 cursor.
*/
int ( * asn1 ) ( struct image *image, size_t offset,
struct asn1_cursor **cursor );
}; };
/** /**
@ -170,6 +184,8 @@ extern int image_select ( struct image *image );
extern struct image * image_find_selected ( void ); extern struct image * image_find_selected ( void );
extern int image_set_trust ( int require_trusted, int permanent ); extern int image_set_trust ( int require_trusted, int permanent );
extern int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ); extern int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf );
extern int image_asn1 ( struct image *image, size_t offset,
struct asn1_cursor **cursor );
/** /**
* Increment reference count on an image * Increment reference count on an image

View File

@ -69,8 +69,12 @@ struct in6_addr {
( ( *( ( const uint16_t * ) (addr) ) & htons ( 0xffc0 ) ) == \ ( ( *( ( const uint16_t * ) (addr) ) & htons ( 0xffc0 ) ) == \
htons ( 0xfe80 ) ) htons ( 0xfe80 ) )
#define IN6_IS_ADDR_NONGLOBAL( addr ) \ #define IN6_IS_ADDR_SITELOCAL( addr ) \
( IN6_IS_ADDR_LINKLOCAL (addr) || IN6_IS_ADDR_MULTICAST (addr) ) ( ( *( ( const uint16_t * ) (addr) ) & htons ( 0xffc0 ) ) == \
htons ( 0xfec0 ) )
#define IN6_IS_ADDR_ULA( addr ) \
( ( *( ( const uint8_t * ) (addr) ) & 0xfe ) == 0xfc )
/** /**
* IPv4 socket address * IPv4 socket address

View File

@ -25,6 +25,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** IPv6 maximum hop limit */ /** IPv6 maximum hop limit */
#define IPV6_HOP_LIMIT 0xff #define IPV6_HOP_LIMIT 0xff
/** IPv6 default prefix length */
#define IPV6_DEFAULT_PREFIX_LEN 64
/** IPv6 maximum prefix length */
#define IPV6_MAX_PREFIX_LEN 128
/** IPv6 header */ /** IPv6 header */
struct ipv6_header { struct ipv6_header {
/** Version (4 bits), Traffic class (8 bits), Flow label (20 bits) */ /** Version (4 bits), Traffic class (8 bits), Flow label (20 bits) */
@ -152,6 +158,24 @@ struct ipv6_pseudo_header {
uint8_t next_header; uint8_t next_header;
} __attribute__ (( packed )); } __attribute__ (( packed ));
/** IPv6 address scopes */
enum ipv6_address_scope {
/** Interface-local address scope */
IPV6_SCOPE_INTERFACE_LOCAL = 0x1,
/** Link-local address scope */
IPV6_SCOPE_LINK_LOCAL = 0x2,
/** Admin-local address scope */
INV6_SCOPE_ADMIN_LOCAL = 0x4,
/** Site-local address scope */
IPV6_SCOPE_SITE_LOCAL = 0x5,
/** Organisation-local address scope */
IPV6_SCOPE_ORGANISATION_LOCAL = 0x8,
/** Global address scope */
IPV6_SCOPE_GLOBAL = 0xe,
/** Maximum scope */
IPV6_SCOPE_MAX = 0xf,
};
/** An IPv6 address/routing table entry */ /** An IPv6 address/routing table entry */
struct ipv6_miniroute { struct ipv6_miniroute {
/** List of miniroutes */ /** List of miniroutes */
@ -168,6 +192,8 @@ struct ipv6_miniroute {
struct in6_addr prefix_mask; struct in6_addr prefix_mask;
/** Router address */ /** Router address */
struct in6_addr router; struct in6_addr router;
/** Scope */
unsigned int scope;
/** Flags */ /** Flags */
unsigned int flags; unsigned int flags;
}; };
@ -238,15 +264,45 @@ static inline void ipv6_all_routers ( struct in6_addr *addr ) {
addr->s6_addr[15] = 2; addr->s6_addr[15] = 2;
} }
/**
* Get multicast address scope
*
* @v addr Multicast address
* @ret scope Address scope
*/
static inline unsigned int
ipv6_multicast_scope ( const struct in6_addr *addr ) {
return ( addr->s6_addr[1] & 0x0f );
}
/** IPv6 settings sibling order */
enum ipv6_settings_order {
/** No address */
IPV6_ORDER_PREFIX_ONLY = -4,
/** Link-local address */
IPV6_ORDER_LINK_LOCAL = -3,
/** Address assigned via SLAAC */
IPV6_ORDER_SLAAC = -2,
/** Address assigned via DHCPv6 */
IPV6_ORDER_DHCPV6 = -1,
};
/** IPv6 link-local address settings block name */
#define IPV6_SETTINGS_NAME "link"
extern struct list_head ipv6_miniroutes; extern struct list_head ipv6_miniroutes;
extern struct net_protocol ipv6_protocol __net_protocol; extern struct net_protocol ipv6_protocol __net_protocol;
extern int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr ); extern int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr );
extern int ipv6_set_prefix ( struct net_device *netdev, struct in6_addr *prefix, extern int ipv6_add_miniroute ( struct net_device *netdev,
unsigned int prefix_len, struct in6_addr *router ); struct in6_addr *address,
extern int ipv6_set_address ( struct net_device *netdev, unsigned int prefix_len,
struct in6_addr *address ); struct in6_addr *router );
extern void ipv6_del_miniroute ( struct ipv6_miniroute *miniroute );
extern struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
struct in6_addr **dest );
extern int parse_ipv6_setting ( const struct setting_type *type, extern int parse_ipv6_setting ( const struct setting_type *type,
const char *value, void *buf, size_t len ); const char *value, void *buf, size_t len );
extern int format_ipv6_setting ( const struct setting_type *type, extern int format_ipv6_setting ( const struct setting_type *type,

22
third_party/ipxe/src/include/ipxe/pem.h vendored Normal file
View File

@ -0,0 +1,22 @@
#ifndef _IPXE_PEM_H
#define _IPXE_PEM_H
/** @file
*
* PEM image format
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/image.h>
/** Pre-encapsulation boundary marker */
#define PEM_BEGIN "-----BEGIN"
/** Post-encapsulation boundary marker */
#define PEM_END "-----END"
extern struct image_type pem_image_type __image_type ( PROBE_NORMAL );
#endif /* _IPXE_PEM_H */

View File

@ -62,18 +62,22 @@ struct setting {
#define SETTING_NETDEV 01 /**< Network device settings */ #define SETTING_NETDEV 01 /**< Network device settings */
#define SETTING_NETDEV_EXTRA 02 /**< Network device additional settings */ #define SETTING_NETDEV_EXTRA 02 /**< Network device additional settings */
#define SETTING_IP 03 /**< IPv4 settings */ #define SETTING_IP4 03 /**< IPv4 settings */
#define SETTING_IP_EXTRA 04 /**< IPv4 additional settings */ #define SETTING_IP4_EXTRA 04 /**< IPv4 additional settings */
#define SETTING_BOOT 05 /**< Generic boot settings */ #define SETTING_IP6 05 /**< IPv6 settings */
#define SETTING_BOOT_EXTRA 06 /**< Generic boot additional settings */ #define SETTING_IP6_EXTRA 06 /**< IPv6 additional settings */
#define SETTING_SANBOOT 07 /**< SAN boot settings */ #define SETTING_IP 07 /**< IPv4 settings */
#define SETTING_SANBOOT_EXTRA 08 /**< SAN boot additional settings */ #define SETTING_IP_EXTRA 08 /**< IPv4 additional settings */
#define SETTING_HOST 09 /**< Host identity settings */ #define SETTING_BOOT 09 /**< Generic boot settings */
#define SETTING_HOST_EXTRA 10 /**< Host identity additional settings */ #define SETTING_BOOT_EXTRA 10 /**< Generic boot additional settings */
#define SETTING_AUTH 11 /**< Authentication settings */ #define SETTING_SANBOOT 11 /**< SAN boot settings */
#define SETTING_AUTH_EXTRA 12 /**< Authentication additional settings */ #define SETTING_SANBOOT_EXTRA 12 /**< SAN boot additional settings */
#define SETTING_CRYPTO 13 /**< Cryptography settings */ #define SETTING_HOST 13 /**< Host identity settings */
#define SETTING_MISC 14 /**< Miscellaneous settings */ #define SETTING_HOST_EXTRA 14 /**< Host identity additional settings */
#define SETTING_AUTH 15 /**< Authentication settings */
#define SETTING_AUTH_EXTRA 16 /**< Authentication additional settings */
#define SETTING_CRYPTO 17 /**< Cryptography settings */
#define SETTING_MISC 18 /**< Miscellaneous settings */
/** @} */ /** @} */
@ -140,6 +144,8 @@ struct settings {
struct settings_operations *op; struct settings_operations *op;
/** Default scope for numerical settings constructed for this block */ /** Default scope for numerical settings constructed for this block */
const struct settings_scope *default_scope; const struct settings_scope *default_scope;
/** Sibling ordering */
int order;
}; };
/** /**
@ -280,7 +286,10 @@ struct builtin_setting {
extern const struct settings_scope builtin_scope; extern const struct settings_scope builtin_scope;
/** IPv6 setting scope */ /** IPv6 setting scope */
extern const struct settings_scope ipv6_scope; extern const struct settings_scope ipv6_settings_scope;
/** DHCPv6 setting scope */
extern const struct settings_scope dhcpv6_scope;
/** /**
* A generic settings block * A generic settings block
@ -421,13 +430,19 @@ extern const struct setting_type setting_type_busdevfn __setting_type;
extern const struct setting_type setting_type_dnssl __setting_type; extern const struct setting_type setting_type_dnssl __setting_type;
extern const struct setting extern const struct setting
ip_setting __setting ( SETTING_IP, ip ); ip_setting __setting ( SETTING_IP4, ip );
extern const struct setting extern const struct setting
netmask_setting __setting ( SETTING_IP, netmask ); netmask_setting __setting ( SETTING_IP4, netmask );
extern const struct setting extern const struct setting
gateway_setting __setting ( SETTING_IP, gateway ); gateway_setting __setting ( SETTING_IP4, gateway );
extern const struct setting extern const struct setting
dns_setting __setting ( SETTING_IP_EXTRA, dns ); dns_setting __setting ( SETTING_IP4_EXTRA, dns );
extern const struct setting
ip6_setting __setting ( SETTING_IP6, ip6 );
extern const struct setting
len6_setting __setting ( SETTING_IP6, len6 );
extern const struct setting
gateway6_setting __setting ( SETTING_IP6, gateway6 );
extern const struct setting extern const struct setting
hostname_setting __setting ( SETTING_HOST, hostname ); hostname_setting __setting ( SETTING_HOST, hostname );
extern const struct setting extern const struct setting

View File

@ -1121,6 +1121,7 @@ static int vmbus_probe_channels ( struct hv_hypervisor *hv,
const struct vmbus_message_header *header = &vmbus->message->header; const struct vmbus_message_header *header = &vmbus->message->header;
const struct vmbus_offer_channel *offer = &vmbus->message->offer; const struct vmbus_offer_channel *offer = &vmbus->message->offer;
const union uuid *type; const union uuid *type;
union uuid instance;
struct vmbus_driver *driver; struct vmbus_driver *driver;
struct vmbus_device *vmdev; struct vmbus_device *vmdev;
struct vmbus_device *tmp; struct vmbus_device *tmp;
@ -1165,8 +1166,11 @@ static int vmbus_probe_channels ( struct hv_hypervisor *hv,
rc = -ENOMEM; rc = -ENOMEM;
goto err_alloc_vmdev; goto err_alloc_vmdev;
} }
memcpy ( &instance, &offer->instance,
sizeof ( instance ) );
uuid_mangle ( &instance );
snprintf ( vmdev->dev.name, sizeof ( vmdev->dev.name ), snprintf ( vmdev->dev.name, sizeof ( vmdev->dev.name ),
"vmbus:%02x", channel ); "{%s}", uuid_ntoa ( &instance ) );
vmdev->dev.desc.bus_type = BUS_TYPE_HV; vmdev->dev.desc.bus_type = BUS_TYPE_HV;
INIT_LIST_HEAD ( &vmdev->dev.children ); INIT_LIST_HEAD ( &vmdev->dev.children );
list_add_tail ( &vmdev->dev.siblings, list_add_tail ( &vmdev->dev.siblings,

View File

@ -788,7 +788,7 @@ int format_ipv4_setting ( const struct setting_type *type __unused,
} }
/** IPv4 address setting */ /** IPv4 address setting */
const struct setting ip_setting __setting ( SETTING_IP, ip ) = { const struct setting ip_setting __setting ( SETTING_IP4, ip ) = {
.name = "ip", .name = "ip",
.description = "IP address", .description = "IP address",
.tag = DHCP_EB_YIADDR, .tag = DHCP_EB_YIADDR,
@ -796,7 +796,7 @@ const struct setting ip_setting __setting ( SETTING_IP, ip ) = {
}; };
/** IPv4 subnet mask setting */ /** IPv4 subnet mask setting */
const struct setting netmask_setting __setting ( SETTING_IP, netmask ) = { const struct setting netmask_setting __setting ( SETTING_IP4, netmask ) = {
.name = "netmask", .name = "netmask",
.description = "Subnet mask", .description = "Subnet mask",
.tag = DHCP_SUBNET_MASK, .tag = DHCP_SUBNET_MASK,
@ -804,7 +804,7 @@ const struct setting netmask_setting __setting ( SETTING_IP, netmask ) = {
}; };
/** Default gateway setting */ /** Default gateway setting */
const struct setting gateway_setting __setting ( SETTING_IP, gateway ) = { const struct setting gateway_setting __setting ( SETTING_IP4, gateway ) = {
.name = "gateway", .name = "gateway",
.description = "Default gateway", .description = "Default gateway",
.tag = DHCP_ROUTERS, .tag = DHCP_ROUTERS,

View File

@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
#include <byteswap.h> #include <byteswap.h>
@ -78,6 +79,40 @@ static uint32_t ipv6col ( struct in6_addr *in ) {
return crc32_le ( 0, in, sizeof ( *in ) ); return crc32_le ( 0, in, sizeof ( *in ) );
} }
/**
* Determine IPv6 address scope
*
* @v addr IPv6 address
* @ret scope Address scope
*/
static unsigned int ipv6_scope ( const struct in6_addr *addr ) {
/* Multicast addresses directly include a scope field */
if ( IN6_IS_ADDR_MULTICAST ( addr ) )
return ipv6_multicast_scope ( addr );
/* Link-local addresses have link-local scope */
if ( IN6_IS_ADDR_LINKLOCAL ( addr ) )
return IPV6_SCOPE_LINK_LOCAL;
/* Site-local addresses have site-local scope */
if ( IN6_IS_ADDR_SITELOCAL ( addr ) )
return IPV6_SCOPE_SITE_LOCAL;
/* Unique local addresses do not directly map to a defined
* scope. They effectively have a scope which is wider than
* link-local but narrower than global. Since the only
* multicast packets that we transmit are link-local, we can
* simply choose an arbitrary scope between link-local and
* global.
*/
if ( IN6_IS_ADDR_ULA ( addr ) )
return IPV6_SCOPE_ORGANISATION_LOCAL;
/* All other addresses are assumed to be global */
return IPV6_SCOPE_GLOBAL;
}
/** /**
* Dump IPv6 routing table entry * Dump IPv6 routing table entry
* *
@ -119,23 +154,32 @@ int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr ) {
} }
/** /**
* Check if IPv6 address is within a routing table entry's local network * Count matching bits of an IPv6 routing table entry prefix
* *
* @v miniroute Routing table entry * @v miniroute Routing table entry
* @v address IPv6 address * @v address IPv6 address
* @ret is_on_link Address is within this entry's local network * @ret match_len Number of matching prefix bits
*/ */
static int ipv6_is_on_link ( struct ipv6_miniroute *miniroute, static unsigned int ipv6_match_len ( struct ipv6_miniroute *miniroute,
struct in6_addr *address ) { struct in6_addr *address ) {
unsigned int match_len = 0;
unsigned int i; unsigned int i;
uint32_t diff;
for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) / for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
sizeof ( address->s6_addr32[0] ) ) ; i++ ) { sizeof ( address->s6_addr32[0] ) ) ; i++ ) {
if ( (( address->s6_addr32[i] ^ miniroute->address.s6_addr32[i])
& miniroute->prefix_mask.s6_addr32[i] ) != 0 ) diff = ntohl ( ~( ( ~( address->s6_addr32[i] ^
return 0; miniroute->address.s6_addr32[i] ) )
& miniroute->prefix_mask.s6_addr32[i] ) );
match_len += 32;
if ( diff ) {
match_len -= flsl ( diff );
break;
} }
return 1; }
return match_len;
} }
/** /**
@ -148,13 +192,16 @@ static int ipv6_is_on_link ( struct ipv6_miniroute *miniroute,
static struct ipv6_miniroute * ipv6_miniroute ( struct net_device *netdev, static struct ipv6_miniroute * ipv6_miniroute ( struct net_device *netdev,
struct in6_addr *address ) { struct in6_addr *address ) {
struct ipv6_miniroute *miniroute; struct ipv6_miniroute *miniroute;
unsigned int match_len;
list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) { list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
if ( ( miniroute->netdev == netdev ) && if ( miniroute->netdev != netdev )
ipv6_is_on_link ( miniroute, address ) ) { continue;
match_len = ipv6_match_len ( miniroute, address );
if ( match_len < miniroute->prefix_len )
continue;
return miniroute; return miniroute;
} }
}
return NULL; return NULL;
} }
@ -164,107 +211,89 @@ static struct ipv6_miniroute * ipv6_miniroute ( struct net_device *netdev,
* @v netdev Network device * @v netdev Network device
* @v address IPv6 address (or prefix) * @v address IPv6 address (or prefix)
* @v prefix_len Prefix length * @v prefix_len Prefix length
* @v flags Flags * @v router Router address (if any)
* @ret miniroute Routing table entry, or NULL on failure
*/
static struct ipv6_miniroute * ipv6_add_miniroute ( struct net_device *netdev,
struct in6_addr *address,
unsigned int prefix_len,
unsigned int flags ) {
struct ipv6_miniroute *miniroute;
uint8_t *prefix_mask;
/* Create routing table entry */
miniroute = zalloc ( sizeof ( *miniroute ) );
if ( ! miniroute )
return NULL;
miniroute->netdev = netdev_get ( netdev );
memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
miniroute->prefix_len = prefix_len;
assert ( prefix_len <= ( 8 * sizeof ( miniroute->prefix_mask ) ) );
for ( prefix_mask = miniroute->prefix_mask.s6_addr ; prefix_len >= 8 ;
prefix_mask++, prefix_len -= 8 ) {
*prefix_mask = 0xff;
}
if ( prefix_len )
*prefix_mask <<= ( 8 - prefix_len );
miniroute->flags = flags;
list_add ( &miniroute->list, &ipv6_miniroutes );
ipv6_dump_miniroute ( miniroute );
return miniroute;
}
/**
* Define IPv6 on-link prefix
*
* @v netdev Network device
* @v prefix IPv6 address prefix
* @v prefix_len Prefix length
* @v router Router address (or NULL)
* @ret rc Return status code * @ret rc Return status code
*/ */
int ipv6_set_prefix ( struct net_device *netdev, struct in6_addr *prefix, int ipv6_add_miniroute ( struct net_device *netdev, struct in6_addr *address,
unsigned int prefix_len, struct in6_addr *router ) { unsigned int prefix_len, struct in6_addr *router ) {
struct ipv6_miniroute *miniroute; struct ipv6_miniroute *miniroute;
int changed; uint8_t *prefix_mask;
unsigned int remaining;
unsigned int i;
/* Find or create routing table entry */ /* Find or create routing table entry */
miniroute = ipv6_miniroute ( netdev, prefix ); miniroute = ipv6_miniroute ( netdev, address );
if ( ! miniroute ) if ( miniroute ) {
miniroute = ipv6_add_miniroute ( netdev, prefix, prefix_len, 0);
/* Remove from existing position in routing table */
list_del ( &miniroute->list );
} else {
/* Create new routing table entry */
miniroute = zalloc ( sizeof ( *miniroute ) );
if ( ! miniroute ) if ( ! miniroute )
return -ENOMEM; return -ENOMEM;
miniroute->netdev = netdev_get ( netdev );
memcpy ( &miniroute->address, address,
sizeof ( miniroute->address ) );
/* Record router and add to start or end of list as appropriate */ /* Default to prefix length of 64 if none specified */
list_del ( &miniroute->list ); if ( ! prefix_len )
prefix_len = IPV6_DEFAULT_PREFIX_LEN;
miniroute->prefix_len = prefix_len;
assert ( prefix_len <= IPV6_MAX_PREFIX_LEN );
/* Construct prefix mask */
remaining = prefix_len;
for ( prefix_mask = miniroute->prefix_mask.s6_addr ;
remaining >= 8 ; prefix_mask++, remaining -= 8 ) {
*prefix_mask = 0xff;
}
if ( remaining )
*prefix_mask <<= ( 8 - remaining );
}
/* Add to start of routing table */
list_add ( &miniroute->list, &ipv6_miniroutes );
/* Set or update address, if applicable */
for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
sizeof ( address->s6_addr32[0] ) ) ; i++ ) {
if ( ( address->s6_addr32[i] &
~miniroute->prefix_mask.s6_addr32[i] ) != 0 ) {
memcpy ( &miniroute->address, address,
sizeof ( miniroute->address ) );
miniroute->flags |= IPV6_HAS_ADDRESS;
}
}
if ( miniroute->prefix_len == IPV6_MAX_PREFIX_LEN )
miniroute->flags |= IPV6_HAS_ADDRESS;
/* Update scope */
miniroute->scope = ipv6_scope ( &miniroute->address );
/* Set or update router, if applicable */
if ( router ) { if ( router ) {
changed = ( ( ! ( miniroute->flags & IPV6_HAS_ROUTER ) ) ||
( memcmp ( &miniroute->router, router,
sizeof ( miniroute->router ) ) != 0 ) );
miniroute->flags |= IPV6_HAS_ROUTER;
memcpy ( &miniroute->router, router, memcpy ( &miniroute->router, router,
sizeof ( miniroute->router ) ); sizeof ( miniroute->router ) );
list_add_tail ( &miniroute->list, &ipv6_miniroutes ); miniroute->flags |= IPV6_HAS_ROUTER;
} else {
changed = ( miniroute->flags & IPV6_HAS_ROUTER );
miniroute->flags &= ~IPV6_HAS_ROUTER;
list_add ( &miniroute->list, &ipv6_miniroutes );
} }
if ( changed )
ipv6_dump_miniroute ( miniroute );
ipv6_dump_miniroute ( miniroute );
return 0; return 0;
} }
/** /**
* Add IPv6 on-link address * Delete IPv6 minirouting table entry
* *
* @v netdev Network device * @v miniroute Routing table entry
* @v address IPv6 address
* @ret rc Return status code
*
* An on-link prefix for the address must already exist.
*/ */
int ipv6_set_address ( struct net_device *netdev, struct in6_addr *address ) { void ipv6_del_miniroute ( struct ipv6_miniroute *miniroute ) {
struct ipv6_miniroute *miniroute;
int changed;
/* Find routing table entry */ netdev_put ( miniroute->netdev );
miniroute = ipv6_miniroute ( netdev, address ); list_del ( &miniroute->list );
if ( ! miniroute ) free ( miniroute );
return -EADDRNOTAVAIL;
/* Record address */
changed = ( ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) ) ||
( memcmp ( &miniroute->address, address,
sizeof ( miniroute->address ) ) != 0 ) );
memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
miniroute->flags |= IPV6_HAS_ADDRESS;
if ( changed )
ipv6_dump_miniroute ( miniroute );
return 0;
} }
/** /**
@ -275,9 +304,17 @@ int ipv6_set_address ( struct net_device *netdev, struct in6_addr *address ) {
* @ret dest Next hop destination address * @ret dest Next hop destination address
* @ret miniroute Routing table entry to use, or NULL if no route * @ret miniroute Routing table entry to use, or NULL if no route
*/ */
static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id, struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
struct in6_addr **dest ) { struct in6_addr **dest ) {
struct ipv6_miniroute *miniroute; struct ipv6_miniroute *miniroute;
struct ipv6_miniroute *chosen = NULL;
unsigned int best = 0;
unsigned int match_len;
unsigned int score;
unsigned int scope;
/* Calculate destination address scope */
scope = ipv6_scope ( *dest );
/* Find first usable route in routing table */ /* Find first usable route in routing table */
list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) { list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
@ -286,35 +323,52 @@ static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
if ( ! netdev_is_open ( miniroute->netdev ) ) if ( ! netdev_is_open ( miniroute->netdev ) )
continue; continue;
/* Skip routing table entries with no usable source address */ /* Skip entries with no usable source address */
if ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) ) if ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) )
continue; continue;
if ( IN6_IS_ADDR_NONGLOBAL ( *dest ) ) { /* Skip entries with a non-matching scope ID, if
* destination specifies a scope ID.
/* If destination is non-global, and the scope ID
* matches this network device, then use this route.
*/ */
if ( miniroute->netdev->index == scope_id ) if ( scope_id && ( miniroute->netdev->index != scope_id ) )
continue;
/* Skip entries that are out of scope */
if ( miniroute->scope < scope )
continue;
/* Calculate match length */
match_len = ipv6_match_len ( miniroute, *dest );
/* If destination is on-link, then use this route */
if ( match_len >= miniroute->prefix_len )
return miniroute; return miniroute;
} else { /* If destination is unicast, then skip off-link
* entries with no router.
/* If destination is an on-link global
* address, then use this route.
*/ */
if ( ipv6_is_on_link ( miniroute, *dest ) ) if ( ! ( IN6_IS_ADDR_MULTICAST ( *dest ) ||
return miniroute; ( miniroute->flags & IPV6_HAS_ROUTER ) ) )
continue;
/* If destination is an off-link global /* Choose best route, defined as being the route with
* address, and we have a default gateway, * the smallest viable scope. If two routes both have
* then use this route. * the same scope, then prefer the route with the
* longest match length.
*/ */
if ( miniroute->flags & IPV6_HAS_ROUTER ) { score = ( ( ( IPV6_SCOPE_MAX + 1 - miniroute->scope ) << 8 )
*dest = &miniroute->router; + match_len );
return miniroute; if ( score > best ) {
chosen = miniroute;
best = score;
} }
} }
/* Return chosen route, if any */
if ( chosen ) {
if ( ! IN6_IS_ADDR_MULTICAST ( *dest ) )
*dest = &chosen->router;
return chosen;
} }
return NULL; return NULL;
@ -902,7 +956,7 @@ static const char * ipv6_sock_ntoa ( struct sockaddr *sa ) {
const char *netdev_name; const char *netdev_name;
/* Identify network device, if applicable */ /* Identify network device, if applicable */
if ( IN6_IS_ADDR_NONGLOBAL ( in ) ) { if ( IN6_IS_ADDR_LINKLOCAL ( in ) || IN6_IS_ADDR_MULTICAST ( in ) ) {
netdev = find_netdev_by_index ( sin6->sin6_scope_id ); netdev = find_netdev_by_index ( sin6->sin6_scope_id );
netdev_name = ( netdev ? netdev->name : "UNKNOWN" ); netdev_name = ( netdev ? netdev->name : "UNKNOWN" );
} else { } else {
@ -968,7 +1022,8 @@ static int ipv6_sock_aton ( const char *string, struct sockaddr *sa ) {
} }
sin6->sin6_scope_id = netdev->index; sin6->sin6_scope_id = netdev->index;
} else if ( IN6_IS_ADDR_NONGLOBAL ( &in ) ) { } else if ( IN6_IS_ADDR_LINKLOCAL ( &in ) ||
IN6_IS_ADDR_MULTICAST ( &in ) ) {
/* If no network device is explicitly specified for a /* If no network device is explicitly specified for a
* link-local or multicast address, default to using * link-local or multicast address, default to using
@ -1061,61 +1116,235 @@ int format_ipv6_setting ( const struct setting_type *type __unused,
return snprintf ( buf, len, "%s", inet6_ntoa ( ipv6 ) ); return snprintf ( buf, len, "%s", inet6_ntoa ( ipv6 ) );
} }
/** IPv6 settings scope */
const struct settings_scope ipv6_settings_scope;
/** IPv6 address setting */
const struct setting ip6_setting __setting ( SETTING_IP6, ip6 ) = {
.name = "ip6",
.description = "IPv6 address",
.type = &setting_type_ipv6,
.scope = &ipv6_settings_scope,
};
/** IPv6 prefix length setting */
const struct setting len6_setting __setting ( SETTING_IP6, len6 ) = {
.name = "len6",
.description = "IPv6 prefix length",
.type = &setting_type_int8,
.scope = &ipv6_settings_scope,
};
/** Default gateway setting */
const struct setting gateway6_setting __setting ( SETTING_IP6, gateway6 ) = {
.name = "gateway6",
.description = "IPv6 gateway",
.type = &setting_type_ipv6,
.scope = &ipv6_settings_scope,
};
/** /**
* Create IPv6 network device * Check applicability of IPv6 link-local address setting
* *
* @v netdev Network device * @v settings Settings block
* @ret rc Return status code * @v setting Setting to fetch
* @ret applies Setting applies within this settings block
*/ */
static int ipv6_probe ( struct net_device *netdev ) { static int ipv6_applies ( struct settings *settings __unused,
struct ipv6_miniroute *miniroute; const struct setting *setting ) {
struct in6_addr address;
return ( setting->scope == &ipv6_settings_scope );
}
/**
* Fetch IPv6 link-local address setting
*
* @v settings Settings block
* @v setting Setting to fetch
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int ipv6_fetch ( struct settings *settings, struct setting *setting,
void *data, size_t len ) {
struct net_device *netdev =
container_of ( settings->parent, struct net_device,
settings.settings );
struct in6_addr ip6;
uint8_t *len6;
int prefix_len; int prefix_len;
int rc; int rc;
/* Construct link-local address from EUI-64 as per RFC 2464 */ /* Construct link-local address from EUI-64 as per RFC 2464 */
memset ( &address, 0, sizeof ( address ) ); memset ( &ip6, 0, sizeof ( ip6 ) );
prefix_len = ipv6_link_local ( &address, netdev ); prefix_len = ipv6_link_local ( &ip6, netdev );
if ( prefix_len < 0 ) { if ( prefix_len < 0 ) {
rc = prefix_len; rc = prefix_len;
DBGC ( netdev, "IPv6 %s could not construct link-local "
"address: %s\n", netdev->name, strerror ( rc ) );
return rc; return rc;
} }
/* Create link-local address for this network device */ /* Handle setting */
miniroute = ipv6_add_miniroute ( netdev, &address, prefix_len, if ( setting_cmp ( setting, &ip6_setting ) == 0 ) {
IPV6_HAS_ADDRESS );
if ( ! miniroute )
return -ENOMEM;
return 0; /* Return link-local ip6 */
if ( len > sizeof ( ip6 ) )
len = sizeof ( ip6 );
memcpy ( data, &ip6, len );
return sizeof ( ip6 );
} else if ( setting_cmp ( setting, &len6_setting ) == 0 ) {
/* Return prefix length */
if ( len ) {
len6 = data;
*len6 = prefix_len;
}
return sizeof ( *len6 );
}
return -ENOENT;
} }
/** IPv6 link-local address settings operations */
static struct settings_operations ipv6_settings_operations = {
.applies = ipv6_applies,
.fetch = ipv6_fetch,
};
/** IPv6 link-local address settings */
struct ipv6_settings {
/** Reference counter */
struct refcnt refcnt;
/** Settings interface */
struct settings settings;
};
/** /**
* Destroy IPv6 network device * Register IPv6 link-local address settings
* *
* @v netdev Network device * @v netdev Network device
* @ret rc Return status code
*/ */
static void ipv6_remove ( struct net_device *netdev ) { static int ipv6_register_settings ( struct net_device *netdev ) {
struct ipv6_miniroute *miniroute; struct settings *parent = netdev_settings ( netdev );
struct ipv6_miniroute *tmp; struct ipv6_settings *ipv6set;
int rc;
/* Delete all miniroutes for this network device */ /* Allocate and initialise structure */
list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) { ipv6set = zalloc ( sizeof ( *ipv6set ) );
if ( miniroute->netdev == netdev ) { if ( ! ipv6set ) {
netdev_put ( miniroute->netdev ); rc = -ENOMEM;
list_del ( &miniroute->list ); goto err_alloc;
free ( miniroute );
}
} }
ref_init ( &ipv6set->refcnt, NULL );
settings_init ( &ipv6set->settings, &ipv6_settings_operations,
&ipv6set->refcnt, &ipv6_settings_scope );
ipv6set->settings.order = IPV6_ORDER_LINK_LOCAL;
/* Register settings */
if ( ( rc = register_settings ( &ipv6set->settings, parent,
IPV6_SETTINGS_NAME ) ) != 0 )
goto err_register;
err_register:
ref_put ( &ipv6set->refcnt );
err_alloc:
return rc;
} }
/** IPv6 network device driver */ /** IPv6 network device driver */
struct net_driver ipv6_driver __net_driver = { struct net_driver ipv6_driver __net_driver = {
.name = "IPv6", .name = "IPv6",
.probe = ipv6_probe, .probe = ipv6_register_settings,
.remove = ipv6_remove, };
/**
* Create IPv6 routing table based on configured settings
*
* @v netdev Network device
* @v settings Settings block
* @ret rc Return status code
*/
static int ipv6_create_routes ( struct net_device *netdev,
struct settings *settings ) {
struct settings *child;
struct settings *origin;
struct in6_addr ip6_buf;
struct in6_addr gateway6_buf;
struct in6_addr *ip6 = &ip6_buf;
struct in6_addr *gateway6 = &gateway6_buf;
uint8_t len6;
size_t len;
int rc;
/* First, create routing table for any child settings. We do
* this depth-first and in reverse order so that the end
* result reflects the relative priorities of the settings
* blocks.
*/
list_for_each_entry_reverse ( child, &settings->children, siblings )
ipv6_create_routes ( netdev, child );
/* Fetch IPv6 address, if any */
len = fetch_setting ( settings, &ip6_setting, &origin, NULL,
ip6, sizeof ( *ip6 ) );
if ( ( len != sizeof ( *ip6 ) ) || ( origin != settings ) )
return 0;
/* Fetch prefix length, if defined */
len = fetch_setting ( settings, &len6_setting, &origin, NULL,
&len6, sizeof ( len6 ) );
if ( ( len != sizeof ( len6 ) ) || ( origin != settings ) )
len6 = 0;
if ( len6 > IPV6_MAX_PREFIX_LEN )
len6 = IPV6_MAX_PREFIX_LEN;
/* Fetch gateway, if defined */
len = fetch_setting ( settings, &gateway6_setting, &origin, NULL,
gateway6, sizeof ( *gateway6 ) );
if ( ( len != sizeof ( *gateway6 ) ) || ( origin != settings ) )
gateway6 = NULL;
/* Create or update route */
if ( ( rc = ipv6_add_miniroute ( netdev, ip6, len6, gateway6 ) ) != 0){
DBGC ( netdev, "IPv6 %s could not add route: %s\n",
netdev->name, strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Create IPv6 routing table based on configured settings
*
* @ret rc Return status code
*/
static int ipv6_create_all_routes ( void ) {
struct ipv6_miniroute *miniroute;
struct ipv6_miniroute *tmp;
struct net_device *netdev;
struct settings *settings;
int rc;
/* Delete all existing routes */
list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list )
ipv6_del_miniroute ( miniroute );
/* Create routes for each configured network device */
for_each_netdev ( netdev ) {
settings = netdev_settings ( netdev );
if ( ( rc = ipv6_create_routes ( netdev, settings ) ) != 0 )
return rc;
}
return 0;
}
/** IPv6 settings applicator */
struct settings_applicator ipv6_settings_applicator __settings_applicator = {
.apply = ipv6_create_all_routes,
}; };
/* Drag in objects via ipv6_protocol */ /* Drag in objects via ipv6_protocol */

View File

@ -20,6 +20,7 @@
FILE_LICENCE ( GPL2_OR_LATER ); FILE_LICENCE ( GPL2_OR_LATER );
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <byteswap.h> #include <byteswap.h>
@ -41,6 +42,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
static struct ipv6conf * ipv6conf_demux ( struct net_device *netdev ); static struct ipv6conf * ipv6conf_demux ( struct net_device *netdev );
static int static int
ipv6conf_rx_router_advertisement ( struct net_device *netdev, ipv6conf_rx_router_advertisement ( struct net_device *netdev,
struct in6_addr *router,
struct ndp_router_advertisement_header *radv, struct ndp_router_advertisement_header *radv,
size_t len ); size_t len );
@ -340,11 +342,6 @@ ndp_rx_router_advertisement_prefix ( struct net_device *netdev,
union ndp_option *option, size_t len ) { union ndp_option *option, size_t len ) {
struct ndp_router_advertisement_header *radv = &ndp->radv; struct ndp_router_advertisement_header *radv = &ndp->radv;
struct ndp_prefix_information_option *prefix_opt = &option->prefix; struct ndp_prefix_information_option *prefix_opt = &option->prefix;
struct in6_addr *router = &sin6_src->sin6_addr;
struct in6_addr address;
struct ipv6conf *ipv6conf;
int prefix_len;
int rc;
/* Sanity check */ /* Sanity check */
if ( sizeof ( *prefix_opt ) > len ) { if ( sizeof ( *prefix_opt ) > len ) {
@ -353,59 +350,13 @@ ndp_rx_router_advertisement_prefix ( struct net_device *netdev,
return -EINVAL; return -EINVAL;
} }
/* Identify IPv6 configurator, if any */
ipv6conf = ipv6conf_demux ( netdev );
DBGC ( netdev, "NDP %s found %sdefault router %s ", DBGC ( netdev, "NDP %s found %sdefault router %s ",
netdev->name, ( radv->lifetime ? "" : "non-" ), netdev->name, ( radv->lifetime ? "" : "non-" ),
inet6_ntoa ( &sin6_src->sin6_addr ) ); inet6_ntoa ( &sin6_src->sin6_addr ) );
DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d%s\n", DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d\n",
( ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) ? "on" : "off" ), ( ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) ? "on" : "off" ),
( ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) ? "" : "non-" ), ( ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) ? "" : "non-" ),
inet6_ntoa ( &prefix_opt->prefix ), inet6_ntoa ( &prefix_opt->prefix ), prefix_opt->prefix_len );
prefix_opt->prefix_len, ( ipv6conf ? "" : " (ignored)" ) );
/* Do nothing unless IPv6 autoconfiguration is in progress */
if ( ! ipv6conf )
return 0;
/* Ignore off-link prefixes */
if ( ! ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) )
return 0;
/* Define prefix */
if ( ( rc = ipv6_set_prefix ( netdev, &prefix_opt->prefix,
prefix_opt->prefix_len,
( radv->lifetime ?
router : NULL ) ) ) != 0 ) {
DBGC ( netdev, "NDP %s could not define prefix %s/%d: %s\n",
netdev->name, inet6_ntoa ( &prefix_opt->prefix ),
prefix_opt->prefix_len, strerror ( rc ) );
return rc;
}
/* Perform stateless address autoconfiguration, if applicable */
if ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) {
memcpy ( &address, &prefix_opt->prefix, sizeof ( address ) );
prefix_len = ipv6_eui64 ( &address, netdev );
if ( prefix_len < 0 ) {
rc = prefix_len;
DBGC ( netdev, "NDP %s could not construct SLAAC "
"address: %s\n", netdev->name, strerror ( rc ) );
return rc;
}
if ( prefix_len != prefix_opt->prefix_len ) {
DBGC ( netdev, "NDP %s incorrect SLAAC prefix length "
"%d (expected %d)\n", netdev->name,
prefix_opt->prefix_len, prefix_len );
return -EINVAL;
}
if ( ( rc = ipv6_set_address ( netdev, &address ) ) != 0 ) {
DBGC ( netdev, "NDP %s could not set address %s: %s\n",
netdev->name, inet6_ntoa ( &address ),
strerror ( rc ) );
return rc;
}
}
return 0; return 0;
} }
@ -585,6 +536,7 @@ ndp_rx_router_advertisement ( struct io_buffer *iobuf,
struct sockaddr_in6 *sin6_dest __unused ) { struct sockaddr_in6 *sin6_dest __unused ) {
union ndp_header *ndp = iobuf->data; union ndp_header *ndp = iobuf->data;
struct ndp_router_advertisement_header *radv = &ndp->radv; struct ndp_router_advertisement_header *radv = &ndp->radv;
struct in6_addr *router = &sin6_src->sin6_addr;
size_t len = iob_len ( iobuf ); size_t len = iob_len ( iobuf );
int rc; int rc;
@ -595,8 +547,8 @@ ndp_rx_router_advertisement ( struct io_buffer *iobuf,
goto err_options; goto err_options;
/* Pass to IPv6 autoconfiguration */ /* Pass to IPv6 autoconfiguration */
if ( ( rc = ipv6conf_rx_router_advertisement ( netdev, radv, if ( ( rc = ipv6conf_rx_router_advertisement ( netdev, router,
len ) ) != 0 ) radv, len ) ) != 0 )
goto err_ipv6conf; goto err_ipv6conf;
err_ipv6conf: err_ipv6conf:
@ -627,16 +579,30 @@ struct icmpv6_handler ndp_handlers[] __icmpv6_handler = {
* *
*/ */
/** An NDP prefix settings block */
struct ndp_prefix_settings {
/** Settings interface */
struct settings settings;
/** Name */
char name[4];
/** Prefix information option */
struct ndp_prefix_information_option *prefix;
};
/** An NDP settings block */ /** An NDP settings block */
struct ndp_settings { struct ndp_settings {
/** Reference counter */ /** Reference counter */
struct refcnt refcnt; struct refcnt refcnt;
/** Settings interface */ /** Settings interface */
struct settings settings; struct settings settings;
/** Router address */
struct in6_addr router;
/** Router lifetime */
unsigned int lifetime;
/** 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 +613,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 +625,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 +633,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 +682,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;
@ -747,22 +745,218 @@ static struct settings_operations ndp_settings_operations = {
.fetch = ndp_fetch, .fetch = ndp_fetch,
}; };
/**
* Check applicability of NDP per-prefix setting
*
* @v settings Settings block
* @v setting Setting to fetch
* @ret applies Setting applies within this settings block
*/
static int ndp_prefix_applies ( struct settings *settings __unused,
const struct setting *setting ) {
return ( setting->scope == &ipv6_settings_scope );
}
/**
* Fetch value of NDP IPv6 address setting
*
* @v settings Settings block
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int ndp_prefix_fetch_ip6 ( struct settings *settings, void *data,
size_t len ) {
struct ndp_prefix_settings *prefset =
container_of ( settings, struct ndp_prefix_settings, settings );
struct ndp_settings *ndpset =
container_of ( settings->parent, struct ndp_settings, settings);
struct net_device *netdev =
container_of ( ndpset->settings.parent, struct net_device,
settings.settings );
struct ndp_prefix_information_option *prefix = prefset->prefix;
struct in6_addr ip6;
int prefix_len;
/* Skip dead prefixes */
if ( ! prefix->valid )
return -ENOENT;
/* Construct IPv6 address via SLAAC, if applicable */
memcpy ( &ip6, &prefix->prefix, sizeof ( ip6 ) );
if ( prefix->flags & NDP_PREFIX_AUTONOMOUS ) {
prefix_len = ipv6_eui64 ( &ip6, netdev );
if ( prefix_len < 0 )
return prefix_len;
if ( prefix_len != prefix->prefix_len )
return -EINVAL;
}
/* Fill in IPv6 address */
if ( len > sizeof ( ip6 ) )
len = sizeof ( ip6 );
memcpy ( data, &ip6, len );
return sizeof ( ip6 );
}
/**
* Fetch value of NDP prefix length setting
*
* @v settings Settings block
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int ndp_prefix_fetch_len6 ( struct settings *settings, void *data,
size_t len ) {
struct ndp_prefix_settings *prefset =
container_of ( settings, struct ndp_prefix_settings, settings );
struct ndp_prefix_information_option *prefix = prefset->prefix;
uint8_t *len6;
/* Fill in prefix length */
if ( len >= sizeof ( *len6 ) ) {
/* We treat an off-link prefix as having a prefix
* length covering the entire IPv6 address.
*/
len6 = data;
*len6 = ( ( prefix->flags & NDP_PREFIX_ON_LINK ) ?
prefix->prefix_len : -1UL );
}
return sizeof ( *len6 );
}
/**
* Fetch value of NDP router address setting
*
* @v settings Settings block
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int ndp_prefix_fetch_gateway6 ( struct settings *settings,
void *data, size_t len ) {
struct ndp_settings *ndpset =
container_of ( settings->parent, struct ndp_settings, settings);
/* Treat non-routing router as non-existent */
if ( ! ndpset->lifetime )
return -ENOENT;
/* Fill in router address */
if ( len > sizeof ( ndpset->router ) )
len = sizeof ( ndpset->router );
memcpy ( data, &ndpset->router, len );
return sizeof ( ndpset->router );
}
/** An NDP per-prefix setting operation */
struct ndp_prefix_operation {
/** Generic setting */
const struct setting *setting;
/**
* Fetch value of setting
*
* @v settings Settings block
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
int ( * fetch ) ( struct settings *settings, void *data, size_t len );
};
/** NDP per-prefix settings operations */
static struct ndp_prefix_operation ndp_prefix_operations[] = {
{ &ip6_setting, ndp_prefix_fetch_ip6 },
{ &len6_setting, ndp_prefix_fetch_len6 },
{ &gateway6_setting, ndp_prefix_fetch_gateway6 },
};
/**
* Fetch value of NDP pre-prefix setting
*
* @v settings Settings block
* @v setting Setting to fetch
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int ndp_prefix_fetch ( struct settings *settings,
struct setting *setting,
void *data, size_t len ) {
struct ndp_prefix_operation *op;
unsigned int i;
/* Handle per-prefix settings */
for ( i = 0 ; i < ( sizeof ( ndp_prefix_operations ) /
sizeof ( ndp_prefix_operations[0] ) ) ; i++ ) {
op = &ndp_prefix_operations[i];
if ( setting_cmp ( setting, op->setting ) == 0 )
return op->fetch ( settings, data, len );
}
return -ENOENT;
}
/** NDP per-prefix settings operations */
static struct settings_operations ndp_prefix_settings_operations = {
.applies = ndp_prefix_applies,
.fetch = ndp_prefix_fetch,
};
/** /**
* Register NDP settings * Register NDP settings
* *
* @v netdev Network device * @v netdev Network device
* @v option NDP options * @v router Router address
* @v lifetime Router lifetime
* @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 ) { struct in6_addr *router,
unsigned int lifetime,
union ndp_option *options, size_t len ) {
struct settings *parent = netdev_settings ( netdev ); struct settings *parent = netdev_settings ( netdev );
union ndp_option *option;
struct ndp_settings *ndpset; struct ndp_settings *ndpset;
struct ndp_prefix_settings *prefset;
size_t offset;
size_t option_len;
unsigned int prefixes;
unsigned int instance;
int order;
int rc; int rc;
/* Count number of prefix options. We can assume that the
* options are well-formed, otherwise they would have been
* rejected prior to being stored.
*/
order = IPV6_ORDER_PREFIX_ONLY;
for ( prefixes = 0, offset = 0 ; offset < len ; offset += option_len ) {
/* Skip non-prefix options */
option = ( ( ( void * ) options ) + offset );
option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
if ( option->header.type != NDP_OPT_PREFIX )
continue;
/* Count number of prefixes */
prefixes++;
/* Increase overall order if we have SLAAC addresses */
if ( option->prefix.flags & NDP_PREFIX_AUTONOMOUS )
order = IPV6_ORDER_SLAAC;
}
/* Allocate and initialise structure */ /* Allocate and initialise structure */
ndpset = zalloc ( sizeof ( *ndpset ) + len ); ndpset = zalloc ( sizeof ( *ndpset ) + len +
( prefixes * sizeof ( *prefset ) ) );
if ( ! ndpset ) { if ( ! ndpset ) {
rc = -ENOMEM; rc = -ENOMEM;
goto err_alloc; goto err_alloc;
@ -770,14 +964,54 @@ static int ndp_register_settings ( struct net_device *netdev,
ref_init ( &ndpset->refcnt, NULL ); ref_init ( &ndpset->refcnt, NULL );
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->settings.order = order;
memcpy ( &ndpset->router, router, sizeof ( ndpset->router ) );
ndpset->lifetime = lifetime;
ndpset->len = len; ndpset->len = len;
memcpy ( ndpset->option, option, len ); memcpy ( ndpset->options, options, len );
prefset = ( ( ( void * ) ndpset->options ) + len );
/* Register settings */ /* Register settings */
if ( ( rc = register_settings ( &ndpset->settings, parent, if ( ( rc = register_settings ( &ndpset->settings, parent,
NDP_SETTINGS_NAME ) ) != 0 ) NDP_SETTINGS_NAME ) ) != 0 )
goto err_register; goto err_register;
/* Construct and register per-prefix settings */
for ( instance = 0, offset = 0 ; offset < len ; offset += option_len ) {
/* Skip non-prefix options */
option = ( ( ( void * ) ndpset->options ) + offset );
option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
if ( option->header.type != NDP_OPT_PREFIX )
continue;
/* Initialise structure */
settings_init ( &prefset->settings,
&ndp_prefix_settings_operations,
&ndpset->refcnt, &ndp_settings_scope );
prefset->settings.order =
( ( option->prefix.flags & NDP_PREFIX_AUTONOMOUS ) ?
IPV6_ORDER_SLAAC : IPV6_ORDER_PREFIX_ONLY );
prefset->prefix = &option->prefix;
snprintf ( prefset->name, sizeof ( prefset->name ), "%d",
instance++ );
/* Register settings */
if ( ( rc = register_settings ( &prefset->settings,
&ndpset->settings,
prefset->name ) ) != 0 )
goto err_register_prefix;
/* Move to next per-prefix settings */
prefset++;
}
assert ( instance == prefixes );
ref_put ( &ndpset->refcnt );
return 0;
err_register_prefix:
unregister_settings ( &ndpset->settings );
err_register: err_register:
ref_put ( &ndpset->refcnt ); ref_put ( &ndpset->refcnt );
err_alloc: err_alloc:
@ -785,11 +1019,11 @@ static int ndp_register_settings ( struct net_device *netdev,
} }
/** DNS server setting */ /** DNS server setting */
const struct setting ndp_dns6_setting __setting ( SETTING_IP_EXTRA, dns6 ) = { 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 +1033,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,
}; };
@ -906,6 +1140,7 @@ static void ipv6conf_expired ( struct retry_timer *timer, int fail ) {
* Handle router advertisement during IPv6 autoconfiguration * Handle router advertisement during IPv6 autoconfiguration
* *
* @v netdev Network device * @v netdev Network device
* @v router Router address
* @v radv Router advertisement * @v radv Router advertisement
* @v len Length of router advertisement * @v len Length of router advertisement
* @ret rc Return status code * @ret rc Return status code
@ -915,6 +1150,7 @@ static void ipv6conf_expired ( struct retry_timer *timer, int fail ) {
*/ */
static int static int
ipv6conf_rx_router_advertisement ( struct net_device *netdev, ipv6conf_rx_router_advertisement ( struct net_device *netdev,
struct in6_addr *router,
struct ndp_router_advertisement_header *radv, struct ndp_router_advertisement_header *radv,
size_t len ) { size_t len ) {
struct ipv6conf *ipv6conf; struct ipv6conf *ipv6conf;
@ -938,8 +1174,9 @@ ipv6conf_rx_router_advertisement ( struct net_device *netdev,
/* Register NDP settings */ /* Register NDP settings */
option_len = ( len - offsetof ( typeof ( *radv ), option ) ); option_len = ( len - offsetof ( typeof ( *radv ), option ) );
if ( ( rc = ndp_register_settings ( netdev, radv->option, if ( ( rc = ndp_register_settings ( netdev, router,
option_len ) ) != 0 ) ntohl ( radv->lifetime ),
radv->option, option_len ) ) != 0 )
return rc; return rc;
/* Start DHCPv6 if required */ /* Start DHCPv6 if required */

View File

@ -266,6 +266,8 @@ struct dhcpv6_settings {
struct refcnt refcnt; struct refcnt refcnt;
/** Settings block */ /** Settings block */
struct settings settings; struct settings settings;
/** Leased address */
struct in6_addr lease;
/** Option list */ /** Option list */
struct dhcpv6_option_list options; struct dhcpv6_option_list options;
}; };
@ -280,7 +282,32 @@ struct dhcpv6_settings {
static int dhcpv6_applies ( struct settings *settings __unused, static int dhcpv6_applies ( struct settings *settings __unused,
const struct setting *setting ) { const struct setting *setting ) {
return ( setting->scope == &ipv6_scope ); return ( ( setting->scope == &dhcpv6_scope ) ||
( setting_cmp ( setting, &ip6_setting ) == 0 ) );
}
/**
* Fetch value of DHCPv6 leased address
*
* @v dhcpset DHCPv6 settings
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int dhcpv6_fetch_lease ( struct dhcpv6_settings *dhcpv6set,
void *data, size_t len ) {
struct in6_addr *lease = &dhcpv6set->lease;
/* Do nothing unless a leased address exists */
if ( IN6_IS_ADDR_UNSPECIFIED ( lease ) )
return -ENOENT;
/* Copy leased address */
if ( len > sizeof ( *lease ) )
len = sizeof ( *lease );
memcpy ( data, lease, len );
return sizeof ( *lease );
} }
/** /**
@ -300,6 +327,10 @@ static int dhcpv6_fetch ( struct settings *settings,
const union dhcpv6_any_option *option; const union dhcpv6_any_option *option;
size_t option_len; size_t option_len;
/* Handle leased address */
if ( setting_cmp ( setting, &ip6_setting ) == 0 )
return dhcpv6_fetch_lease ( dhcpv6set, data, len );
/* Find option */ /* Find option */
option = dhcpv6_option ( &dhcpv6set->options, setting->tag ); option = dhcpv6_option ( &dhcpv6set->options, setting->tag );
if ( ! option ) if ( ! option )
@ -322,11 +353,13 @@ static struct settings_operations dhcpv6_settings_operations = {
/** /**
* Register DHCPv6 options as network device settings * Register DHCPv6 options as network device settings
* *
* @v lease DHCPv6 leased address
* @v options DHCPv6 option list * @v options DHCPv6 option list
* @v parent Parent settings block * @v parent Parent settings block
* @ret rc Return status code * @ret rc Return status code
*/ */
static int dhcpv6_register ( struct dhcpv6_option_list *options, static int dhcpv6_register ( struct in6_addr *lease,
struct dhcpv6_option_list *options,
struct settings *parent ) { struct settings *parent ) {
struct dhcpv6_settings *dhcpv6set; struct dhcpv6_settings *dhcpv6set;
void *data; void *data;
@ -341,12 +374,14 @@ static int dhcpv6_register ( struct dhcpv6_option_list *options,
} }
ref_init ( &dhcpv6set->refcnt, NULL ); ref_init ( &dhcpv6set->refcnt, NULL );
settings_init ( &dhcpv6set->settings, &dhcpv6_settings_operations, settings_init ( &dhcpv6set->settings, &dhcpv6_settings_operations,
&dhcpv6set->refcnt, &ipv6_scope ); &dhcpv6set->refcnt, &dhcpv6_scope );
dhcpv6set->settings.order = IPV6_ORDER_DHCPV6;
data = ( ( ( void * ) dhcpv6set ) + sizeof ( *dhcpv6set ) ); data = ( ( ( void * ) dhcpv6set ) + sizeof ( *dhcpv6set ) );
len = options->len; len = options->len;
memcpy ( data, options->data, len ); memcpy ( data, options->data, len );
dhcpv6set->options.data = data; dhcpv6set->options.data = data;
dhcpv6set->options.len = len; dhcpv6set->options.len = len;
memcpy ( &dhcpv6set->lease, lease, sizeof ( dhcpv6set->lease ) );
/* Register settings */ /* Register settings */
if ( ( rc = register_settings ( &dhcpv6set->settings, parent, if ( ( rc = register_settings ( &dhcpv6set->settings, parent,
@ -427,8 +462,6 @@ enum dhcpv6_session_state_flags {
DHCPV6_RX_RECORD_SERVER_ID = 0x04, DHCPV6_RX_RECORD_SERVER_ID = 0x04,
/** Record received IPv6 address */ /** Record received IPv6 address */
DHCPV6_RX_RECORD_IAADDR = 0x08, DHCPV6_RX_RECORD_IAADDR = 0x08,
/** Apply received IPv6 address */
DHCPV6_RX_APPLY_IAADDR = 0x10,
}; };
/** DHCPv6 request state */ /** DHCPv6 request state */
@ -436,7 +469,7 @@ static struct dhcpv6_session_state dhcpv6_request = {
.tx_type = DHCPV6_REQUEST, .tx_type = DHCPV6_REQUEST,
.rx_type = DHCPV6_REPLY, .rx_type = DHCPV6_REPLY,
.flags = ( DHCPV6_TX_IA_NA | DHCPV6_TX_IAADDR | .flags = ( DHCPV6_TX_IA_NA | DHCPV6_TX_IAADDR |
DHCPV6_RX_RECORD_IAADDR | DHCPV6_RX_APPLY_IAADDR ), DHCPV6_RX_RECORD_IAADDR ),
.next = NULL, .next = NULL,
}; };
@ -835,40 +868,24 @@ static int dhcpv6_rx ( struct dhcpv6_session *dhcpv6,
dhcpv6->server_duid_len ); dhcpv6->server_duid_len );
} }
/* Apply identity association address, if applicable */ /* Transition to next state, if applicable */
if ( dhcpv6->state->flags & DHCPV6_RX_APPLY_IAADDR ) {
if ( ( rc = ipv6_set_address ( dhcpv6->netdev,
&dhcpv6->lease ) ) != 0 ) {
DBGC ( dhcpv6, "DHCPv6 %s could not apply %s: %s\n",
dhcpv6->netdev->name,
inet6_ntoa ( &dhcpv6->lease ), strerror ( rc ) );
/* This is plausibly the error we want to return */
dhcpv6->rc = rc;
goto done;
}
}
/* Transition to next state or complete DHCPv6, as applicable */
if ( dhcpv6->state->next ) { if ( dhcpv6->state->next ) {
/* Transition to next state */
dhcpv6_set_state ( dhcpv6, dhcpv6->state->next ); dhcpv6_set_state ( dhcpv6, dhcpv6->state->next );
rc = 0; rc = 0;
goto done;
} else { }
/* Register settings */ /* Register settings */
if ( ( rc = dhcpv6_register ( &options, parent ) ) != 0 ) { if ( ( rc = dhcpv6_register ( &dhcpv6->lease, &options,
DBGC ( dhcpv6, "DHCPv6 %s could not register " parent ) ) != 0 ) {
"settings: %s\n", dhcpv6->netdev->name, DBGC ( dhcpv6, "DHCPv6 %s could not register settings: %s\n",
strerror ( rc ) ); dhcpv6->netdev->name, strerror ( rc ) );
goto done; goto done;
} }
/* Mark as complete */ /* Mark as complete */
dhcpv6_finished ( dhcpv6, 0 ); dhcpv6_finished ( dhcpv6, 0 );
DBGC ( dhcpv6, "DHCPv6 %s complete\n", dhcpv6->netdev->name ); DBGC ( dhcpv6, "DHCPv6 %s complete\n", dhcpv6->netdev->name );
}
done: done:
free_iob ( iobuf ); free_iob ( iobuf );
@ -987,7 +1004,7 @@ const struct setting filename6_setting __setting ( SETTING_BOOT, filename ) = {
.description = "Boot filename", .description = "Boot filename",
.tag = DHCPV6_BOOTFILE_URL, .tag = DHCPV6_BOOTFILE_URL,
.type = &setting_type_string, .type = &setting_type_string,
.scope = &ipv6_scope, .scope = &dhcpv6_scope,
}; };
/** DNS search list setting */ /** DNS search list setting */
@ -996,5 +1013,5 @@ const struct setting dnssl6_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
.description = "DNS search list", .description = "DNS search list",
.tag = DHCPV6_DOMAIN_LIST, .tag = DHCPV6_DOMAIN_LIST,
.type = &setting_type_dnssl, .type = &setting_type_dnssl,
.scope = &ipv6_scope, .scope = &dhcpv6_scope,
}; };

View File

@ -1048,7 +1048,7 @@ const struct setting_type setting_type_dnssl __setting_type = {
}; };
/** IPv4 DNS server setting */ /** IPv4 DNS server setting */
const struct setting dns_setting __setting ( SETTING_IP_EXTRA, dns ) = { const struct setting dns_setting __setting ( SETTING_IP4_EXTRA, dns ) = {
.name = "dns", .name = "dns",
.description = "DNS server", .description = "DNS server",
.tag = DHCP_DNS_SERVERS, .tag = DHCP_DNS_SERVERS,
@ -1056,12 +1056,12 @@ const struct setting dns_setting __setting ( SETTING_IP_EXTRA, dns ) = {
}; };
/** IPv6 DNS server setting */ /** IPv6 DNS server setting */
const struct setting dns6_setting __setting ( SETTING_IP_EXTRA, dns6 ) = { const struct setting dns6_setting __setting ( SETTING_IP6_EXTRA, dns6 ) = {
.name = "dns6", .name = "dns6",
.description = "DNS server", .description = "DNS server",
.tag = DHCPV6_DNS_SERVERS, .tag = DHCPV6_DNS_SERVERS,
.type = &setting_type_ipv6, .type = &setting_type_ipv6,
.scope = &ipv6_scope, .scope = &dhcpv6_scope,
}; };
/** DNS search list */ /** DNS search list */

View File

@ -213,7 +213,7 @@ const struct setting syslog6_setting __setting ( SETTING_MISC, syslog6 ) = {
.description = "Syslog server", .description = "Syslog server",
.tag = DHCPV6_LOG_SERVERS, .tag = DHCPV6_LOG_SERVERS,
.type = &setting_type_ipv6, .type = &setting_type_ipv6,
.scope = &ipv6_scope, .scope = &dhcpv6_scope,
}; };
/** /**

97
third_party/ipxe/src/tests/asn1_test.c vendored Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* ASN.1 self-tests
*
*/
/* Forcibly enable assertions */
#undef NDEBUG
#include <stdlib.h>
#include <assert.h>
#include <ipxe/image.h>
#include <ipxe/asn1.h>
#include <ipxe/test.h>
#include "asn1_test.h"
/**
* Report ASN.1 test result
*
* @v test ASN.1 test
* @v file Test code file
* @v line Test code line
*/
void asn1_okx ( struct asn1_test *test, const char *file, unsigned int line ) {
struct digest_algorithm *digest = &asn1_test_digest_algorithm;
struct asn1_cursor *cursor;
uint8_t ctx[digest->ctxsize];
uint8_t out[ASN1_TEST_DIGEST_SIZE];
unsigned int i;
size_t offset;
int next;
/* Sanity check */
assert ( sizeof ( out ) == digest->digestsize );
/* Correct image data pointer */
test->image->data = virt_to_user ( ( void * ) test->image->data );
/* Check that image is detected as correct type */
okx ( register_image ( test->image ) == 0, file, line );
okx ( test->image->type == test->type, file, line );
/* Check that all ASN.1 objects can be extracted */
for ( offset = 0, i = 0 ; i < test->count ; offset = next, i++ ) {
/* Extract ASN.1 object */
next = image_asn1 ( test->image, offset, &cursor );
okx ( next >= 0, file, line );
okx ( ( ( size_t ) next ) > offset, file, line );
if ( next > 0 ) {
/* Calculate digest of ASN.1 object */
digest_init ( digest, ctx );
digest_update ( digest, ctx, cursor->data,
cursor->len );
digest_final ( digest, ctx, out );
/* Compare against expected digest */
okx ( memcmp ( out, test->expected[i].digest,
sizeof ( out ) ) == 0, file, line );
/* Free ASN.1 object */
free ( cursor );
}
}
/* Check that we have reached the end of the image */
okx ( offset == test->image->len, file, line );
/* Unregister image */
unregister_image ( test->image );
}

73
third_party/ipxe/src/tests/asn1_test.h vendored Normal file
View File

@ -0,0 +1,73 @@
#ifndef _ASN1_TEST_H
#define _ASN1_TEST_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/image.h>
#include <ipxe/sha1.h>
#include <ipxe/test.h>
/** Digest algorithm used for ASN.1 tests */
#define asn1_test_digest_algorithm sha1_algorithm
/** Digest size used for ASN.1 tests */
#define ASN1_TEST_DIGEST_SIZE SHA1_DIGEST_SIZE
/** An ASN.1 test digest */
struct asn1_test_digest {
/** Digest value */
uint8_t digest[ASN1_TEST_DIGEST_SIZE];
};
/** An ASN.1 test */
struct asn1_test {
/** Image type */
struct image_type *type;
/** Source image */
struct image *image;
/** Expected digests of ASN.1 objects */
struct asn1_test_digest *expected;
/** Number of ASN.1 objects */
unsigned int count;
};
/**
* Define an ASN.1 test
*
* @v _name Test name
* @v _type Test image file type
* @v _file Test image file data
* @v ... Expected ASN.1 object digests
* @ret test ASN.1 test
*/
#define ASN1( _name, _type, _file, ... ) \
static const char _name ## __file[] = _file; \
static struct image _name ## __image = { \
.refcnt = REF_INIT ( ref_no_free ), \
.name = #_name, \
.data = ( userptr_t ) ( _name ## __file ), \
.len = sizeof ( _name ## __file ), \
}; \
static struct asn1_test_digest _name ## _expected[] = { \
__VA_ARGS__ \
}; \
static struct asn1_test _name = { \
.type = _type, \
.image = & _name ## __image, \
.expected = _name ## _expected, \
.count = ( sizeof ( _name ## _expected ) / \
sizeof ( _name ## _expected[0] ) ), \
};
extern void asn1_okx ( struct asn1_test *test, const char *file,
unsigned int line );
/**
* Report ASN.1 test result
*
* @v test ASN.1 test
*/
#define asn1_ok( test ) asn1_okx ( test, __FILE__, __LINE__ )
#endif /* _ASN1_TEST_H */

84
third_party/ipxe/src/tests/der_test.c vendored Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* DER self-tests
*
*/
/* Forcibly enable assertions */
#undef NDEBUG
#include <string.h>
#include <assert.h>
#include <ipxe/test.h>
#include <ipxe/der.h>
#include "asn1_test.h"
/** Define inline data */
#define DATA(...) { __VA_ARGS__ }
/** Define inline expected digest */
#define DIGEST(...) { { __VA_ARGS__ } }
/** 32-bit RSA private key */
ASN1 ( rsa32, &der_image_type,
DATA ( 0x30, 0x2c, 0x02, 0x01, 0x00, 0x02, 0x05, 0x00, 0xb7, 0x56,
0x5c, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x04, 0x66,
0xa4, 0xc4, 0x35, 0x02, 0x03, 0x00, 0xda, 0x9f, 0x02, 0x03,
0x00, 0xd6, 0xaf, 0x02, 0x02, 0x01, 0x59, 0x02, 0x02, 0x4e,
0xe1, 0x02, 0x03, 0x00, 0xa6, 0x5a ),
DIGEST ( 0x82, 0x66, 0x24, 0xd9, 0xc3, 0x98, 0x1e, 0x5e, 0x56, 0xed,
0xd0, 0xd0, 0x2a, 0x5e, 0x9c, 0x3a, 0x58, 0xdf, 0x76, 0x0d ) );
/** 64-bit RSA private key */
ASN1 ( rsa64, &der_image_type,
DATA ( 0x30, 0x3e, 0x02, 0x01, 0x00, 0x02, 0x09, 0x00, 0xa1, 0xba,
0xb5, 0x70, 0x00, 0x89, 0xc0, 0x43, 0x02, 0x03, 0x01, 0x00,
0x01, 0x02, 0x08, 0x43, 0x98, 0xc6, 0x3c, 0x5f, 0xdc, 0x98,
0x01, 0x02, 0x05, 0x00, 0xcf, 0x91, 0x1c, 0x5d, 0x02, 0x05,
0x00, 0xc7, 0x77, 0x85, 0x1f, 0x02, 0x05, 0x00, 0xbc, 0xb3,
0x33, 0x91, 0x02, 0x04, 0x1b, 0xf9, 0x38, 0x13, 0x02, 0x04,
0x19, 0xf2, 0x58, 0x86 ),
DIGEST ( 0xee, 0x17, 0x32, 0x31, 0xf0, 0x3d, 0xfd, 0xaa, 0x9b, 0x47,
0xaf, 0x7b, 0x4b, 0x52, 0x0b, 0xb1, 0xab, 0x25, 0x3f, 0x11 ) );
/**
* Perform DER self-test
*
*/
static void der_test_exec ( void ) {
/* Perform tests */
asn1_ok ( &rsa32 );
asn1_ok ( &rsa64 );
}
/** DER self-test */
struct self_test der_test __self_test = {
.name = "der",
.exec = der_test_exec,
};

View File

@ -41,6 +41,38 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Define inline IPv6 address */ /** Define inline IPv6 address */
#define IPV6(...) { __VA_ARGS__ } #define IPV6(...) { __VA_ARGS__ }
/** An IPv6 test routing table entry */
struct ipv6_test_route {
/** Local address */
const char *address;
/** Prefix length */
unsigned int prefix_len;
/** Router address (if any) */
const char *router;
};
/** An IPv6 test routing table */
struct ipv6_test_table {
/** Test routing table entries */
const struct ipv6_test_route *routes;
/** Number of table entries */
unsigned int count;
/** Constructed routing table */
struct list_head list;
};
/** Define a test routing table */
#define TABLE( name, ... ) \
static const struct ipv6_test_route name ## _routes[] = { \
__VA_ARGS__ \
}; \
static struct ipv6_test_table name = { \
.routes = name ## _routes, \
.count = ( sizeof ( name ## _routes ) / \
sizeof ( name ## _routes[0] ) ), \
.list = LIST_HEAD_INIT ( name.list ), \
};
/** The unspecified IPv6 address */ /** The unspecified IPv6 address */
static const struct in6_addr sample_unspecified = { static const struct in6_addr sample_unspecified = {
.s6_addr = IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, .s6_addr = IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -53,6 +85,18 @@ static const struct in6_addr sample_link_local = {
0x00, 0x00, 0x69, 0xff, 0xfe, 0x50, 0x58, 0x45 ), 0x00, 0x00, 0x69, 0xff, 0xfe, 0x50, 0x58, 0x45 ),
}; };
/** A sample site-local IPv6 address */
static const struct in6_addr sample_site_local = {
.s6_addr = IPV6 ( 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 ),
};
/** A sample ULA IPv6 address */
static const struct in6_addr sample_ula = {
.s6_addr = IPV6 ( 0xfd, 0x44, 0x91, 0x12, 0x64, 0x42, 0x00, 0x00,
0x00, 0x00, 0x69, 0xff, 0xfe, 0x50, 0x58, 0x45 ),
};
/** A sample global IPv6 address */ /** A sample global IPv6 address */
static const struct in6_addr sample_global = { static const struct in6_addr sample_global = {
.s6_addr = IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4, .s6_addr = IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4,
@ -65,27 +109,57 @@ static const struct in6_addr sample_multicast = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ),
}; };
/** Dummy network device used for routing tests */
static struct net_device ipv6_test_netdev = {
.refcnt = REF_INIT ( ref_no_free ),
.index = 42,
.state = NETDEV_OPEN,
};
/** Routing table with only a link-local address */
TABLE ( table_link_local,
{ "fe80::69ff:fe50:5845", 64, NULL } );
/** Routing table with a global address */
TABLE ( table_normal,
{ "fe80::69ff:fe50:5845", 64, NULL },
{ "2001:db8:3::1", 64, "fe80::1" } );
/** Routing table with multiple addresses and routers */
TABLE ( table_multi,
{ "fe80::69ff:fe50:5845", 64, NULL },
{ "2001:db8:3::1", 64, "fe80::1" },
{ "2001:db8:5::1", 64, NULL },
{ "2001:db8:42::1", 64, "fe80::2" },
{ "fd44:9112:6442::69ff:fe50:5845", 64, "fe80::1" },
{ "fd70:6ba9:50ae::69ff:fe50:5845", 64, "fe80::3" } );
/** /**
* Report an inet6_ntoa() test result * Report an inet6_ntoa() test result
* *
* @v addr IPv6 address * @v addr IPv6 address
* @v text Expected textual representation * @v text Expected textual representation
* @v file Test code file
* @v line Test code line
*/ */
static void inet6_ntoa_okx ( const struct in6_addr *addr, const char *text,
const char *file, unsigned int line ) {
char *actual;
actual = inet6_ntoa ( addr );
DBG ( "inet6_ntoa ( %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ) "
"= %s\n", ntohs ( addr->s6_addr16[0] ),
ntohs ( addr->s6_addr16[1] ), ntohs ( addr->s6_addr16[2] ),
ntohs ( addr->s6_addr16[3] ), ntohs ( addr->s6_addr16[4] ),
ntohs ( addr->s6_addr16[5] ), ntohs ( addr->s6_addr16[6] ),
ntohs ( addr->s6_addr16[7] ), actual );
okx ( strcmp ( actual, text ) == 0, file, line );
}
#define inet6_ntoa_ok( addr, text ) do { \ #define inet6_ntoa_ok( addr, text ) do { \
static const struct in6_addr in = { \ static const struct in6_addr in = { \
.s6_addr = addr, \ .s6_addr = addr, \
}; \ }; \
static const char expected[] = text; \ inet6_ntoa_okx ( &in, text, __FILE__, __LINE__ ); \
char *actual; \
\
actual = inet6_ntoa ( &in ); \
DBG ( "inet6_ntoa ( %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ) " \
"= %s\n", ntohs ( in.s6_addr16[0] ), \
ntohs ( in.s6_addr16[1] ), ntohs ( in.s6_addr16[2] ), \
ntohs ( in.s6_addr16[3] ), ntohs ( in.s6_addr16[4] ), \
ntohs ( in.s6_addr16[5] ), ntohs ( in.s6_addr16[6] ), \
ntohs ( in.s6_addr16[7] ), actual ); \
ok ( strcmp ( actual, expected ) == 0 ); \
} while ( 0 ) } while ( 0 )
/** /**
@ -93,31 +167,182 @@ static const struct in6_addr sample_multicast = {
* *
* @v text Textual representation * @v text Textual representation
* @v addr Expected IPv6 address * @v addr Expected IPv6 address
* @v file Test code file
* @v line Test code line
*/ */
static void inet6_aton_okx ( const char *text, const struct in6_addr *addr,
const char *file, unsigned int line ) {
struct in6_addr actual;
okx ( inet6_aton ( text, &actual ) == 0, file, line );
DBG ( "inet6_aton ( \"%s\" ) = %s\n", text, inet6_ntoa ( &actual ) );
okx ( memcmp ( &actual, addr, sizeof ( actual ) ) == 0,
file, line );
}
#define inet6_aton_ok( text, addr ) do { \ #define inet6_aton_ok( text, addr ) do { \
static const char string[] = text; \ static const struct in6_addr in = { \
static const struct in6_addr expected = { \
.s6_addr = addr, \ .s6_addr = addr, \
}; \ }; \
struct in6_addr actual; \ inet6_aton_okx ( text, &in, __FILE__, __LINE__ ); \
\
ok ( inet6_aton ( string, &actual ) == 0 ); \
DBG ( "inet6_aton ( \"%s\" ) = %s\n", string, \
inet6_ntoa ( &actual ) ); \
ok ( memcmp ( &actual, &expected, sizeof ( actual ) ) == 0 ); \
} while ( 0 ) } while ( 0 )
/** /**
* Report an inet6_aton() failure test result * Report an inet6_aton() failure test result
* *
* @v text Textual representation * @v text Textual representation
* @v file Test code file
* @v line Test code line
*/ */
#define inet6_aton_fail_ok( text ) do { \ static void inet6_aton_fail_okx ( const char *text, const char *file,
static const char string[] = text; \ unsigned int line ) {
struct in6_addr dummy; \ struct in6_addr dummy;
\
ok ( inet6_aton ( string, &dummy ) != 0 ); \ okx ( inet6_aton ( text, &dummy ) != 0, file, line );
} while ( 0 ) }
#define inet6_aton_fail_ok( text ) \
inet6_aton_fail_okx ( text, __FILE__, __LINE__ )
/**
* Create test routing table
*
* @v table Test routing table
* @v file Test code file
* @v line Test code line
*/
static void ipv6_table_okx ( struct ipv6_test_table *table, const char *file,
unsigned int line ) {
const struct ipv6_test_route *route;
struct in6_addr address;
struct in6_addr router;
struct list_head saved;
unsigned int i;
/* Sanity check */
okx ( list_empty ( &table->list ), file, line );
/* Save existing routing table */
INIT_LIST_HEAD ( &saved );
list_splice_init ( &ipv6_miniroutes, &saved );
/* Construct routing table */
for ( i = 0 ; i < table->count ; i++ ) {
/* Parse address and router (if applicable) */
route = &table->routes[i];
okx ( inet6_aton ( route->address, &address ) == 0,
file, line );
if ( route->router ) {
okx ( inet6_aton ( route->router, &router ) == 0,
file, line );
}
/* Add routing table entry */
okx ( ipv6_add_miniroute ( &ipv6_test_netdev, &address,
route->prefix_len,
( route->router ?
&router : NULL ) ) == 0,
file, line );
}
/* Save constructed routing table */
list_splice_init ( &ipv6_miniroutes, &table->list );
/* Restore original routing table */
list_splice ( &saved, &ipv6_miniroutes );
}
#define ipv6_table_ok( table ) \
ipv6_table_okx ( table, __FILE__, __LINE__ )
/**
* Report an ipv6_route() test result
*
* @v table Test routing table
* @v dest Destination address
* @v src Expected source address, or NULL to expect failure
* @v next Expected next hop address, or NULL to expect destination
* @v file Test code file
* @v line Test code line
*/
static void ipv6_route_okx ( struct ipv6_test_table *table, const char *dest,
const char *src, const char *next,
const char *file, unsigned int line ) {
struct in6_addr in_dest;
struct in6_addr in_src;
struct in6_addr in_next;
struct in6_addr *actual;
struct ipv6_miniroute *miniroute;
struct list_head saved;
/* Switch to test routing table */
INIT_LIST_HEAD ( &saved );
list_splice_init ( &ipv6_miniroutes, &saved );
list_splice_init ( &table->list, &ipv6_miniroutes );
/* Parse addresses */
okx ( inet6_aton ( dest, &in_dest ) == 0, file, line );
if ( src )
okx ( inet6_aton ( src, &in_src ) == 0, file, line );
if ( next ) {
okx ( inet6_aton ( next, &in_next ) == 0, file, line );
} else {
memcpy ( &in_next, &in_dest, sizeof ( in_next ) );
}
/* Perform routing */
actual = &in_dest;
miniroute = ipv6_route ( ipv6_test_netdev.index, &actual );
/* Validate result */
if ( src ) {
/* Check that a route was found */
okx ( miniroute != NULL, file, line );
DBG ( "ipv6_route ( %s ) = %s", dest, inet6_ntoa ( actual ) );
DBG ( " from %s\n", inet6_ntoa ( &miniroute->address ) );
/* Check that expected source address was used */
okx ( memcmp ( &miniroute->address, &in_src,
sizeof ( in_src ) ) == 0, file, line );
/* Check that expected next hop address was used */
okx ( memcmp ( actual, &in_next, sizeof ( *actual ) ) == 0,
file, line );
} else {
/* Routing is expected to fail */
okx ( miniroute == NULL, file, line );
}
/* Restore original routing table */
list_splice_init ( &ipv6_miniroutes, &table->list );
list_splice ( &saved, &ipv6_miniroutes );
}
#define ipv6_route_ok( table, dest, src, next ) \
ipv6_route_okx ( table, dest, src, next, __FILE__, __LINE__ )
/**
* Destroy test routing table
*
* @v table Test routing table
*/
static void ipv6_table_del ( struct ipv6_test_table *table ) {
struct ipv6_miniroute *miniroute;
struct ipv6_miniroute *tmp;
struct list_head saved;
/* Switch to test routing table */
INIT_LIST_HEAD ( &saved );
list_splice_init ( &ipv6_miniroutes, &saved );
list_splice_init ( &table->list, &ipv6_miniroutes );
/* Delete all existing routes */
list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list )
ipv6_del_miniroute ( miniroute );
/* Restore original routing table */
list_splice ( &saved, &ipv6_miniroutes );
}
/** /**
* Perform IPv6 self-tests * Perform IPv6 self-tests
@ -128,16 +353,34 @@ static void ipv6_test_exec ( void ) {
/* Address testing macros */ /* Address testing macros */
ok ( IN6_IS_ADDR_UNSPECIFIED ( &sample_unspecified ) ); ok ( IN6_IS_ADDR_UNSPECIFIED ( &sample_unspecified ) );
ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_link_local ) ); ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_link_local ) );
ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_site_local ) );
ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_ula ) );
ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_global ) ); ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_global ) );
ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_multicast ) ); ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_multicast ) );
ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_unspecified ) ); ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_unspecified ) );
ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_link_local ) ); ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_link_local ) );
ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_site_local ) );
ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_ula ) );
ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_global ) ); ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_global ) );
ok ( IN6_IS_ADDR_MULTICAST ( &sample_multicast ) ); ok ( IN6_IS_ADDR_MULTICAST ( &sample_multicast ) );
ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_unspecified ) ); ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_unspecified ) );
ok ( IN6_IS_ADDR_LINKLOCAL ( &sample_link_local ) ); ok ( IN6_IS_ADDR_LINKLOCAL ( &sample_link_local ) );
ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_site_local ) );
ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_ula ) );
ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_global ) ); ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_global ) );
ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_multicast ) ); ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_multicast ) );
ok ( ! IN6_IS_ADDR_SITELOCAL ( &sample_unspecified ) );
ok ( ! IN6_IS_ADDR_SITELOCAL ( &sample_link_local ) );
ok ( IN6_IS_ADDR_SITELOCAL ( &sample_site_local ) );
ok ( ! IN6_IS_ADDR_SITELOCAL ( &sample_ula ) );
ok ( ! IN6_IS_ADDR_SITELOCAL ( &sample_global ) );
ok ( ! IN6_IS_ADDR_SITELOCAL ( &sample_multicast ) );
ok ( ! IN6_IS_ADDR_ULA ( &sample_unspecified ) );
ok ( ! IN6_IS_ADDR_ULA ( &sample_link_local ) );
ok ( ! IN6_IS_ADDR_ULA ( &sample_site_local ) );
ok ( IN6_IS_ADDR_ULA ( &sample_ula ) );
ok ( ! IN6_IS_ADDR_ULA ( &sample_global ) );
ok ( ! IN6_IS_ADDR_ULA ( &sample_multicast ) );
/* inet6_ntoa() tests */ /* inet6_ntoa() tests */
inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4, inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4,
@ -214,6 +457,58 @@ static void ipv6_test_exec ( void ) {
inet6_aton_fail_ok ( "2001:db8::1::2" ); inet6_aton_fail_ok ( "2001:db8::1::2" );
inet6_aton_fail_ok ( "2001:ba8:0:1d4:::6950:5845" ); inet6_aton_fail_ok ( "2001:ba8:0:1d4:::6950:5845" );
inet6_aton_fail_ok ( ":::" ); inet6_aton_fail_ok ( ":::" );
/* Create test routing tables */
ipv6_table_ok ( &table_link_local );
ipv6_table_ok ( &table_normal );
ipv6_table_ok ( &table_multi );
/* Routing table with only a link-local address */
ipv6_route_ok ( &table_link_local, "fe80::1",
"fe80::69ff:fe50:5845", NULL );
ipv6_route_ok ( &table_link_local, "2001:db8:1::1",
NULL, NULL );
ipv6_route_ok ( &table_link_local, "ff02::1",
"fe80::69ff:fe50:5845", NULL );
/** Routing table with a global address */
ipv6_route_ok ( &table_normal, "fe80::1",
"fe80::69ff:fe50:5845", NULL );
ipv6_route_ok ( &table_normal, "2001:db8:3::42",
"2001:db8:3::1", NULL );
ipv6_route_ok ( &table_normal, "2001:ba8:0:1d4::6950:5845",
"2001:db8:3::1", "fe80::1" );
ipv6_route_ok ( &table_normal, "ff02::1",
"fe80::69ff:fe50:5845", NULL );
ipv6_route_ok ( &table_normal, "ff0e::1",
"2001:db8:3::1", NULL );
/** Routing table with multiple addresses and routers */
ipv6_route_ok ( &table_multi, "fe80::1",
"fe80::69ff:fe50:5845", NULL );
ipv6_route_ok ( &table_multi, "2001:db8:3::17",
"2001:db8:3::1", NULL );
ipv6_route_ok ( &table_multi, "2001:db8:5::92",
"2001:db8:5::1", NULL );
ipv6_route_ok ( &table_multi, "2001:db8:42::17",
"2001:db8:42::1", NULL );
ipv6_route_ok ( &table_multi, "2001:db8:5:1::17",
"2001:db8:3::1", "fe80::1" );
ipv6_route_ok ( &table_multi, "fd44:9112:6442::1",
"fd44:9112:6442::69ff:fe50:5845", NULL );
ipv6_route_ok ( &table_multi, "fd70:6ba9:50ae::1",
"fd70:6ba9:50ae::69ff:fe50:5845", NULL );
ipv6_route_ok ( &table_multi, "fd40::3",
"fd44:9112:6442::69ff:fe50:5845", "fe80::1" );
ipv6_route_ok ( &table_multi, "fd70::2",
"fd70:6ba9:50ae::69ff:fe50:5845", "fe80::3" );
ipv6_route_ok ( &table_multi, "ff02::1",
"fe80::69ff:fe50:5845", NULL );
/* Destroy test routing tables */
ipv6_table_del ( &table_link_local );
ipv6_table_del ( &table_normal );
ipv6_table_del ( &table_multi );
} }
/** IPv6 self-test */ /** IPv6 self-test */

107
third_party/ipxe/src/tests/pem_test.c vendored Normal file
View File

@ -0,0 +1,107 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* PEM self-tests
*
*/
/* Forcibly enable assertions */
#undef NDEBUG
#include <string.h>
#include <assert.h>
#include <ipxe/test.h>
#include <ipxe/pem.h>
#include "asn1_test.h"
/** Define inline expected digest */
#define DIGEST(...) { { __VA_ARGS__ } }
/** Single RSA private key */
ASN1 ( single, &pem_image_type,
"-----BEGIN RSA PRIVATE KEY-----\n"
"MCwCAQACBQC6loItAgMBAAECBCqhYIkCAwDyVwIDAMUbAgMAr9kCAmr9AgIaWQ==\n"
"-----END RSA PRIVATE KEY-----\n",
DIGEST ( 0xb9, 0x38, 0x83, 0xcd, 0xf4, 0x58, 0xa9, 0xa2, 0x84, 0x11,
0xfa, 0x0b, 0x6f, 0xdc, 0x3e, 0xa3, 0x7c, 0x90, 0x7c, 0x2d ) );
/** Three concatenated RSA private keys */
ASN1 ( multiple, &pem_image_type,
"-----BEGIN RSA PRIVATE KEY-----\n"
"MCwCAQACBQDtbjyVAgMBAAECBQCEOtJxAgMA+xsCAwDyDwICLGsCAgqTAgIxVQ==\n"
"-----END RSA PRIVATE KEY-----\n"
"-----BEGIN RSA PRIVATE KEY-----\n"
"MCwCAQACBQC3VlyxAgMBAAECBGakxDUCAwDanwIDANavAgIBWQICTuECAwCmWg==\n"
"-----END RSA PRIVATE KEY-----\n"
"-----BEGIN RSA PRIVATE KEY-----\n"
"MCwCAQACBQC89dS1AgMBAAECBQCxjnLBAgMA3qcCAwDZQwICP3cCAgpRAgI57A==\n"
"-----END RSA PRIVATE KEY-----\n",
DIGEST ( 0x9c, 0xb2, 0xc1, 0xa0, 0x9c, 0xcb, 0x11, 0xbf, 0x80, 0xd0,
0x8c, 0xe5, 0xda, 0xf2, 0x3b, 0x2c, 0xca, 0x64, 0x25, 0x8a ),
DIGEST ( 0x82, 0x66, 0x24, 0xd9, 0xc3, 0x98, 0x1e, 0x5e, 0x56, 0xed,
0xd0, 0xd0, 0x2a, 0x5e, 0x9c, 0x3a, 0x58, 0xdf, 0x76, 0x0d ),
DIGEST ( 0x01, 0xd2, 0x8a, 0x74, 0x42, 0x08, 0x0f, 0xb0, 0x03, 0x82,
0xcd, 0xa3, 0xdc, 0x78, 0xfe, 0xd7, 0xa3, 0x28, 0xfc, 0x29 ) );
/** Two RSA private keys with various bits of noise added */
ASN1 ( noisy, &pem_image_type,
"Hello world! This is uninteresting stuff before the actual data.\n"
"-----BEGIN RSA PRIVATE KEY-----\n"
"MCwCAQACBQC3VlyxAgMBAAECBGakxDUCAwDanwIDANavAgIBWQICTuECAwCmWg==\n"
"-----END RSA PRIVATE KEY-----\n"
"Here is some more uninteresting stuff.\n"
"Followed by what is actually another RSA private key, but with "
"extra whitespace added, and the description change to pretend "
"it's a certificate\n"
"-----BEGIN CERTIFICATE-----\n"
" MCwCAQACBQC6loItAgMBAAECBCqhYIkCAwD\r\n"
" yVwIDAMUbAgMAr9kCAmr9AgIaWQ== \r\n"
"-----END CERTIFICATE-----\n"
"and some trailing garbage as well\n"
"and more garbage with no final newline",
DIGEST ( 0x82, 0x66, 0x24, 0xd9, 0xc3, 0x98, 0x1e, 0x5e, 0x56, 0xed,
0xd0, 0xd0, 0x2a, 0x5e, 0x9c, 0x3a, 0x58, 0xdf, 0x76, 0x0d ),
DIGEST ( 0xb9, 0x38, 0x83, 0xcd, 0xf4, 0x58, 0xa9, 0xa2, 0x84, 0x11,
0xfa, 0x0b, 0x6f, 0xdc, 0x3e, 0xa3, 0x7c, 0x90, 0x7c, 0x2d ) );
/**
* Perform PEM self-test
*
*/
static void pem_test_exec ( void ) {
/* Perform tests */
asn1_ok ( &single );
asn1_ok ( &multiple );
asn1_ok ( &noisy );
}
/** PEM self-test */
struct self_test pem_test __self_test = {
.name = "pem",
.exec = pem_test_exec,
};

View File

@ -69,3 +69,5 @@ REQUIRE_OBJECT ( pccrc_test );
REQUIRE_OBJECT ( linebuf_test ); REQUIRE_OBJECT ( linebuf_test );
REQUIRE_OBJECT ( iobuf_test ); REQUIRE_OBJECT ( iobuf_test );
REQUIRE_OBJECT ( bitops_test ); REQUIRE_OBJECT ( bitops_test );
REQUIRE_OBJECT ( der_test );
REQUIRE_OBJECT ( pem_test );

View File

@ -50,30 +50,28 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/ */
int imgverify ( struct image *image, struct image *signature, int imgverify ( struct image *image, struct image *signature,
const char *name ) { const char *name ) {
size_t len; struct asn1_cursor *data;
void *data;
struct cms_signature *sig; struct cms_signature *sig;
struct cms_signer_info *info; struct cms_signer_info *info;
time_t now; time_t now;
int next;
int rc; int rc;
/* Mark image as untrusted */ /* Mark image as untrusted */
image_untrust ( image ); image_untrust ( image );
/* Copy signature to internal memory */ /* Get raw signature data */
len = signature->len; next = image_asn1 ( signature, 0, &data );
data = malloc ( len ); if ( next < 0 ) {
if ( ! data ) { rc = next;
rc = -ENOMEM; goto err_asn1;
goto err_alloc;
} }
copy_from_user ( data, signature->data, 0, len );
/* Parse signature */ /* Parse signature */
if ( ( rc = cms_signature ( data, len, &sig ) ) != 0 ) if ( ( rc = cms_signature ( data->data, data->len, &sig ) ) != 0 )
goto err_parse; goto err_parse;
/* Free internal copy of signature */ /* Free raw signature data */
free ( data ); free ( data );
data = NULL; data = NULL;
@ -107,7 +105,7 @@ int imgverify ( struct image *image, struct image *signature,
cms_put ( sig ); cms_put ( sig );
err_parse: err_parse:
free ( data ); free ( data );
err_alloc: err_asn1:
syslog ( LOG_ERR, "Image \"%s\" signature bad: %s\n", syslog ( LOG_ERR, "Image \"%s\" signature bad: %s\n",
image->name, strerror ( rc ) ); image->name, strerror ( rc ) );
return rc; return rc;