david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Merge branch 'master' into strings

This commit is contained in:
Holger Lubitz 2007-08-02 00:13:40 +02:00
commit 58f5565eb0
66 changed files with 4028 additions and 735 deletions

View File

@ -145,6 +145,7 @@ DEBUG_TARGETS += dbg%.o c s
# SRCDIRS lists all directories containing source files.
#
SRCDIRS += libgcc
SRCDIRS += core
SRCDIRS += proto
SRCDIRS += net net/tcp net/udp

View File

@ -130,6 +130,18 @@ endif
# this is almost always a win. the kernel uses it, too.
CFLAGS+= -mpreferred-stack-boundary=2
# use regparm for all functions - C functions called from assembly (or
# vice versa) need __cdecl now
CFLAGS+= -mregparm=3
# use -mrtd (same __cdecl requirements as above)
CFLAGS+= -mrtd
# this is the logical complement to -mregparm=3.
# it doesn't currently buy us anything, but if anything ever tries
# to return small structures, let's be prepared
CFLAGS+= -freg-struct-return
LDFLAGS+= -N --no-check-sections
ifeq "$(shell uname -s)" "FreeBSD"

View File

@ -39,7 +39,7 @@ extern char _end[];
* address space, and returns the physical address of the new location
* to the prefix in %edi.
*/
void relocate ( struct i386_all_regs *ix86 ) {
__cdecl void relocate ( struct i386_all_regs *ix86 ) {
struct memory_map memmap;
unsigned long start, end, size, padded_size;
unsigned long new_start, new_end;

View File

@ -1,336 +0,0 @@
/*
* Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file
*
* 64-bit division
*
* The x86 CPU (386 upwards) has a divl instruction which will perform
* unsigned division of a 64-bit dividend by a 32-bit divisor. If the
* resulting quotient does not fit in 32 bits, then a CPU exception
* will occur.
*
* Unsigned integer division is expressed as solving
*
* x = d.q + r 0 <= q, 0 <= r < d
*
* given the dividend (x) and divisor (d), to find the quotient (q)
* and remainder (r).
*
* The x86 divl instruction will solve
*
* x = d.q + r 0 <= q, 0 <= r < d
*
* given x in the range 0 <= x < 2^64 and 1 <= d < 2^32, and causing a
* hardware exception if the resulting q >= 2^32.
*
* We can therefore use divl only if we can prove that the conditions
*
* 0 <= x < 2^64
* 1 <= d < 2^32
* q < 2^32
*
* are satisfied.
*
*
* Case 1 : 1 <= d < 2^32
* ======================
*
* We express x as
*
* x = xh.2^32 + xl 0 <= xh < 2^32, 0 <= xl < 2^32 (1)
*
* i.e. split x into low and high dwords. We then solve
*
* xh = d.qh + r' 0 <= qh, 0 <= r' < d (2)
*
* which we can do using a divl instruction since
*
* 0 <= xh < 2^64 since 0 <= xh < 2^32 from (1) (3)
*
* and
*
* 1 <= d < 2^32 by definition of this Case (4)
*
* and
*
* d.qh = xh - r' from (2)
* d.qh <= xh since r' >= 0 from (2)
* qh <= xh since d >= 1 from (2)
* qh < 2^32 since xh < 2^32 from (1) (5)
*
* Having obtained qh and r', we then solve
*
* ( r'.2^32 + xl ) = d.ql + r 0 <= ql, 0 <= r < d (6)
*
* which we can do using another divl instruction since
*
* xl <= 2^32 - 1 from (1), so
* r'.2^32 + xl <= ( r' + 1 ).2^32 - 1
* r'.2^32 + xl <= d.2^32 - 1 since r' < d from (2)
* r'.2^32 + xl < d.2^32 (7)
* r'.2^32 + xl < 2^64 since d < 2^32 from (4) (8)
*
* and
*
* 1 <= d < 2^32 by definition of this Case (9)
*
* and
*
* d.ql = ( r'.2^32 + xl ) - r from (6)
* d.ql <= r'.2^32 + xl since r >= 0 from (6)
* d.ql < d.2^32 from (7)
* ql < 2^32 since d >= 1 from (2) (10)
*
* This then gives us
*
* x = xh.2^32 + xl from (1)
* x = ( d.qh + r' ).2^32 + xl from (2)
* x = d.qh.2^32 + ( r'.2^32 + xl )
* x = d.qh.2^32 + d.ql + r from (3)
* x = d.( qh.2^32 + ql ) + r (11)
*
* Letting
*
* q = qh.2^32 + ql (12)
*
* gives
*
* x = d.q + r from (11) and (12)
*
* which is the solution.
*
*
* This therefore gives us a two-step algorithm:
*
* xh = d.qh + r' 0 <= qh, 0 <= r' < d (2)
* ( r'.2^32 + xl ) = d.ql + r 0 <= ql, 0 <= r < d (6)
*
* which translates to
*
* %edx:%eax = 0:xh
* divl d
* qh = %eax
* r' = %edx
*
* %edx:%eax = r':xl
* divl d
* ql = %eax
* r = %edx
*
* Note that if
*
* xh < d
*
* (which is a fast dword comparison) then the first divl instruction
* can be omitted, since the answer will be
*
* qh = 0
* r = xh
*
*
* Case 2 : 2^32 <= d < 2^64
* =========================
*
* We first express d as
*
* d = dh.2^k + dl 2^31 <= dh < 2^32,
* 0 <= dl < 2^k, 1 <= k <= 32 (1)
*
* i.e. find the highest bit set in d, subtract 32, and split d into
* dh and dl at that point.
*
* We then express x as
*
* x = xh.2^k + xl 0 <= xl < 2^k (2)
*
* giving
*
* xh.2^k = x - xl from (2)
* xh.2^k <= x since xl >= 0 from (1)
* xh.2^k < 2^64 since xh < 2^64 from (1)
* xh < 2^(64-k) (3)
*
* We then solve the division
*
* xh = dh.q' + r' 0 <= r' < dh (4)
*
* which we can do using a divl instruction since
*
* 0 <= xh < 2^64 since x < 2^64 and xh < x
*
* and
*
* 1 <= dh < 2^32 from (1)
*
* and
*
* dh.q' = xh - r' from (4)
* dh.q' <= xh since r' >= 0 from (4)
* dh.q' < 2^(64-k) from (3) (5)
* q'.2^31 <= dh.q' since dh >= 2^31 from (1) (6)
* q'.2^31 < 2^(64-k) from (5) and (6)
* q' < 2^(33-k)
* q' < 2^32 since k >= 1 from (1) (7)
*
* This gives us
*
* xh.2^k = dh.q'.2^k + r'.2^k from (4)
* x - xl = ( d - dl ).q' + r'.2^k from (1) and (2)
* x = d.q' + ( r'.2^k + xl ) - dl.q' (8)
*
* Now
*
* r'.2^k + xl < r'.2^k + 2^k since xl < 2^k from (2)
* r'.2^k + xl < ( r' + 1 ).2^k
* r'.2^k + xl < dh.2^k since r' < dh from (4)
* r'.2^k + xl < ( d - dl ) from (1) (9)
*
*
* (missing)
*
*
* This gives us two cases to consider:
*
* case (a):
*
* dl.q' <= ( r'.2^k + xl ) (15a)
*
* in which case
*
* x = d.q' + ( r'.2^k + xl - dl.q' )
*
* is a direct solution to the division, since
*
* r'.2^k + xl < d from (9)
* ( r'.2^k + xl - dl.q' ) < d since dl >= 0 and q' >= 0
*
* and
*
* 0 <= ( r'.2^k + xl - dl.q' ) from (15a)
*
* case (b):
*
* dl.q' > ( r'.2^k + xl ) (15b)
*
* Express
*
* x = d.(q'-1) + ( r'.2^k + xl ) + ( d - dl.q' )
*
*
* (missing)
*
*
* special case: k = 32 cannot be handled with shifts
*
* (missing)
*
*/
#include <stdint.h>
#include <assert.h>
typedef uint64_t UDItype;
struct uint64 {
uint32_t l;
uint32_t h;
};
static inline void udivmod64_lo ( const struct uint64 *x,
const struct uint64 *d,
struct uint64 *q,
struct uint64 *r ) {
uint32_t r_dash;
q->h = 0;
r->h = 0;
r_dash = x->h;
if ( x->h >= d->l ) {
__asm__ ( "divl %2"
: "=&a" ( q->h ), "=&d" ( r_dash )
: "g" ( d->l ), "0" ( x->h ), "1" ( 0 ) );
}
__asm__ ( "divl %2"
: "=&a" ( q->l ), "=&d" ( r->l )
: "g" ( d->l ), "0" ( x->l ), "1" ( r_dash ) );
}
static void udivmod64 ( const struct uint64 *x,
const struct uint64 *d,
struct uint64 *q,
struct uint64 *r ) {
if ( d->h == 0 ) {
udivmod64_lo ( x, d, q, r );
} else {
assert ( 0 );
while ( 1 ) {};
}
}
/**
* 64-bit division with remainder
*
* @v x Dividend
* @v d Divisor
* @ret r Remainder
* @ret q Quotient
*/
UDItype __udivmoddi4 ( UDItype x, UDItype d, UDItype *r ) {
UDItype q;
UDItype *_x = &x;
UDItype *_d = &d;
UDItype *_q = &q;
UDItype *_r = r;
udivmod64 ( ( struct uint64 * ) _x, ( struct uint64 * ) _d,
( struct uint64 * ) _q, ( struct uint64 * ) _r );
assert ( ( x == ( ( d * q ) + (*r) ) ) );
assert ( (*r) < d );
return q;
}
/**
* 64-bit division
*
* @v x Dividend
* @v d Divisor
* @ret q Quotient
*/
UDItype __udivdi3 ( UDItype x, UDItype d ) {
UDItype r;
return __udivmoddi4 ( x, d, &r );
}
/**
* 64-bit modulus
*
* @v x Dividend
* @v d Divisor
* @ret q Quotient
*/
UDItype __umoddi3 ( UDItype x, UDItype d ) {
UDItype r;
__udivmoddi4 ( x, d, &r );
return r;
}

View File

@ -423,8 +423,14 @@ static void undinet_poll ( struct net_device *netdev ) {
if ( ! undinic->isr_processing ) {
/* Do nothing unless ISR has been triggered */
if ( ! undinet_isr_triggered() )
if ( ! undinet_isr_triggered() ) {
/* Allow interrupt to occur */
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
"nop\n\t"
"nop\n\t"
"cli\n\t" ) : : );
return;
}
/* Start ISR processing */
undinic->isr_processing = 1;

View File

@ -33,7 +33,6 @@
#include <gpxe/uaccess.h>
#include <gpxe/image.h>
#include <gpxe/segment.h>
#include <gpxe/memmap.h>
#include <gpxe/init.h>
#include <gpxe/initrd.h>
@ -168,58 +167,78 @@ static int bzimage_set_cmdline ( struct image *image,
}
/**
* Load initrd, if any
* Load initrds, if any
*
* @v image bzImage image
* @v exec_ctx Execution context
* @ret rc Return status code
*/
static int bzimage_load_initrd ( struct image *image,
struct bzimage_exec_context *exec_ctx,
struct image *initrd ) {
physaddr_t start = user_to_phys ( initrd->data, 0 );
struct bzimage_exec_context *exec_ctx ) {
struct image *initrd;
size_t initrd_len;
size_t total_len = 0;
size_t offset = 0;
physaddr_t start;
int rc;
DBGC ( image, "bzImage %p loading initrd %p (%s)\n",
image, initrd, initrd->name );
/* Find a suitable start address */
if ( ( start + initrd->len ) <= exec_ctx->mem_limit ) {
/* Just use initrd in situ */
DBGC ( image, "bzImage %p using initrd as [%lx,%lx)\n",
image, start, ( start + initrd->len ) );
} else {
for ( ; ; start -= 0x100000 ) {
/* Check that we're not going to overwrite the
* kernel itself. This check isn't totally
* accurate, but errs on the side of caution.
*/
if ( start <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
DBGC ( image, "bzImage %p could not find a "
"location for initrd\n", image );
return -ENOBUFS;
}
/* Check that we are within the kernel's range */
if ( ( start + initrd->len ) > exec_ctx->mem_limit )
continue;
/* Prepare and verify segment */
if ( ( rc = prep_segment ( phys_to_user ( start ),
initrd->len,
initrd->len ) ) != 0 )
continue;
/* Copy to segment */
DBGC ( image, "bzImage %p relocating initrd to "
"[%lx,%lx)\n", image, start,
( start + initrd->len ) );
memcpy_user ( phys_to_user ( start ), 0,
initrd->data, 0, initrd->len );
break;
}
/* Add up length of all initrd images */
for_each_image ( initrd ) {
if ( initrd->type != &initrd_image_type )
continue;
initrd_len = ( ( initrd->len + 0x0f ) & ~0x0f );
total_len += initrd_len;
}
/* Give up if no initrd images found */
if ( ! total_len )
return 0;
/* Find a suitable start address. Try 1MB boundaries,
* starting from the downloaded kernel image itself and
* working downwards until we hit an available region.
*/
for ( start = ( user_to_phys ( image->data, 0 ) & ~0xfffff ) ; ;
start -= 0x100000 ) {
/* Check that we're not going to overwrite the
* kernel itself. This check isn't totally
* accurate, but errs on the side of caution.
*/
if ( start <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
DBGC ( image, "bzImage %p could not find a location "
"for initrd\n", image );
return -ENOBUFS;
}
/* Check that we are within the kernel's range */
if ( ( start + total_len ) > exec_ctx->mem_limit )
continue;
/* Prepare and verify segment */
if ( ( rc = prep_segment ( phys_to_user ( start ), 0,
total_len ) ) != 0 )
continue;
/* Use this address */
break;
}
/* Construct initrd */
DBGC ( image, "bzImage %p constructing initrd at [%lx,%lx)\n",
image, start, ( start + total_len ) );
for_each_image ( initrd ) {
if ( initrd->type != &initrd_image_type )
continue;
initrd_len = ( ( initrd->len + 0x0f ) & ~0x0f );
DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n",
image, initrd, ( start + offset ),
( start + offset + initrd->len ) );
memcpy_user ( phys_to_user ( start ), offset,
initrd->data, 0, initrd->len );
offset += initrd_len;
}
assert ( offset == total_len );
/* Record initrd location */
exec_ctx->ramdisk_image = start;
exec_ctx->ramdisk_size = initrd->len;
exec_ctx->ramdisk_size = total_len;
return 0;
}
@ -234,7 +253,6 @@ static int bzimage_exec ( struct image *image ) {
struct bzimage_exec_context exec_ctx;
struct bzimage_header bzhdr;
const char *cmdline = ( image->cmdline ? image->cmdline : "" );
struct image *initrd;
int rc;
/* Initialise context */
@ -262,15 +280,9 @@ static int bzimage_exec ( struct image *image ) {
if ( ( rc = bzimage_set_cmdline ( image, &exec_ctx, cmdline ) ) != 0 )
return rc;
/* Load an initrd, if one exists */
for_each_image ( initrd ) {
if ( initrd->type == &initrd_image_type ) {
if ( ( rc = bzimage_load_initrd ( image, &exec_ctx,
initrd ) ) != 0 )
return rc;
break;
}
}
/* Load any initrds */
if ( ( rc = bzimage_load_initrd ( image, &exec_ctx ) ) != 0 )
return rc;
/* Update and store kernel header */
bzhdr.vid_mode = exec_ctx.vid_mode;

View File

@ -298,7 +298,7 @@ static int eltorito_load_disk ( struct image *image,
* @v image El Torito file
* @ret rc Return status code
*/
int eltorito_load ( struct image *image ) {
static int eltorito_load ( struct image *image ) {
struct eltorito_boot_entry boot_entry;
unsigned long bootcat_offset;
int rc;

View File

@ -360,7 +360,7 @@ static int multiboot_load_elf ( struct image *image ) {
* @v image Multiboot file
* @ret rc Return status code
*/
int multiboot_load ( struct image *image ) {
static int multiboot_load ( struct image *image ) {
struct multiboot_header_info hdr;
int rc;

View File

@ -244,7 +244,7 @@ static int nbi_process_segments ( struct image *image,
* @v image NBI image
* @ret rc Return status code
*/
int nbi_load ( struct image *image ) {
static int nbi_load ( struct image *image ) {
struct imgheader imgheader;
int rc;
@ -397,16 +397,13 @@ static int nbi_prepare_dhcp ( struct image *image ) {
return -ENODEV;
}
if ( ( rc = create_dhcp_packet ( boot_netdev, DHCPACK, basemem_packet,
sizeof ( basemem_packet ),
&dhcppkt ) ) != 0 ) {
if ( ( rc = create_dhcp_response ( boot_netdev, DHCPACK, NULL,
basemem_packet,
sizeof ( basemem_packet ),
&dhcppkt ) ) != 0 ) {
DBGC ( image, "NBI %p failed to build DHCP packet\n", image );
return rc;
}
if ( ( rc = copy_dhcp_packet_options ( &dhcppkt, NULL ) ) != 0 ) {
DBGC ( image, "NBI %p failed to copy DHCP options\n", image );
return rc;
}
return 0;
}

View File

@ -321,7 +321,7 @@ static int int13_get_extended_parameters ( struct int13_drive *drive,
* INT 13 handler
*
*/
static void int13 ( struct i386_all_regs *ix86 ) {
static __cdecl void int13 ( struct i386_all_regs *ix86 ) {
int command = ix86->regs.ah;
unsigned int bios_drive = ix86->regs.dl;
unsigned int original_bios_drive = bios_drive;

View File

@ -112,7 +112,7 @@ static PXENV_EXIT_t pxenv_unknown ( struct s_PXENV_UNKNOWN *pxenv_unknown ) {
* @v es:di Address of PXE parameter block
* @ret ax PXE exit code
*/
void pxe_api_call ( struct i386_all_regs *ix86 ) {
__cdecl void pxe_api_call ( struct i386_all_regs *ix86 ) {
int opcode = ix86->regs.bx;
userptr_t parameters = real_to_user ( ix86->segs.es, ix86->regs.di );
size_t param_len;
@ -304,7 +304,7 @@ void pxe_api_call ( struct i386_all_regs *ix86 ) {
* @v es:di Address of PXE parameter block
* @ret ax PXE exit code
*/
void pxe_loader_call ( struct i386_all_regs *ix86 ) {
__cdecl void pxe_loader_call ( struct i386_all_regs *ix86 ) {
userptr_t uparams = real_to_user ( ix86->segs.es, ix86->regs.di );
struct s_UNDI_LOADER params;
PXENV_EXIT_t ret;

View File

@ -73,6 +73,7 @@
#define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */
#undef DOWNLOAD_PROTO_NFS /* Network File System */
#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */
#undef DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */
#undef DOWNLOAD_PROTO_FTP /* File Transfer Protocol */
#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */
#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */

60
src/core/abft.c Normal file
View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <realmode.h>
#include <gpxe/aoe.h>
#include <gpxe/netdevice.h>
#include <gpxe/abft.h>
/** @file
*
* AoE Boot Firmware Table
*
*/
#define abftab __use_data16 ( abftab )
/** The aBFT used by gPXE */
struct abft_table __data16 ( abftab ) __attribute__ (( aligned ( 16 ) )) = {
/* ACPI header */
.acpi = {
.signature = ABFT_SIG,
.length = sizeof ( abftab ),
.revision = 1,
.oem_id = "FENSYS",
.oem_table_id = "gPXE",
},
};
/**
* Fill in all variable portions of aBFT
*
* @v aoe AoE session
*/
void abft_fill_data ( struct aoe_session *aoe ) {
/* Fill in boot parameters */
abftab.shelf = aoe->major;
abftab.slot = aoe->minor;
memcpy ( abftab.mac, aoe->netdev->ll_addr, sizeof ( abftab.mac ) );
/* Update checksum */
acpi_fix_checksum ( &abftab.acpi );
DBG ( "AoE boot firmware table:\n" );
DBG_HD ( &abftab, sizeof ( abftab ) );
}

View File

@ -87,6 +87,9 @@ REQUIRE_OBJECT ( nfs );
#ifdef DOWNLOAD_PROTO_HTTP
REQUIRE_OBJECT ( http );
#endif
#ifdef DOWNLOAD_PROTO_HTTPS
REQUIRE_OBJECT ( https );
#endif
#ifdef DOWNLOAD_PROTO_FTP
REQUIRE_OBJECT ( ftp );
#endif

78
src/core/filter.c Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <gpxe/xfer.h>
#include <gpxe/filter.h>
/** @file
*
* Data transfer filters
*
*/
/*
* Pass-through methods to be used by filters which don't want to
* intercept all events.
*
*/
void filter_close ( struct xfer_interface *xfer, int rc ) {
struct xfer_interface *other = filter_other_half ( xfer );
xfer_close ( other, rc );
}
int filter_vredirect ( struct xfer_interface *xfer, int type,
va_list args ) {
struct xfer_interface *other = filter_other_half ( xfer );
return xfer_vredirect ( other, type, args );
}
int filter_seek ( struct xfer_interface *xfer, off_t offset, int whence ) {
struct xfer_interface *other = filter_other_half ( xfer );
return xfer_seek ( other, offset, whence );
}
size_t filter_window ( struct xfer_interface *xfer ) {
struct xfer_interface *other = filter_other_half ( xfer );
return xfer_window ( other );
}
struct io_buffer * filter_alloc_iob ( struct xfer_interface *xfer,
size_t len ) {
struct xfer_interface *other = filter_other_half ( xfer );
return xfer_alloc_iob ( other, len );
}
int filter_deliver_iob ( struct xfer_interface *xfer, struct io_buffer *iobuf,
struct xfer_metadata *meta ) {
struct xfer_interface *other = filter_other_half ( xfer );
return xfer_deliver_iob_meta ( other, iobuf, meta );
}
int filter_deliver_raw ( struct xfer_interface *xfer, const void *data,
size_t len ) {
struct xfer_interface *other = filter_other_half ( xfer );
return xfer_deliver_raw ( other, data, len );
}

View File

@ -24,7 +24,7 @@ Literature dealing with the network protocols:
*
* @ret rc Return status code
*/
int main ( void ) {
__cdecl int main ( void ) {
initialise();
startup();

View File

@ -0,0 +1,867 @@
/*
* Copyright(C) 2006 Cameron Rich
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* @file asn1.c
*
* Some primitive asn methods for extraction rsa modulus information. It also
* is used for retrieving information from X.509 certificates.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "crypto.h"
#define SIG_OID_PREFIX_SIZE 8
#define SIG_TYPE_MD2 0x02
#define SIG_TYPE_MD5 0x04
#define SIG_TYPE_SHA1 0x05
/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */
static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] =
{
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01
};
/* CN, O, OU */
static const uint8_t g_dn_types[] = { 3, 10, 11 };
static int get_asn1_length(const uint8_t *buf, int *offset)
{
int len, i;
if (!(buf[*offset] & 0x80)) /* short form */
{
len = buf[(*offset)++];
}
else /* long form */
{
int length_bytes = buf[(*offset)++]&0x7f;
len = 0;
for (i = 0; i < length_bytes; i++)
{
len <<= 8;
len += buf[(*offset)++];
}
}
return len;
}
/**
* Skip the ASN1.1 object type and its length. Get ready to read the object's
* data.
*/
int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type)
{
if (buf[*offset] != obj_type)
return X509_NOT_OK;
(*offset)++;
return get_asn1_length(buf, offset);
}
/**
* Skip over an ASN.1 object type completely. Get ready to read the next
* object.
*/
int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type)
{
int len;
if (buf[*offset] != obj_type)
return X509_NOT_OK;
(*offset)++;
len = get_asn1_length(buf, offset);
*offset += len;
return 0;
}
/**
* Read an integer value for ASN.1 data
* Note: This function allocates memory which must be freed by the user.
*/
int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object)
{
int len;
if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0)
goto end_int_array;
*object = (uint8_t *)malloc(len);
memcpy(*object, &buf[*offset], len);
*offset += len;
end_int_array:
return len;
}
#if 0
/**
* Get all the RSA private key specifics from an ASN.1 encoded file
*/
int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx)
{
int offset = 7;
uint8_t *modulus, *priv_exp, *pub_exp;
int mod_len, priv_len, pub_len;
#ifdef CONFIG_BIGINT_CRT
uint8_t *p, *q, *dP, *dQ, *qInv;
int p_len, q_len, dP_len, dQ_len, qInv_len;
#endif
/* not in der format */
if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */
{
#ifdef CONFIG_SSL_FULL_MODE
printf("Error: This is not a valid ASN.1 file\n");
#endif
return X509_INVALID_PRIV_KEY;
}
/* initialise the RNG */
RNG_initialize(buf, len);
mod_len = asn1_get_int(buf, &offset, &modulus);
pub_len = asn1_get_int(buf, &offset, &pub_exp);
priv_len = asn1_get_int(buf, &offset, &priv_exp);
if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0)
return X509_INVALID_PRIV_KEY;
#ifdef CONFIG_BIGINT_CRT
p_len = asn1_get_int(buf, &offset, &p);
q_len = asn1_get_int(buf, &offset, &q);
dP_len = asn1_get_int(buf, &offset, &dP);
dQ_len = asn1_get_int(buf, &offset, &dQ);
qInv_len = asn1_get_int(buf, &offset, &qInv);
if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0)
return X509_INVALID_PRIV_KEY;
RSA_priv_key_new(rsa_ctx,
modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len,
p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len);
free(p);
free(q);
free(dP);
free(dQ);
free(qInv);
#else
RSA_priv_key_new(rsa_ctx,
modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len);
#endif
free(modulus);
free(priv_exp);
free(pub_exp);
return X509_OK;
}
/**
* Get the time of a certificate. Ignore hours/minutes/seconds.
*/
static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t)
{
int ret = X509_NOT_OK, len, t_offset;
struct tm tm;
if (buf[(*offset)++] != ASN1_UTC_TIME)
goto end_utc_time;
len = get_asn1_length(buf, offset);
t_offset = *offset;
memset(&tm, 0, sizeof(struct tm));
tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0');
if (tm.tm_year <= 50) /* 1951-2050 thing */
{
tm.tm_year += 100;
}
tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1;
tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0');
*t = mktime(&tm);
*offset += len;
ret = X509_OK;
end_utc_time:
return ret;
}
/**
* Get the version type of a certificate (which we don't actually care about)
*/
static int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
{
int ret = X509_NOT_OK;
(*offset) += 2; /* get past explicit tag */
if (asn1_skip_obj(cert, offset, ASN1_INTEGER))
goto end_version;
ret = X509_OK;
end_version:
return ret;
}
/**
* Retrieve the notbefore and notafter certificate times.
*/
static int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
{
return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
asn1_get_utc_time(cert, offset, &x509_ctx->not_before) ||
asn1_get_utc_time(cert, offset, &x509_ctx->not_after));
}
/**
* Get the components of a distinguished name
*/
static int asn1_get_oid_x520(const uint8_t *buf, int *offset)
{
int dn_type = 0;
int len;
if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
goto end_oid;
/* expect a sequence of 2.5.4.[x] where x is a one of distinguished name
components we are interested in. */
if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04)
dn_type = buf[(*offset)++];
else
{
*offset += len; /* skip over it */
}
end_oid:
return dn_type;
}
/**
* Obtain an ASN.1 printable string type.
*/
static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str)
{
int len = X509_NOT_OK;
/* some certs have this awful crud in them for some reason */
if (buf[*offset] != ASN1_PRINTABLE_STR &&
buf[*offset] != ASN1_TELETEX_STR && buf[*offset] != ASN1_IA5_STR)
goto end_pnt_str;
(*offset)++;
len = get_asn1_length(buf, offset);
*str = (char *)malloc(len+1); /* allow for null */
memcpy(*str, &buf[*offset], len);
(*str)[len] = 0; /* null terminate */
*offset += len;
end_pnt_str:
return len;
}
/**
* Get the subject name (or the issuer) of a certificate.
*/
static int asn1_name(const uint8_t *cert, int *offset, char *dn[])
{
int ret = X509_NOT_OK;
int dn_type;
char *tmp = NULL;
if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
goto end_name;
while (asn1_next_obj(cert, offset, ASN1_SET) >= 0)
{
int i, found = 0;
if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
(dn_type = asn1_get_oid_x520(cert, offset)) < 0)
goto end_name;
if (asn1_get_printable_str(cert, offset, &tmp) < 0)
{
free(tmp);
goto end_name;
}
/* find the distinguished named type */
for (i = 0; i < X509_NUM_DN_TYPES; i++)
{
if (dn_type == g_dn_types[i])
{
if (dn[i] == NULL)
{
dn[i] = tmp;
found = 1;
break;
}
}
}
if (found == 0) /* not found so get rid of it */
{
free(tmp);
}
}
ret = X509_OK;
end_name:
return ret;
}
/**
* Read the modulus and public exponent of a certificate.
*/
static int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
{
int ret = X509_NOT_OK, mod_len, pub_len;
uint8_t *modulus, *pub_exp;
if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
asn1_skip_obj(cert, offset, ASN1_SEQUENCE) ||
asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0)
goto end_pub_key;
(*offset)++;
if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
goto end_pub_key;
mod_len = asn1_get_int(cert, offset, &modulus);
pub_len = asn1_get_int(cert, offset, &pub_exp);
RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len);
free(modulus);
free(pub_exp);
ret = X509_OK;
end_pub_key:
return ret;
}
#ifdef CONFIG_SSL_CERT_VERIFICATION
/**
* Read the signature of the certificate.
*/
static int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
{
int ret = X509_NOT_OK;
if (cert[(*offset)++] != ASN1_BIT_STRING)
goto end_sig;
x509_ctx->sig_len = get_asn1_length(cert, offset);
x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len);
memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len);
*offset += x509_ctx->sig_len;
ret = X509_OK;
end_sig:
return ret;
}
/*
* Compare 2 distinguished name components for equality
* @return 0 if a match
*/
static int asn1_compare_dn_comp(const char *dn1, const char *dn2)
{
int ret = 1;
if ((dn1 && dn2 == NULL) || (dn1 == NULL && dn2)) goto err_no_match;
ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 0;
err_no_match:
return ret;
}
/**
* Clean up all of the CA certificates.
*/
void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx)
{
int i = 0;
while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
{
x509_free(ca_cert_ctx->cert[i]);
ca_cert_ctx->cert[i++] = NULL;
}
free(ca_cert_ctx);
}
/*
* Compare 2 distinguished names for equality
* @return 0 if a match
*/
static int asn1_compare_dn(char * const dn1[], char * const dn2[])
{
int i;
for (i = 0; i < X509_NUM_DN_TYPES; i++)
{
if (asn1_compare_dn_comp(dn1[i], dn2[i]))
{
return 1;
}
}
return 0; /* all good */
}
/**
* Retrieve the signature from a certificate.
*/
const uint8_t *x509_get_signature(const uint8_t *asn1_sig, int *len)
{
int offset = 0;
const uint8_t *ptr = NULL;
if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 ||
asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
goto end_get_sig;
if (asn1_sig[offset++] != ASN1_OCTET_STRING)
goto end_get_sig;
*len = get_asn1_length(asn1_sig, &offset);
ptr = &asn1_sig[offset]; /* all ok */
end_get_sig:
return ptr;
}
#endif
/**
* Read the signature type of the certificate. We only support RSA-MD5 and
* RSA-SHA1 signature types.
*/
static int asn1_signature_type(const uint8_t *cert,
int *offset, X509_CTX *x509_ctx)
{
int ret = X509_NOT_OK, len;
if (cert[(*offset)++] != ASN1_OID)
goto end_check_sig;
len = get_asn1_length(cert, offset);
if (memcmp(sig_oid_prefix, &cert[*offset], SIG_OID_PREFIX_SIZE))
goto end_check_sig; /* unrecognised cert type */
x509_ctx->sig_type = cert[*offset + SIG_OID_PREFIX_SIZE];
*offset += len;
if (asn1_skip_obj(cert, offset, ASN1_NULL))
goto end_check_sig;
ret = X509_OK;
end_check_sig:
return ret;
}
/**
* Construct a new x509 object.
* @return 0 if ok. < 0 if there was a problem.
*/
int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
{
int begin_tbs, end_tbs;
int ret = X509_NOT_OK, offset = 0, cert_size = 0;
X509_CTX *x509_ctx;
BI_CTX *bi_ctx;
*ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
x509_ctx = *ctx;
/* get the certificate size */
asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE);
if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
goto end_cert;
begin_tbs = offset; /* start of the tbs */
end_tbs = begin_tbs; /* work out the end of the tbs */
asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
goto end_cert;
if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */
{
if (asn1_version(cert, &offset, x509_ctx))
goto end_cert;
}
if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */
asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
goto end_cert;
/* make sure the signature is ok */
if (asn1_signature_type(cert, &offset, x509_ctx))
{
ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
goto end_cert;
}
if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) ||
asn1_validity(cert, &offset, x509_ctx) ||
asn1_name(cert, &offset, x509_ctx->cert_dn) ||
asn1_public_key(cert, &offset, x509_ctx))
goto end_cert;
bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
/* use the appropriate signature algorithm (either SHA1 or MD5) */
if (x509_ctx->sig_type == SIG_TYPE_MD5)
{
MD5_CTX md5_ctx;
uint8_t md5_dgst[MD5_SIZE];
MD5Init(&md5_ctx);
MD5Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
MD5Final(&md5_ctx, md5_dgst);
x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
}
else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
{
SHA1_CTX sha_ctx;
uint8_t sha_dgst[SHA1_SIZE];
SHA1Init(&sha_ctx);
SHA1Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
SHA1Final(&sha_ctx, sha_dgst);
x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
}
offset = end_tbs; /* skip the v3 data */
if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
asn1_signature(cert, &offset, x509_ctx))
goto end_cert;
#endif
if (len)
{
*len = cert_size;
}
ret = X509_OK;
end_cert:
#ifdef CONFIG_SSL_FULL_MODE
if (ret)
{
printf("Error: Invalid X509 ASN.1 file\n");
}
#endif
return ret;
}
/**
* Free an X.509 object's resources.
*/
void x509_free(X509_CTX *x509_ctx)
{
X509_CTX *next;
int i;
if (x509_ctx == NULL) /* if already null, then don't bother */
return;
for (i = 0; i < X509_NUM_DN_TYPES; i++)
{
free(x509_ctx->ca_cert_dn[i]);
free(x509_ctx->cert_dn[i]);
}
free(x509_ctx->signature);
#ifdef CONFIG_SSL_CERT_VERIFICATION
if (x509_ctx->digest)
{
bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
}
#endif
RSA_free(x509_ctx->rsa_ctx);
next = x509_ctx->next;
free(x509_ctx);
x509_free(next); /* clear the chain */
}
#ifdef CONFIG_SSL_CERT_VERIFICATION
/**
* Do some basic checks on the certificate chain.
*
* Certificate verification consists of a number of checks:
* - A root certificate exists in the certificate store.
* - The date of the certificate is after the start date.
* - The date of the certificate is before the finish date.
* - The certificate chain is valid.
* - That the certificate(s) are not self-signed.
* - The signature of the certificate is valid.
*/
int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
{
int ret = X509_OK, i = 0;
bigint *cert_sig;
X509_CTX *next_cert = NULL;
BI_CTX *ctx;
bigint *mod, *expn;
struct timeval tv;
int match_ca_cert = 0;
if (cert == NULL || ca_cert_ctx == NULL)
{
ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
goto end_verify;
}
/* last cert in the chain - look for a trusted cert */
if (cert->next == NULL)
{
while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
{
if (asn1_compare_dn(cert->ca_cert_dn,
ca_cert_ctx->cert[i]->cert_dn) == 0)
{
match_ca_cert = 1;
break;
}
i++;
}
if (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
{
next_cert = ca_cert_ctx->cert[i];
}
else /* trusted cert not found */
{
ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
goto end_verify;
}
}
else
{
next_cert = cert->next;
}
gettimeofday(&tv, NULL);
/* check the not before date */
if (tv.tv_sec < cert->not_before)
{
ret = X509_VFY_ERROR_NOT_YET_VALID;
goto end_verify;
}
/* check the not after date */
if (tv.tv_sec > cert->not_after)
{
ret = X509_VFY_ERROR_EXPIRED;
goto end_verify;
}
/* check the chain integrity */
if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn))
{
ret = X509_VFY_ERROR_INVALID_CHAIN;
goto end_verify;
}
/* check for self-signing */
if (!match_ca_cert && asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
{
ret = X509_VFY_ERROR_SELF_SIGNED;
goto end_verify;
}
/* check the signature */
ctx = cert->rsa_ctx->bi_ctx;
mod = next_cert->rsa_ctx->m;
expn = next_cert->rsa_ctx->e;
cert_sig = RSA_sign_verify(ctx, cert->signature, cert->sig_len,
bi_clone(ctx, mod), bi_clone(ctx, expn));
if (cert_sig)
{
ret = cert->digest ? /* check the signature */
bi_compare(cert_sig, cert->digest) :
X509_VFY_ERROR_UNSUPPORTED_DIGEST;
bi_free(ctx, cert_sig);
if (ret)
goto end_verify;
}
else
{
ret = X509_VFY_ERROR_BAD_SIGNATURE;
goto end_verify;
}
/* go down the certificate chain using recursion. */
if (ret == 0 && cert->next)
{
ret = x509_verify(ca_cert_ctx, next_cert);
}
end_verify:
return ret;
}
#endif
#if defined (CONFIG_SSL_FULL_MODE)
/**
* Used for diagnostics.
*/
void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
{
if (cert == NULL)
return;
printf("---------------- CERT DEBUG ----------------\n");
printf("* CA Cert Distinguished Name\n");
if (cert->ca_cert_dn[X509_COMMON_NAME])
{
printf("Common Name (CN):\t%s\n", cert->ca_cert_dn[X509_COMMON_NAME]);
}
if (cert->ca_cert_dn[X509_ORGANIZATION])
{
printf("Organization (O):\t%s\n", cert->ca_cert_dn[X509_ORGANIZATION]);
}
if (cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE])
{
printf("Organizational Unit (OU): %s\n",
cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE]);
}
printf("* Cert Distinguished Name\n");
if (cert->cert_dn[X509_COMMON_NAME])
{
printf("Common Name (CN):\t%s\n", cert->cert_dn[X509_COMMON_NAME]);
}
if (cert->cert_dn[X509_ORGANIZATION])
{
printf("Organization (O):\t%s\n", cert->cert_dn[X509_ORGANIZATION]);
}
if (cert->cert_dn[X509_ORGANIZATIONAL_TYPE])
{
printf("Organizational Unit (OU): %s\n",
cert->cert_dn[X509_ORGANIZATIONAL_TYPE]);
}
printf("Not Before:\t\t%s", ctime(&cert->not_before));
printf("Not After:\t\t%s", ctime(&cert->not_after));
printf("RSA bitsize:\t\t%d\n", cert->rsa_ctx->num_octets*8);
printf("Sig Type:\t\t");
switch (cert->sig_type)
{
case SIG_TYPE_MD5:
printf("MD5\n");
break;
case SIG_TYPE_SHA1:
printf("SHA1\n");
break;
case SIG_TYPE_MD2:
printf("MD2\n");
break;
default:
printf("Unrecognized: %d\n", cert->sig_type);
break;
}
printf("Verify:\t\t\t");
if (ca_cert_ctx)
{
x509_display_error(x509_verify(ca_cert_ctx, cert));
}
printf("\n");
#if 0
print_blob("Signature", cert->signature, cert->sig_len);
bi_print("Modulus", cert->rsa_ctx->m);
bi_print("Pub Exp", cert->rsa_ctx->e);
#endif
if (ca_cert_ctx)
{
x509_print(ca_cert_ctx, cert->next);
}
}
void x509_display_error(int error)
{
switch (error)
{
case X509_NOT_OK:
printf("X509 not ok");
break;
case X509_VFY_ERROR_NO_TRUSTED_CERT:
printf("No trusted cert is available");
break;
case X509_VFY_ERROR_BAD_SIGNATURE:
printf("Bad signature");
break;
case X509_VFY_ERROR_NOT_YET_VALID:
printf("Cert is not yet valid");
break;
case X509_VFY_ERROR_EXPIRED:
printf("Cert has expired");
break;
case X509_VFY_ERROR_SELF_SIGNED:
printf("Cert is self-signed");
break;
case X509_VFY_ERROR_INVALID_CHAIN:
printf("Chain is invalid (check order of certs)");
break;
case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
printf("Unsupported digest");
break;
case X509_INVALID_PRIV_KEY:
printf("Invalid private key");
break;
}
}
#endif /* CONFIG_SSL_FULL_MODE */
#endif

View File

@ -77,23 +77,14 @@ static void check(const bigint *bi);
*/
BI_CTX *bi_initialize(void)
{
/* calloc() sets everything to zero */
BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX));
ctx->active_list = NULL;
ctx->active_count = 0;
ctx->free_list = NULL;
ctx->free_count = 0;
ctx->mod_offset = 0;
#ifdef CONFIG_BIGINT_MONTGOMERY
ctx->use_classical = 0;
#endif
/* the radix */
ctx->bi_radix = alloc(ctx, 2);
ctx->bi_radix->comps[0] = 0;
ctx->bi_radix->comps[1] = 1;
bi_permanent(ctx->bi_radix);
return ctx;
}
@ -285,7 +276,7 @@ bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib)
* @param bia [in] A bigint.
* @param bib [in] Another bigint.
* @param is_negative [out] If defined, indicates that the result was negative.
* is_negative may be NULL.
* is_negative may be null.
* @return The result of the subtraction. The result is always positive.
*/
bigint *bi_subtract(BI_CTX *ctx,
@ -482,7 +473,7 @@ bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod)
/*
* Perform an integer divide on a bigint.
*/
static bigint *bi_int_divide(__unused BI_CTX *ctx, bigint *biR, comp denom)
static bigint *bi_int_divide(BI_CTX *ctx __unused, bigint *biR, comp denom)
{
int i = biR->size - 1;
long_comp r = 0;
@ -781,7 +772,9 @@ void bi_free_mod(BI_CTX *ctx, int mod_offset)
*/
static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
{
int i, j, i_plus_j, n = bia->size, t = bib->size;
int i, j, i_plus_j;
int n = bia->size;
int t = bib->size;
bigint *biR = alloc(ctx, n + t);
comp *sr = biR->comps;
comp *sa = bia->comps;
@ -1059,7 +1052,7 @@ static bigint *alloc(BI_CTX *ctx, int size)
#ifdef CONFIG_SSL_FULL_MODE
printf("alloc: refs was not 0\n");
#endif
abort();
abort(); /* create a stack trace from a core dump */
}
more_comps(biR, size);
@ -1220,7 +1213,7 @@ static bigint *comp_mod(bigint *bi, int mod)
/*
* Barrett reduction has no need for some parts of the product, so ignore bits
* of the multiply. This routine gives Barrett its big performance
* improvements over classical/Montgomery reduction methods.
* improvements over Classical/Montgomery reduction methods.
*/
static bigint *partial_multiply(BI_CTX *ctx, bigint *bia, bigint *bib,
int inner_partial, int outer_partial)
@ -1293,10 +1286,10 @@ static bigint *partial_multiply(BI_CTX *ctx, bigint *bia, bigint *bib,
}
/**
* @brief Perform a single barrett reduction.
* @brief Perform a single Barrett reduction.
* @param ctx [in] The bigint session context.
* @param bi [in] A bigint.
* @return The result of the barrett reduction.
* @return The result of the Barrett reduction.
*/
bigint *bi_barrett(BI_CTX *ctx, bigint *bi)
{
@ -1308,7 +1301,7 @@ bigint *bi_barrett(BI_CTX *ctx, bigint *bi)
check(bi);
check(bim);
/* use classical method instead - Barrett cannot help here */
/* use Classical method instead - Barrett cannot help here */
if (bi->size > k*2)
{
return bi_mod(ctx, bi);
@ -1397,9 +1390,7 @@ bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)
#ifdef CONFIG_BIGINT_SLIDING_WINDOW
for (j = i; j > 32; j /= 5) /* work out an optimum size */
{
window_size++;
}
/* work out the slide constants */
precompute_slide_window(ctx, window_size, bi);
@ -1420,15 +1411,11 @@ bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)
int part_exp = 0;
if (l < 0) /* LSB of exponent will always be 1 */
{
l = 0;
}
else
{
while (exp_bit_is_one(biexp, l) == 0)
{
l++; /* go back up */
}
}
/* build up the section of the exponent */

View File

@ -74,14 +74,14 @@ bigint *bi_str_import(BI_CTX *ctx, const char *data);
* appropriate reduction technique (which is bi_mod() when doing classical
* reduction).
*/
#if defined(CONFIG_BIGINT_CLASSICAL)
#define bi_residue(A, B) bi_mod(A, B)
#if defined(CONFIG_BIGINT_MONTGOMERY)
#define bi_residue(A, B) bi_mont(A, B)
bigint *bi_mont(BI_CTX *ctx, bigint *bixy);
#elif defined(CONFIG_BIGINT_BARRETT)
#define bi_residue(A, B) bi_barrett(A, B)
bigint *bi_barrett(BI_CTX *ctx, bigint *bi);
#else /* CONFIG_BIGINT_MONTGOMERY */
#define bi_residue(A, B) bi_mont(A, B)
bigint *bi_mont(BI_CTX *ctx, bigint *bixy);
#else /* if defined(CONFIG_BIGINT_CLASSICAL) */
#define bi_residue(A, B) bi_mod(A, B)
#endif
#ifdef CONFIG_BIGINT_SQUARE

View File

@ -124,7 +124,12 @@ void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
void RNG_initialize(const uint8_t *seed_buf, int size);
void RNG_terminate(void);
void get_random(int num_rand_bytes, uint8_t *rand_data);
void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
//void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
#include <string.h>
static inline void get_random_NZ(int num_rand_bytes, uint8_t *rand_data) {
memset ( rand_data, 0x01, num_rand_bytes );
}
/**************************************************************************
* RSA declarations
@ -163,15 +168,15 @@ void RSA_pub_key_new(RSA_CTX **rsa_ctx,
const uint8_t *modulus, int mod_len,
const uint8_t *pub_exp, int pub_len);
void RSA_free(RSA_CTX *ctx);
int RSA_decrypt(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
int is_decryption);
bigint *RSA_private(RSA_CTX *c, bigint *bi_msg);
bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
#ifdef CONFIG_SSL_CERT_VERIFICATION
bigint *RSA_raw_sign_verify(RSA_CTX *c, bigint *bi_msg);
bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
bigint *modulus, bigint *pub_exp);
bigint *RSA_public(RSA_CTX *c, bigint *bi_msg);
int RSA_encrypt(RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
bigint *RSA_public(const RSA_CTX *c, bigint *bi_msg);
int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
uint8_t *out_data, int is_signing);
void RSA_print(const RSA_CTX *ctx);
#endif

View File

@ -27,9 +27,6 @@ static inline void close ( int fd __unused ) {
}
typedef void FILE;
#define SEEK_SET 0
#define SEEK_CUR 0
#define SEEK_END 0
static inline FILE * fopen ( const char *filename __unused,
const char *mode __unused ) {

View File

@ -28,7 +28,7 @@
#include "crypto.h"
#ifdef CONFIG_BIGINT_CRT
static bigint *bi_crt(RSA_CTX *rsa, bigint *bi);
static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi);
#endif
void RSA_priv_key_new(RSA_CTX **ctx,
@ -72,7 +72,7 @@ void RSA_pub_key_new(RSA_CTX **ctx,
{
RSA_CTX *rsa_ctx;
BI_CTX *bi_ctx = bi_initialize();
*ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX)); /* reset to all 0 */
*ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX));
rsa_ctx = *ctx;
rsa_ctx->bi_ctx = bi_ctx;
rsa_ctx->num_octets = (mod_len & 0xFFF0);
@ -126,8 +126,8 @@ void RSA_free(RSA_CTX *rsa_ctx)
* @return The number of bytes that were originally encrypted. -1 on error.
* @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
*/
int RSA_decrypt(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
int is_decryption)
int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data,
uint8_t *out_data, int is_decryption)
{
int byte_size = ctx->num_octets;
uint8_t *block;
@ -155,10 +155,9 @@ int RSA_decrypt(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */
{
while (block[i++] == 0xff && i < byte_size);
if (block[i-2] != 0xff)
{
i = byte_size; /*ensure size is 0 */
}
}
else /* PKCS1.5 encryption padding is random */
#endif
@ -169,9 +168,7 @@ int RSA_decrypt(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
/* get only the bit we want */
if (size > 0)
{
memcpy(out_data, &block[i], size);
}
free(block);
return size ? size : -1;
@ -180,7 +177,7 @@ int RSA_decrypt(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
/**
* Performs m = c^d mod n
*/
bigint *RSA_private(RSA_CTX *c, bigint *bi_msg)
bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg)
{
#ifdef CONFIG_BIGINT_CRT
return bi_crt(c, bi_msg);
@ -197,7 +194,7 @@ bigint *RSA_private(RSA_CTX *c, bigint *bi_msg)
* This should really be in bigint.c (and was at one stage), but needs
* access to the RSA_CTX context...
*/
static bigint *bi_crt(RSA_CTX *rsa, bigint *bi)
static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi)
{
BI_CTX *ctx = rsa->bi_ctx;
bigint *m1, *m2, *h;
@ -245,7 +242,7 @@ void RSA_print(const RSA_CTX *rsa_ctx)
/**
* Performs c = m^e mod n
*/
bigint *RSA_public(RSA_CTX *c, bigint *bi_msg)
bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg)
{
c->bi_ctx->mod_offset = BIGINT_M_OFFSET;
return bi_mod_power(c->bi_ctx, bi_msg, c->e);
@ -255,7 +252,7 @@ bigint *RSA_public(RSA_CTX *c, bigint *bi_msg)
* Use PKCS1.5 for encryption/signing.
* see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
*/
int RSA_encrypt(RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
uint8_t *out_data, int is_signing)
{
int byte_size = ctx->num_octets;
@ -273,10 +270,7 @@ int RSA_encrypt(RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
else /* randomize the encryption padding with non-zero bytes */
{
out_data[1] = 2;
memset(&out_data[2], 0x01, num_pads_needed);
#if 0
get_random_NZ(num_pads_needed, &out_data[2]);
#endif
}
out_data[2+num_pads_needed] = 0;
@ -291,18 +285,19 @@ int RSA_encrypt(RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
}
#if 0
/**
* Take a signature and decrypt it.
*/
bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
bigint *modulus, bigint *pub_exp)
{
uint8_t *block = (uint8_t *)malloc(sig_len);
uint8_t *block;
int i, size;
bigint *decrypted_bi, *dat_bi;
bigint *bir = NULL;
block = (uint8_t *)malloc(sig_len);
/* decrypt */
dat_bi = bi_import(ctx, sig, sig_len);
ctx->mod_offset = BIGINT_M_OFFSET;
@ -332,7 +327,6 @@ bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
free(block);
return bir;
}
#endif
#endif /* CONFIG_SSL_CERT_VERIFICATION */

120
src/crypto/hmac.c Normal file
View File

@ -0,0 +1,120 @@
/*
* Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* @file
*
* Keyed-Hashing for Message Authentication
*/
#include <string.h>
#include <assert.h>
#include <gpxe/crypto.h>
#include <gpxe/hmac.h>
/**
* Reduce HMAC key length
*
* @v digest Digest algorithm to use
* @v digest_ctx Digest context
* @v key Key
* @v key_len Length of key
*/
static void hmac_reduce_key ( struct crypto_algorithm *digest,
void *key, size_t *key_len ) {
uint8_t digest_ctx[digest->ctxsize];
digest_init ( digest, digest_ctx );
digest_update ( digest, digest_ctx, key, *key_len );
digest_final ( digest, digest_ctx, key );
*key_len = digest->digestsize;
}
/**
* Initialise HMAC
*
* @v digest Digest algorithm to use
* @v digest_ctx Digest context
* @v key Key
* @v key_len Length of key
*
* The length of the key should be less than the block size of the
* digest algorithm being used. (If the key length is greater, it
* will be replaced with its own digest, and key_len will be updated
* accordingly).
*/
void hmac_init ( struct crypto_algorithm *digest, void *digest_ctx,
void *key, size_t *key_len ) {
unsigned char k_ipad[digest->blocksize];
unsigned int i;
/* Reduce key if necessary */
if ( *key_len > sizeof ( k_ipad ) )
hmac_reduce_key ( digest, key, key_len );
/* Construct input pad */
memset ( k_ipad, 0, sizeof ( k_ipad ) );
memcpy ( k_ipad, key, *key_len );
for ( i = 0 ; i < sizeof ( k_ipad ) ; i++ ) {
k_ipad[i] ^= 0x36;
}
/* Start inner hash */
digest_init ( digest, digest_ctx );
digest_update ( digest, digest_ctx, k_ipad, sizeof ( k_ipad ) );
}
/**
* Finalise HMAC
*
* @v digest Digest algorithm to use
* @v digest_ctx Digest context
* @v key Key
* @v key_len Length of key
* @v hmac HMAC digest to fill in
*
* The length of the key should be less than the block size of the
* digest algorithm being used. (If the key length is greater, it
* will be replaced with its own digest, and key_len will be updated
* accordingly).
*/
void hmac_final ( struct crypto_algorithm *digest, void *digest_ctx,
void *key, size_t *key_len, void *hmac ) {
unsigned char k_opad[digest->blocksize];
unsigned int i;
/* Reduce key if necessary */
if ( *key_len > sizeof ( k_opad ) )
hmac_reduce_key ( digest, key, key_len );
/* Construct output pad */
memset ( k_opad, 0, sizeof ( k_opad ) );
memcpy ( k_opad, key, *key_len );
for ( i = 0 ; i < sizeof ( k_opad ) ; i++ ) {
k_opad[i] ^= 0x5c;
}
/* Finish inner hash */
digest_final ( digest, digest_ctx, hmac );
/* Perform outer hash */
digest_init ( digest, digest_ctx );
digest_update ( digest, digest_ctx, k_opad, sizeof ( k_opad ) );
digest_update ( digest, digest_ctx, hmac, digest->digestsize );
digest_final ( digest, digest_ctx, hmac );
}

View File

@ -54,7 +54,7 @@ static u32 __md5step f4(u32 b, u32 c, u32 d)
return ( c ^ ( b | ~d ) );
}
struct md5_step md5_steps[4] = {
static struct md5_step md5_steps[4] = {
{
.f = f1,
.coefficient = 1,

View File

@ -153,6 +153,10 @@ static int spi_bit_rw ( struct spi_bus *bus, struct spi_device *device,
= container_of ( bus, struct spi_bit_basher, bus );
uint32_t tmp;
/* Set clock line to idle state */
write_bit ( &spibit->basher, SPI_BIT_SCLK,
( bus->mode & SPI_MODE_CPOL ) );
/* Assert chip select on specified slave */
spi_bit_set_slave_select ( spibit, device->slave, SELECT_SLAVE );

View File

@ -43,7 +43,7 @@ static struct bss {
struct statistics_block stats_blk;
} bnx2_bss;
struct bnx2 bnx2;
static struct bnx2 bnx2;
static struct flash_spec flash_table[] =
{

View File

@ -364,7 +364,7 @@ struct ring_desc {
#endif
/* Private Storage for the NIC */
struct ns83820_private {
static struct ns83820_private {
u8 *base;
int up;
long idle;

View File

@ -67,7 +67,7 @@ static struct nic_operations pcnet32_operations;
/* End Etherboot Specific */
int cards_found /* __initdata */ ;
static int cards_found = 0 /* __initdata */ ;
#ifdef REMOVE
/* FIXME: Remove these they are probably pointless */

View File

@ -400,7 +400,7 @@ static void rtl8169_hw_PHY_config(struct nic *nic __unused);
// 20-16 5-bit GMII/MII register address
// 15-0 16-bit GMII/MII register data
//=================================================================
void RTL8169_WRITE_GMII_REG(unsigned long ioaddr, int RegAddr, int value)
static void RTL8169_WRITE_GMII_REG(unsigned long ioaddr, int RegAddr, int value)
{
int i;
@ -418,7 +418,7 @@ void RTL8169_WRITE_GMII_REG(unsigned long ioaddr, int RegAddr, int value)
}
//=================================================================
int RTL8169_READ_GMII_REG(unsigned long ioaddr, int RegAddr)
static int RTL8169_READ_GMII_REG(unsigned long ioaddr, int RegAddr)
{
int i, value = -1;

View File

@ -1204,7 +1204,7 @@ struct velocity_info_tbl {
u32 flags;
};
struct velocity_info_tbl *info;
static struct velocity_info_tbl *info;
#define mac_hw_mibs_init(regs) {\
BYTE_REG_BITS_ON(MIBCR_MIBFRZ,&((regs)->MIBCR));\
@ -1768,7 +1768,7 @@ struct velocity_opt {
#define TX_DESC_MAX 256
#define TX_DESC_DEF TX_DESC_MIN
struct velocity_info {
static struct velocity_info {
// struct list_head list;
struct pci_device *pdev;

View File

@ -45,7 +45,8 @@
* @v nargs Argument count
* @v args Argument list
*/
void imgfill_cmdline ( struct image *image, unsigned int nargs, char **args ) {
static void imgfill_cmdline ( struct image *image, unsigned int nargs,
char **args ) {
size_t used = 0;
image->cmdline[0] = '\0';

View File

@ -19,18 +19,7 @@ int m_delay; /*
bool m_echo;
bool m_cbreak;
/**
* Check KEY_ code supported status
*
* @v kc keycode value to check
* @ret TRUE KEY_* supported
* @ret FALSE KEY_* unsupported
*/
int has_key ( int kc __unused ) {
return TRUE;
}
int _wgetc ( WINDOW *win ) {
static int _wgetc ( WINDOW *win ) {
int timer, c;
if ( win == NULL )

View File

@ -50,7 +50,7 @@ struct _softlabelkeys {
short saved_pair;
};
struct _softlabelkeys *slks;
static struct _softlabelkeys *slks;
/*
I either need to break the primitives here, or write a collection of

View File

@ -276,6 +276,9 @@ extern void dbg_hex_dump_da ( unsigned long dispaddr,
/** Declare a variable or data structure as unused. */
#define __unused __attribute__ (( unused ))
/** Apply standard C calling conventions */
#define __cdecl __attribute__ (( cdecl , regparm(0) ))
/**
* Declare a function as used.
*

View File

@ -566,6 +566,10 @@ static inline bool has_colors ( void ) {
return TRUE;
}
static inline int has_key ( int kc __unused ) {
return TRUE;
}
static inline int hline ( chtype ch, int n ) {
return whline ( stdscr, ch, n );
}

35
src/include/gpxe/abft.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _GPXE_ABFT_H
#define _GPXE_ABFT_H
/** @file
*
* AoE boot firmware table
*
*/
#include <stdint.h>
#include <gpxe/acpi.h>
#include <gpxe/if_ether.h>
/** AoE boot firmware table signature */
#define ABFT_SIG "aBFT"
/**
* AoE Boot Firmware Table (aBFT)
*/
struct abft_table {
/** ACPI header */
struct acpi_description_header acpi;
/** AoE shelf */
uint16_t shelf;
/** AoE slot */
uint8_t slot;
/** Reserved */
uint8_t reserved_a;
/** MAC address */
uint8_t mac[ETH_ALEN];
} __attribute__ (( packed ));
extern void abft_fill_data ( struct aoe_session *aoe );
#endif /* _GPXE_ABFT_H */

View File

@ -81,6 +81,9 @@ struct aoehdr {
/** An AoE session */
struct aoe_session {
/** Reference counter */
struct refcnt refcnt;
/** List of all AoE sessions */
struct list_head list;
@ -103,8 +106,8 @@ struct aoe_session {
unsigned int status;
/** Byte offset within command's data buffer */
unsigned int command_offset;
/** Asynchronous operation for this command */
struct async async;
/** Return status code for command */
int rc;
/** Retransmission timer */
struct retry_timer timer;
@ -116,20 +119,8 @@ struct aoe_session {
/** Maximum number of sectors per packet */
#define AOE_MAX_COUNT 2
extern void aoe_open ( struct aoe_session *aoe );
extern void aoe_close ( struct aoe_session *aoe );
extern int aoe_issue ( struct aoe_session *aoe,
struct ata_command *command,
struct async *parent );
/** An AoE device */
struct aoe_device {
/** ATA device interface */
struct ata_device ata;
/** AoE protocol instance */
struct aoe_session aoe;
};
extern int init_aoedev ( struct aoe_device *aoedev );
extern void aoe_detach ( struct ata_device *ata );
extern int aoe_attach ( struct ata_device *ata, struct net_device *netdev,
const char *root_path );
#endif /* _GPXE_AOE_H */

View File

@ -4,6 +4,7 @@
#include <stdint.h>
#include <gpxe/blockdev.h>
#include <gpxe/uaccess.h>
#include <gpxe/refcnt.h>
/** @file
*
@ -195,6 +196,8 @@ struct ata_device {
*/
int ( * command ) ( struct ata_device *ata,
struct ata_command *command );
/** Backing device */
struct refcnt *backend;
};
extern int init_atadev ( struct ata_device *ata );

View File

@ -168,6 +168,19 @@ struct job_interface;
*/
#define DHCP_EB_SIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 3 )
/** Network device descriptor
*
* Byte 0 is the bus type ID; remaining bytes depend on the bus type.
*
* PCI devices:
* Byte 0 : 1 (PCI)
* Byte 1 : PCI vendor ID MSB
* Byte 2 : PCI vendor ID LSB
* Byte 3 : PCI device ID MSB
* Byte 4 : PCI device ID LSB
*/
#define DHCP_EB_BUS_ID DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb1 )
/** BIOS drive number
*
* This is the drive number for a drive emulated via INT 13. 0x80 is
@ -503,15 +516,19 @@ extern void find_global_dhcp_ipv4_option ( unsigned int tag,
struct in_addr *inp );
extern void delete_dhcp_option ( struct dhcp_option_block *options,
unsigned int tag );
extern int apply_dhcp_options ( struct dhcp_option_block *options );
extern int apply_global_dhcp_options ( void );
extern struct dhcp_option_block dhcp_request_options;
extern int create_dhcp_packet ( struct net_device *netdev, uint8_t msgtype,
void *data, size_t max_len,
struct dhcp_packet *dhcppkt );
extern int copy_dhcp_packet_options ( struct dhcp_packet *dhcppkt,
struct dhcp_option_block *options );
extern int create_dhcp_request ( struct net_device *netdev, int msgtype,
struct dhcp_option_block *options,
void *data, size_t max_len,
struct dhcp_packet *dhcppkt );
extern int create_dhcp_response ( struct net_device *netdev, int msgtype,
struct dhcp_option_block *options,
void *data, size_t max_len,
struct dhcp_packet *dhcppkt );
extern int start_dhcp ( struct job_interface *job, struct net_device *netdev,
int (*register_options) ( struct net_device *,
struct dhcp_option_block * ));

View File

@ -115,6 +115,8 @@
#define ERRFILE_cipher ( ERRFILE_OTHER | 0x00090000 )
#define ERRFILE_image_cmd ( ERRFILE_OTHER | 0x000a0000 )
#define ERRFILE_uri_test ( ERRFILE_OTHER | 0x000b0000 )
#define ERRFILE_ibft ( ERRFILE_OTHER | 0x000c0000 )
#define ERRFILE_tls ( ERRFILE_OTHER | 0x000d0000 )
/** @} */

75
src/include/gpxe/filter.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef _GPXE_FILTER_H
#define _GPXE_FILTER_H
/** @file
*
* Data transfer filters
*
*/
#include <stddef.h>
#include <gpxe/xfer.h>
/**
* Half of a data transfer filter
*
* Embed two of these structures within a structure implementing a
* data transfer filter, and intialise with filter_init(). You can
* then use the filter_xxx() methods as the data transfer interface
* methods as required.
*/
struct xfer_filter_half {
/** Data transfer interface */
struct xfer_interface xfer;
/** Other half of the data transfer filter */
struct xfer_filter_half *other;
};
/**
* Get data transfer interface for the other half of a data transfer filter
*
* @v xfer Data transfer interface
* @ret other Other half's data transfer interface
*/
static inline __attribute__ (( always_inline )) struct xfer_interface *
filter_other_half ( struct xfer_interface *xfer ) {
struct xfer_filter_half *half =
container_of ( xfer, struct xfer_filter_half, xfer );
return &half->other->xfer;
}
extern void filter_close ( struct xfer_interface *xfer, int rc );
extern int filter_vredirect ( struct xfer_interface *xfer, int type,
va_list args );
extern int filter_seek ( struct xfer_interface *xfer, off_t offset,
int whence );
extern size_t filter_window ( struct xfer_interface *xfer );
extern struct io_buffer * filter_alloc_iob ( struct xfer_interface *xfer,
size_t len );
extern int filter_deliver_iob ( struct xfer_interface *xfer,
struct io_buffer *iobuf,
struct xfer_metadata *meta );
extern int filter_deliver_raw ( struct xfer_interface *xfer, const void *data,
size_t len );
/**
* Initialise a data transfer filter
*
* @v left "Left" half of the filter
* @v left_op Data transfer interface operations for "left" half
* @v right "Right" half of the filter
* @v right_op Data transfer interface operations for "right" half
* @v refcnt Containing object reference counter, or NULL
*/
static inline void filter_init ( struct xfer_filter_half *left,
struct xfer_interface_operations *left_op,
struct xfer_filter_half *right,
struct xfer_interface_operations *right_op,
struct refcnt *refcnt ) {
xfer_init ( &left->xfer, left_op, refcnt );
xfer_init ( &right->xfer, right_op, refcnt );
left->other = right;
right->other = left;
}
#endif /* _GPXE_FILTER_H */

30
src/include/gpxe/hmac.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef _GPXE_HMAC_H
#define _GPXE_HMAC_H
/** @file
*
* Keyed-Hashing for Message Authentication
*/
#include <gpxe/crypto.h>
/**
* Update HMAC
*
* @v digest Digest algorithm to use
* @v digest_ctx Digest context
* @v data Data
* @v len Length of data
*/
static inline void hmac_update ( struct crypto_algorithm *digest,
void *digest_ctx, const void *data,
size_t len ) {
digest_update ( digest, digest_ctx, data, len );
}
extern void hmac_init ( struct crypto_algorithm *digest, void *digest_ctx,
void *key, size_t *key_len );
extern void hmac_final ( struct crypto_algorithm *digest, void *digest_ctx,
void *key, size_t *key_len, void *hmac );
#endif /* _GPXE_HMAC_H */

View File

@ -13,4 +13,9 @@
/** HTTPS default port */
#define HTTPS_PORT 443
extern int http_open_filter ( struct xfer_interface *xfer, struct uri *uri,
unsigned int default_port,
int ( * filter ) ( struct xfer_interface *,
struct xfer_interface ** ) );
#endif /* _GPXE_HTTP_H */

View File

@ -8,6 +8,7 @@
*/
#include <stdint.h>
#include <gpxe/socket.h>
#include <gpxe/scsi.h>
#include <gpxe/chap.h>
#include <gpxe/refcnt.h>
@ -501,6 +502,8 @@ struct iscsi_session {
char *target_iqn;
/** Logical Unit Number (LUN) */
uint64_t lun;
/** Target socket address (recorded only for iBFT) */
struct sockaddr target_sockaddr;
/** Session status
*
@ -514,6 +517,11 @@ struct iscsi_session {
* Reset upon a successful connection.
*/
int retry_count;
/** Username (if any) */
char *username;
/** Password (if any) */
char *password;
/** CHAP challenge/response */
struct chap_challenge chap;
@ -641,5 +649,6 @@ struct iscsi_session {
extern int iscsi_attach ( struct scsi_device *scsi, const char *root_path );
extern void iscsi_detach ( struct scsi_device *scsi );
extern const char * iscsi_initiator_iqn ( void );
#endif /* _GPXE_ISCSI_H */

View File

@ -7,6 +7,7 @@
*
*/
#include <stdarg.h>
#include <gpxe/tables.h>
struct xfer_interface;

View File

@ -1,12 +1,171 @@
#ifndef _GPXE_TLS_H
#define _GPXE_TLS_H
#include <errno.h>
/**
* @file
*
* Transport Layer Security Protocol
*/
struct stream_application;
#include <stdint.h>
#include <gpxe/refcnt.h>
#include <gpxe/filter.h>
#include <gpxe/process.h>
#include <gpxe/crypto.h>
#include <gpxe/md5.h>
#include <gpxe/sha1.h>
static inline int add_tls ( struct stream_application *app __unused ) {
return -ENOTSUP;
}
/** A TLS header */
struct tls_header {
/** Content type
*
* This is a TLS_TYPE_XXX constant
*/
uint8_t type;
/** Protocol version
*
* This is a TLS_VERSION_XXX constant
*/
uint16_t version;
/** Length of payload */
uint16_t length;
} __attribute__ (( packed ));
/** TLS version 1.0 */
#define TLS_VERSION_TLS_1_0 0x0301
/** TLS version 1.1 */
#define TLS_VERSION_TLS_1_1 0x0302
/** Change cipher content type */
#define TLS_TYPE_CHANGE_CIPHER 20
/** Alert content type */
#define TLS_TYPE_ALERT 21
/** Handshake content type */
#define TLS_TYPE_HANDSHAKE 22
/** Application data content type */
#define TLS_TYPE_DATA 23
/* Handshake message types */
#define TLS_HELLO_REQUEST 0
#define TLS_CLIENT_HELLO 1
#define TLS_SERVER_HELLO 2
#define TLS_CERTIFICATE 11
#define TLS_SERVER_KEY_EXCHANGE 12
#define TLS_CERTIFICATE_REQUEST 13
#define TLS_SERVER_HELLO_DONE 14
#define TLS_CERTIFICATE_VERIFY 15
#define TLS_CLIENT_KEY_EXCHANGE 16
#define TLS_FINISHED 20
/* TLS alert levels */
#define TLS_ALERT_WARNING 1
#define TLS_ALERT_FATAL 2
/* TLS cipher specifications */
#define TLS_RSA_WITH_NULL_MD5 0x0001
#define TLS_RSA_WITH_NULL_SHA 0x0002
#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002f
#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035
/** TLS RX state machine state */
enum tls_rx_state {
TLS_RX_HEADER = 0,
TLS_RX_DATA,
};
/** TLS TX state machine state */
enum tls_tx_state {
TLS_TX_NONE = 0,
TLS_TX_CLIENT_HELLO,
TLS_TX_CLIENT_KEY_EXCHANGE,
TLS_TX_CHANGE_CIPHER,
TLS_TX_FINISHED,
TLS_TX_DATA
};
/** A TLS cipher specification */
struct tls_cipherspec {
/** Public-key encryption algorithm */
struct crypto_algorithm *pubkey;
/** Bulk encryption cipher algorithm */
struct crypto_algorithm *cipher;
/** MAC digest algorithm */
struct crypto_algorithm *digest;
/** Key length */
size_t key_len;
/** Dynamically-allocated storage */
void *dynamic;
/** Public key encryption context */
void *pubkey_ctx;
/** Bulk encryption cipher context */
void *cipher_ctx;
/** Next bulk encryption cipher context (TX only) */
void *cipher_next_ctx;
/** MAC secret */
void *mac_secret;
};
/** A TLS session */
struct tls_session {
/** Reference counter */
struct refcnt refcnt;
/** Plaintext stream */
struct xfer_filter_half plainstream;
/** Ciphertext stream */
struct xfer_filter_half cipherstream;
/** Current TX cipher specification */
struct tls_cipherspec tx_cipherspec;
/** Next TX cipher specification */
struct tls_cipherspec tx_cipherspec_pending;
/** Current RX cipher specification */
struct tls_cipherspec rx_cipherspec;
/** Next RX cipher specification */
struct tls_cipherspec rx_cipherspec_pending;
/** Premaster secret */
uint8_t pre_master_secret[48];
/** Master secret */
uint8_t master_secret[48];
/** Server random bytes */
uint8_t server_random[32];
/** Client random bytes */
uint8_t client_random[32];
/** MD5 context for handshake verification */
uint8_t handshake_md5_ctx[MD5_CTX_SIZE];
/** SHA1 context for handshake verification */
uint8_t handshake_sha1_ctx[SHA1_CTX_SIZE];
/** Hack: server RSA public key */
uint8_t *rsa_mod;
size_t rsa_mod_len;
uint8_t *rsa_pub_exp;
size_t rsa_pub_exp_len;
/** TX sequence number */
uint64_t tx_seq;
/** TX state */
enum tls_tx_state tx_state;
/** TX process */
struct process process;
/** RX sequence number */
uint64_t rx_seq;
/** RX state */
enum tls_rx_state rx_state;
/** Offset within current RX state */
size_t rx_rcvd;
/** Current received record header */
struct tls_header rx_header;
/** Current received raw data buffer */
void *rx_data;
};
extern int add_tls ( struct xfer_interface *xfer,
struct xfer_interface **next );
#endif /* _GPXE_TLS_H */

View File

@ -0,0 +1,6 @@
#ifndef _USR_AOEBOOT_H
#define _USR_AOEBOOT_H
extern int aoeboot ( const char *root_path );
#endif /* _USR_AOEBOOT_H */

View File

@ -69,10 +69,12 @@ PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
*get_cached_info ) {
struct dhcp_packet dhcppkt;
int ( * dhcp_packet_creator ) ( struct net_device *, int,
struct dhcp_option_block *, void *,
size_t, struct dhcp_packet * );
unsigned int msgtype;
void *data = NULL;
size_t len;
int msgtype;
struct dhcp_option_block *options;
userptr_t buffer;
int rc;
@ -102,21 +104,17 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
/* Construct DHCP packet */
if ( get_cached_info->PacketType == PXENV_PACKET_TYPE_DHCP_DISCOVER ) {
dhcp_packet_creator = create_dhcp_request;
msgtype = DHCPDISCOVER;
options = &dhcp_request_options;
} else {
dhcp_packet_creator = create_dhcp_response;
msgtype = DHCPACK;
options = NULL;
}
if ( ( rc = create_dhcp_packet ( pxe_netdev, msgtype, data, len,
&dhcppkt ) ) != 0 ) {
if ( ( rc = dhcp_packet_creator ( pxe_netdev, msgtype, NULL,
data, len, &dhcppkt ) ) != 0 ) {
DBG ( " failed to build packet" );
goto err;
}
if ( ( rc = copy_dhcp_packet_options ( &dhcppkt, options ) ) != 0 ) {
DBG ( " failed to copy options" );
goto err;
}
/* Overwrite filename to work around Microsoft RIS bug */
if ( pxe_ris_filename ) {

26
src/libgcc/__divdi3.c Normal file
View File

@ -0,0 +1,26 @@
/*
* arch/i386/libgcc/__divdi3.c
*/
#include "libgcc.h"
LIBGCC int64_t __divdi3(int64_t num, int64_t den)
{
int minus = 0;
int64_t v;
if ( num < 0 ) {
num = -num;
minus = 1;
}
if ( den < 0 ) {
den = -den;
minus ^= 1;
}
v = __udivmoddi4(num, den, NULL);
if ( minus )
v = -v;
return v;
}

26
src/libgcc/__moddi3.c Normal file
View File

@ -0,0 +1,26 @@
/*
* arch/i386/libgcc/__moddi3.c
*/
#include "libgcc.h"
LIBGCC int64_t __moddi3(int64_t num, int64_t den)
{
int minus = 0;
int64_t v;
if ( num < 0 ) {
num = -num;
minus = 1;
}
if ( den < 0 ) {
den = -den;
minus ^= 1;
}
(void) __udivmoddi4(num, den, (uint64_t *)&v);
if ( minus )
v = -v;
return v;
}

10
src/libgcc/__udivdi3.c Normal file
View File

@ -0,0 +1,10 @@
/*
* arch/i386/libgcc/__divdi3.c
*/
#include "libgcc.h"
LIBGCC uint64_t __udivdi3(uint64_t num, uint64_t den)
{
return __udivmoddi4(num, den, NULL);
}

32
src/libgcc/__udivmoddi4.c Normal file
View File

@ -0,0 +1,32 @@
#include "libgcc.h"
LIBGCC uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem_p)
{
uint64_t quot = 0, qbit = 1;
if ( den == 0 ) {
return 1/((unsigned)den); /* Intentional divide by zero, without
triggering a compiler warning which
would abort the build */
}
/* Left-justify denominator and count shift */
while ( (int64_t)den >= 0 ) {
den <<= 1;
qbit <<= 1;
}
while ( qbit ) {
if ( den <= num ) {
num -= den;
quot += qbit;
}
den >>= 1;
qbit >>= 1;
}
if ( rem_p )
*rem_p = num;
return quot;
}

13
src/libgcc/__umoddi3.c Normal file
View File

@ -0,0 +1,13 @@
/*
* arch/i386/libgcc/__umoddi3.c
*/
#include "libgcc.h"
LIBGCC uint64_t __umoddi3(uint64_t num, uint64_t den)
{
uint64_t v;
(void) __udivmoddi4(num, den, &v);
return v;
}

26
src/libgcc/libgcc.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _LIBGCC_H
#define _LIBGCC_H
#include <stdint.h>
#include <stddef.h>
/*
* It seems as though gcc expects its implicit arithmetic functions to
* be cdecl, even if -mrtd is specified. This is somewhat
* inconsistent; for example, if -mregparm=3 is used then the implicit
* functions do become regparm(3).
*
* The implicit calls to memcpy() and memset() which gcc can generate
* do not seem to have this inconsistency; -mregparm and -mrtd affect
* them in the same way as any other function.
*
*/
#define LIBGCC __attribute__ (( cdecl ))
extern LIBGCC uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem);
extern LIBGCC uint64_t __udivdi3(uint64_t num, uint64_t den);
extern LIBGCC uint64_t __umoddi3(uint64_t num, uint64_t den);
extern LIBGCC int64_t __divdi3(int64_t num, int64_t den);
extern LIBGCC int64_t __moddi3(int64_t num, int64_t den);
#endif /* _LIBGCC_H */

View File

@ -1,6 +1,4 @@
/** @file
*
* gcc implicit functions
*
* gcc sometimes likes to insert implicit calls to memcpy().
* Unfortunately, there doesn't seem to be any way to prevent it from

View File

@ -19,6 +19,7 @@
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
@ -29,7 +30,7 @@
#include <gpxe/uaccess.h>
#include <gpxe/ata.h>
#include <gpxe/netdevice.h>
#include <gpxe/async.h>
#include <gpxe/process.h>
#include <gpxe/aoe.h>
/** @file
@ -43,6 +44,14 @@ struct net_protocol aoe_protocol;
/** List of all AoE sessions */
static LIST_HEAD ( aoe_sessions );
static void aoe_free ( struct refcnt *refcnt ) {
struct aoe_session *aoe =
container_of ( refcnt, struct aoe_session, refcnt );
netdev_put ( aoe->netdev );
free ( aoe );
}
/**
* Mark current AoE command complete
*
@ -55,8 +64,8 @@ static void aoe_done ( struct aoe_session *aoe, int rc ) {
aoe->command->cb.cmd_stat = aoe->status;
aoe->command = NULL;
/* Mark async operation as complete */
async_done ( &aoe->async, rc );
/* Mark operation as complete */
aoe->rc = rc;
}
/**
@ -265,46 +274,99 @@ struct net_protocol aoe_protocol __net_protocol = {
.rx = aoe_rx,
};
/**
* Open AoE session
*
* @v aoe AoE session
*/
void aoe_open ( struct aoe_session *aoe ) {
memcpy ( aoe->target, ethernet_protocol.ll_broadcast,
sizeof ( aoe->target ) );
aoe->tag = AOE_TAG_MAGIC;
aoe->timer.expired = aoe_timer_expired;
list_add ( &aoe->list, &aoe_sessions );
}
/**
* Close AoE session
*
* @v aoe AoE session
*/
void aoe_close ( struct aoe_session *aoe ) {
list_del ( &aoe->list );
}
/**
* Issue ATA command via an open AoE session
*
* @v aoe AoE session
* @v ata ATA device
* @v command ATA command
* @v parent Parent asynchronous operation
* @ret rc Return status code
*
* Only one command may be issued concurrently per session. This call
* is non-blocking; use async_wait() to wait for the command to
* complete.
*/
int aoe_issue ( struct aoe_session *aoe, struct ata_command *command,
struct async *parent ) {
static int aoe_command ( struct ata_device *ata,
struct ata_command *command ) {
struct aoe_session *aoe =
container_of ( ata->backend, struct aoe_session, refcnt );
int rc;
aoe->command = command;
aoe->status = 0;
aoe->command_offset = 0;
aoe_send_command ( aoe );
async_init ( &aoe->async, &default_async_operations, parent );
aoe->rc = -EINPROGRESS;
while ( aoe->rc == -EINPROGRESS )
step();
rc = aoe->rc;
return rc;
}
static int aoe_detached_command ( struct ata_device *ata __unused,
struct ata_command *command __unused ) {
return -ENODEV;
}
void aoe_detach ( struct ata_device *ata ) {
struct aoe_session *aoe =
container_of ( ata->backend, struct aoe_session, refcnt );
stop_timer ( &aoe->timer );
ata->command = aoe_detached_command;
list_del ( &aoe->list );
ref_put ( ata->backend );
ata->backend = NULL;
}
static int aoe_parse_root_path ( struct aoe_session *aoe,
const char *root_path ) {
char *ptr;
if ( strncmp ( root_path, "aoe:", 4 ) != 0 )
return -EINVAL;
ptr = ( ( char * ) root_path + 4 );
if ( *ptr++ != 'e' )
return -EINVAL;
aoe->major = strtoul ( ptr, &ptr, 10 );
if ( *ptr++ != '.' )
return -EINVAL;
aoe->minor = strtoul ( ptr, &ptr, 10 );
if ( *ptr )
return -EINVAL;
return 0;
}
int aoe_attach ( struct ata_device *ata, struct net_device *netdev,
const char *root_path ) {
struct aoe_session *aoe;
int rc;
/* Allocate and initialise structure */
aoe = zalloc ( sizeof ( *aoe ) );
if ( ! aoe )
return -ENOMEM;
aoe->refcnt.free = aoe_free;
aoe->netdev = netdev_get ( netdev );
memcpy ( aoe->target, ethernet_protocol.ll_broadcast,
sizeof ( aoe->target ) );
aoe->tag = AOE_TAG_MAGIC;
aoe->timer.expired = aoe_timer_expired;
/* Parse root path */
if ( ( rc = aoe_parse_root_path ( aoe, root_path ) ) != 0 )
goto err;
/* Attach parent interface, transfer reference to connection
* list, and return
*/
ata->backend = ref_get ( &aoe->refcnt );
ata->command = aoe_command;
list_add ( &aoe->list, &aoe_sessions );
return 0;
err:
ref_put ( &aoe->refcnt );
return rc;
}

View File

@ -65,8 +65,9 @@ ndp_find_entry ( struct in6_addr *in6 ) {
* @v ll_addr Link-layer address
* @v state State of the entry - one of the NDP_STATE_XXX values
*/
void add_ndp_entry ( struct net_device *netdev, struct in6_addr *in6,
void *ll_addr, int state ) {
static void
add_ndp_entry ( struct net_device *netdev, struct in6_addr *in6,
void *ll_addr, int state ) {
struct ndp_entry *ndp;
ndp = &ndp_table[next_new_ndp_entry++ % NUM_NDP_ENTRIES];

View File

@ -40,7 +40,6 @@
#include <gpxe/tcpip.h>
#include <gpxe/process.h>
#include <gpxe/linebuf.h>
#include <gpxe/tls.h>
#include <gpxe/http.h>
/** HTTP receive state */
@ -459,15 +458,21 @@ static struct xfer_interface_operations http_xfer_operations = {
};
/**
* Initiate an HTTP connection
* Initiate an HTTP connection, with optional filter
*
* @v xfer Data transfer interface
* @v uri Uniform Resource Identifier
* @v default_port Default port number
* @v filter Filter to apply to socket, or NULL
* @ret rc Return status code
*/
int http_open ( struct xfer_interface *xfer, struct uri *uri ) {
int http_open_filter ( struct xfer_interface *xfer, struct uri *uri,
unsigned int default_port,
int ( * filter ) ( struct xfer_interface *xfer,
struct xfer_interface **next ) ) {
struct http_request *http;
struct sockaddr_tcpip server;
struct xfer_interface *socket;
int rc;
/* Sanity checks */
@ -486,20 +491,17 @@ int http_open ( struct xfer_interface *xfer, struct uri *uri ) {
/* Open socket */
memset ( &server, 0, sizeof ( server ) );
server.st_port = htons ( uri_port ( http->uri, HTTP_PORT ) );
if ( ( rc = xfer_open_named_socket ( &http->socket, SOCK_STREAM,
server.st_port = htons ( uri_port ( http->uri, default_port ) );
socket = &http->socket;
if ( filter ) {
if ( ( rc = filter ( socket, &socket ) ) != 0 )
goto err;
}
if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM,
( struct sockaddr * ) &server,
uri->host, NULL ) ) != 0 )
goto err;
#if 0
if ( strcmp ( http->uri->scheme, "https" ) == 0 ) {
st->st_port = htons ( uri_port ( http->uri, HTTPS_PORT ) );
if ( ( rc = add_tls ( &http->stream ) ) != 0 )
goto err;
}
#endif
/* Attach to parent interface, mortalise self, and return */
xfer_plug_plug ( &http->xfer, xfer );
ref_put ( &http->refcnt );
@ -513,14 +515,19 @@ int http_open ( struct xfer_interface *xfer, struct uri *uri ) {
return rc;
}
/**
* Initiate an HTTP connection
*
* @v xfer Data transfer interface
* @v uri Uniform Resource Identifier
* @ret rc Return status code
*/
static int http_open ( struct xfer_interface *xfer, struct uri *uri ) {
return http_open_filter ( xfer, uri, HTTP_PORT, NULL );
}
/** HTTP URI opener */
struct uri_opener http_uri_opener __uri_opener = {
.scheme = "http",
.open = http_open,
};
/** HTTPS URI opener */
struct uri_opener https_uri_opener __uri_opener = {
.scheme = "https",
.open = http_open,
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
* Copyright (C) 2007 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
@ -16,40 +16,31 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stddef.h>
#include <gpxe/async.h>
#include <gpxe/aoe.h>
/** @file
/**
* @file
*
* AoE ATA device
* Secure Hyper Text Transfer Protocol (HTTPS)
*
*/
#include <stddef.h>
#include <gpxe/open.h>
#include <gpxe/tls.h>
#include <gpxe/http.h>
/**
* Issue ATA command via AoE device
* Initiate an HTTPS connection
*
* @v ata ATA device
* @v command ATA command
* @v xfer Data transfer interface
* @v uri Uniform Resource Identifier
* @ret rc Return status code
*/
static int aoe_command ( struct ata_device *ata,
struct ata_command *command ) {
struct aoe_device *aoedev
= container_of ( ata, struct aoe_device, ata );
struct async async;
return async_block ( &async, aoe_issue ( &aoedev->aoe, command,
&async ) );
static int https_open ( struct xfer_interface *xfer, struct uri *uri ) {
return http_open_filter ( xfer, uri, HTTPS_PORT, add_tls );
}
/**
* Initialise AoE device
*
* @v aoedev AoE device
*/
int init_aoedev ( struct aoe_device *aoedev ) {
aoedev->ata.command = aoe_command;
aoe_open ( &aoedev->aoe );
return init_atadev ( &aoedev->ata );
}
/** HTTPS URI opener */
struct uri_opener https_uri_opener __uri_opener = {
.scheme = "https",
.open = https_open,
};

View File

@ -41,16 +41,16 @@
*/
/** iSCSI initiator name (explicitly specified) */
char *iscsi_initiator_iqn;
static char *iscsi_explicit_initiator_iqn;
/** Default iSCSI initiator name (constructed from hostname) */
char *iscsi_default_initiator_iqn;
static char *iscsi_default_initiator_iqn;
/** iSCSI username */
char *iscsi_username;
static char *iscsi_username;
/** iSCSI password */
char *iscsi_password;
static char *iscsi_password;
static void iscsi_start_tx ( struct iscsi_session *iscsi );
static void iscsi_start_login ( struct iscsi_session *iscsi );
@ -78,6 +78,8 @@ static void iscsi_free ( struct refcnt *refcnt ) {
free ( iscsi->target_address );
free ( iscsi->target_iqn );
free ( iscsi->username );
free ( iscsi->password );
chap_finish ( &iscsi->chap );
iscsi_rx_buffered_data_done ( iscsi );
free ( iscsi );
@ -436,22 +438,16 @@ static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
*/
static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
void *data, size_t len ) {
char *initiator_iqn;
unsigned int used = 0;
unsigned int i;
if ( iscsi->status & ISCSI_STATUS_STRINGS_SECURITY ) {
initiator_iqn = iscsi_initiator_iqn;
if ( ! initiator_iqn )
initiator_iqn = iscsi_default_initiator_iqn;
if ( ! initiator_iqn )
initiator_iqn = "iqn.2000-09.org.etherboot:UNKNOWN";
used += ssnprintf ( data + used, len - used,
"InitiatorName=%s%c"
"TargetName=%s%c"
"SessionType=Normal%c"
"AuthMethod=CHAP,None%c",
initiator_iqn, 0,
iscsi_initiator_iqn(), 0,
iscsi->target_iqn, 0, 0, 0 );
}
@ -460,10 +456,10 @@ static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
}
if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_RESPONSE ) &&
iscsi_username ) {
iscsi->username ) {
used += ssnprintf ( data + used, len - used,
"CHAP_N=%s%cCHAP_R=0x",
iscsi_username, 0 );
iscsi->username, 0 );
for ( i = 0 ; i < iscsi->chap.response_len ; i++ ) {
used += ssnprintf ( data + used, len - used, "%02x",
iscsi->chap.response[i] );
@ -647,9 +643,9 @@ static int iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
* challenge.
*/
chap_set_identifier ( &iscsi->chap, identifier );
if ( iscsi_password ) {
chap_update ( &iscsi->chap, iscsi_password,
strlen ( iscsi_password ) );
if ( iscsi->password ) {
chap_update ( &iscsi->chap, iscsi->password,
strlen ( iscsi->password ) );
}
return 0;
@ -1279,10 +1275,43 @@ static void iscsi_socket_close ( struct xfer_interface *socket, int rc ) {
}
}
/**
* Handle redirection event
*
* @v socket Transport layer interface
* @v type Location type
* @v args Remaining arguments depend upon location type
* @ret rc Return status code
*/
static int iscsi_vredirect ( struct xfer_interface *socket, int type,
va_list args ) {
struct iscsi_session *iscsi =
container_of ( socket, struct iscsi_session, socket );
va_list tmp;
struct sockaddr *peer;
/* Intercept redirects to a LOCATION_SOCKET and record the IP
* address for the iBFT. This is a bit of a hack, but avoids
* inventing an ioctl()-style call to retrieve the socket
* address from a data-xfer interface.
*/
if ( type == LOCATION_SOCKET ) {
va_copy ( tmp, args );
( void ) va_arg ( tmp, int ); /* Discard "semantics" */
peer = va_arg ( tmp, struct sockaddr * );
memcpy ( &iscsi->target_sockaddr, peer,
sizeof ( iscsi->target_sockaddr ) );
va_end ( tmp );
}
return xfer_vopen ( socket, type, args );
}
/** iSCSI socket operations */
static struct xfer_interface_operations iscsi_socket_operations = {
.close = iscsi_socket_close,
.vredirect = xfer_vopen,
.vredirect = iscsi_vredirect,
.seek = ignore_xfer_seek,
.window = unlimited_xfer_window,
.alloc_iob = default_xfer_alloc_iob,
@ -1460,6 +1489,32 @@ static int iscsi_parse_root_path ( struct iscsi_session *iscsi,
return 0;
}
/**
* Set iSCSI authentication details
*
* @v iscsi iSCSI session
* @v username Username, if any
* @v password Password, if any
* @ret rc Return status code
*/
static int iscsi_set_auth ( struct iscsi_session *iscsi,
const char *username, const char *password ) {
if ( username ) {
iscsi->username = strdup ( username );
if ( ! iscsi->username )
return -ENOMEM;
}
if ( password ) {
iscsi->password = strdup ( password );
if ( ! iscsi->password )
return -ENOMEM;
}
return 0;
}
/**
* Attach iSCSI interface
*
@ -1482,6 +1537,10 @@ int iscsi_attach ( struct scsi_device *scsi, const char *root_path ) {
/* Parse root path */
if ( ( rc = iscsi_parse_root_path ( iscsi, root_path ) ) != 0 )
goto err;
/* Set fields not specified by root path */
if ( ( rc = iscsi_set_auth ( iscsi, iscsi_username,
iscsi_password ) ) != 0 )
goto err;
/* Sanity checks */
if ( ! iscsi->target_address ) {
@ -1533,7 +1592,7 @@ static int apply_dhcp_iscsi_string ( unsigned int tag,
/* Identify string and prefix */
switch ( tag ) {
case DHCP_ISCSI_INITIATOR_IQN:
string = &iscsi_initiator_iqn;
string = &iscsi_explicit_initiator_iqn;
break;
case DHCP_EB_USERNAME:
string = &iscsi_username;
@ -1584,3 +1643,24 @@ struct dhcp_option_applicator dhcp_iscsi_applicators[] __dhcp_applicator = {
.apply = apply_dhcp_iscsi_string,
},
};
/****************************************************************************
*
* Initiator name
*
*/
/**
* Get iSCSI initiator IQN
*
* @v iscsi iSCSI session
* @ret rc Return status code
*/
const char * iscsi_initiator_iqn ( void ) {
if ( iscsi_explicit_initiator_iqn )
return iscsi_explicit_initiator_iqn;
if ( iscsi_default_initiator_iqn )
return iscsi_default_initiator_iqn;
return "iqn.2000-09.org.etherboot:UNKNOWN";
}

1733
src/net/tls.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
#include <byteswap.h>
#include <gpxe/if_ether.h>
#include <gpxe/netdevice.h>
#include <gpxe/device.h>
#include <gpxe/xfer.h>
#include <gpxe/open.h>
#include <gpxe/job.h>
@ -108,7 +109,7 @@ static uint32_t dhcp_xid ( struct net_device *netdev ) {
}
/** Options common to all DHCP requests */
struct dhcp_option_block dhcp_request_options = {
static struct dhcp_option_block dhcp_request_options = {
.data = dhcp_request_options_data,
.max_len = sizeof ( dhcp_request_options_data ),
.len = sizeof ( dhcp_request_options_data ),
@ -270,8 +271,8 @@ static int copy_dhcp_packet_encap_options ( struct dhcp_packet *dhcppkt,
* @c options may specify a single options block, or be left as NULL
* in order to copy options from all registered options blocks.
*/
int copy_dhcp_packet_options ( struct dhcp_packet *dhcppkt,
struct dhcp_option_block *options ) {
static int copy_dhcp_packet_options ( struct dhcp_packet *dhcppkt,
struct dhcp_option_block *options ) {
return copy_dhcp_packet_encap_options ( dhcppkt, options, 0 );
}
@ -289,9 +290,10 @@ int copy_dhcp_packet_options ( struct dhcp_packet *dhcppkt,
* dhcp_packet structure that can be passed to
* set_dhcp_packet_option() or copy_dhcp_packet_options().
*/
int create_dhcp_packet ( struct net_device *netdev, uint8_t msgtype,
void *data, size_t max_len,
struct dhcp_packet *dhcppkt ) {
static int create_dhcp_packet ( struct net_device *netdev,
unsigned int msgtype,
void *data, size_t max_len,
struct dhcp_packet *dhcppkt ) {
struct dhcphdr *dhcphdr = data;
int rc;
@ -473,6 +475,121 @@ static struct dhcp_option_block * dhcp_parse ( const struct dhcphdr *dhcphdr,
return options;
}
/****************************************************************************
*
* Whole-packet construction
*
*/
/** DHCP network device descriptor */
struct dhcp_netdev_desc {
/** Bus type ID */
uint8_t type;
/** Vendor ID */
uint16_t vendor;
/** Device ID */
uint16_t device;
} __attribute__ (( packed ));
/**
* Create DHCP request
*
* @v netdev Network device
* @v msgtype DHCP message type
* @v options DHCP server response options, or NULL
* @v data Buffer for DHCP packet
* @v max_len Size of DHCP packet buffer
* @v dhcppkt DHCP packet structure to fill in
* @ret rc Return status code
*/
int create_dhcp_request ( struct net_device *netdev, int msgtype,
struct dhcp_option_block *options,
void *data, size_t max_len,
struct dhcp_packet *dhcppkt ) {
struct device_description *desc = &netdev->dev->desc;
struct dhcp_netdev_desc dhcp_desc;
int rc;
/* Create DHCP packet */
if ( ( rc = create_dhcp_packet ( netdev, msgtype, data, max_len,
dhcppkt ) ) != 0 ) {
DBG ( "DHCP could not create DHCP packet: %s\n",
strerror ( rc ) );
return rc;
}
/* Copy in options common to all requests */
if ( ( rc = copy_dhcp_packet_options ( dhcppkt,
&dhcp_request_options )) !=0 ){
DBG ( "DHCP could not set common DHCP options: %s\n",
strerror ( rc ) );
return rc;
}
/* Copy any required options from previous server repsonse */
if ( options ) {
if ( ( rc = copy_dhcp_packet_option ( dhcppkt, options,
DHCP_SERVER_IDENTIFIER,
DHCP_SERVER_IDENTIFIER ) ) != 0 ) {
DBG ( "DHCP could not set server identifier "
"option: %s\n", strerror ( rc ) );
return rc;
}
if ( ( rc = copy_dhcp_packet_option ( dhcppkt, options,
DHCP_EB_YIADDR,
DHCP_REQUESTED_ADDRESS ) ) != 0 ) {
DBG ( "DHCP could not set requested address "
"option: %s\n", strerror ( rc ) );
return rc;
}
}
/* Add options to identify the network device */
dhcp_desc.type = desc->bus_type;
dhcp_desc.vendor = htons ( desc->vendor );
dhcp_desc.device = htons ( desc->device );
if ( ( rc = set_dhcp_packet_option ( dhcppkt, DHCP_EB_BUS_ID,
&dhcp_desc,
sizeof ( dhcp_desc ) ) ) != 0 ) {
DBG ( "DHCP could not set bus ID option: %s\n",
strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Create DHCP response
*
* @v netdev Network device
* @v msgtype DHCP message type
* @v options DHCP options, or NULL
* @v data Buffer for DHCP packet
* @v max_len Size of DHCP packet buffer
* @v dhcppkt DHCP packet structure to fill in
* @ret rc Return status code
*/
int create_dhcp_response ( struct net_device *netdev, int msgtype,
struct dhcp_option_block *options,
void *data, size_t max_len,
struct dhcp_packet *dhcppkt ) {
int rc;
/* Create packet and copy in options */
if ( ( rc = create_dhcp_packet ( netdev, msgtype, data, max_len,
dhcppkt ) ) != 0 ) {
DBG ( " failed to build packet" );
return rc;
}
if ( ( rc = copy_dhcp_packet_options ( dhcppkt, options ) ) != 0 ) {
DBG ( " failed to copy options" );
return rc;
}
return 0;
}
/****************************************************************************
*
* DHCP to UDP interface
@ -556,8 +673,8 @@ static int dhcp_send_request ( struct dhcp_session *dhcp ) {
struct xfer_metadata meta = {
.netdev = dhcp->netdev,
};
struct dhcp_packet dhcppkt;
struct io_buffer *iobuf;
struct dhcp_packet dhcppkt;
int rc;
DBGC ( dhcp, "DHCP %p transmitting %s\n",
@ -577,40 +694,15 @@ static int dhcp_send_request ( struct dhcp_session *dhcp ) {
return -ENOMEM;
/* Create DHCP packet in temporary buffer */
if ( ( rc = create_dhcp_packet ( dhcp->netdev, dhcp->state,
iobuf->data, iob_tailroom ( iobuf ),
&dhcppkt ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not create DHCP packet: %s\n",
if ( ( rc = create_dhcp_request ( dhcp->netdev, dhcp->state,
dhcp->options, iobuf->data,
iob_tailroom ( iobuf ),
&dhcppkt ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
dhcp, strerror ( rc ) );
goto done;
}
/* Copy in options common to all requests */
if ( ( rc = copy_dhcp_packet_options ( &dhcppkt,
&dhcp_request_options ) ) != 0){
DBGC ( dhcp, "DHCP %p could not set common DHCP options: %s\n",
dhcp, strerror ( rc ) );
goto done;
}
/* Copy any required options from previous server repsonse */
if ( dhcp->options ) {
if ( ( rc = copy_dhcp_packet_option ( &dhcppkt, dhcp->options,
DHCP_SERVER_IDENTIFIER,
DHCP_SERVER_IDENTIFIER ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not set server identifier "
"option: %s\n", dhcp, strerror ( rc ) );
goto done;
}
if ( ( rc = copy_dhcp_packet_option ( &dhcppkt, dhcp->options,
DHCP_EB_YIADDR,
DHCP_REQUESTED_ADDRESS ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not set requested address "
"option: %s\n", dhcp, strerror ( rc ) );
goto done;
}
}
/* Transmit the packet */
iob_put ( iobuf, dhcppkt.len );
rc = xfer_deliver_iob_meta ( &dhcp->xfer, iobuf, &meta );

View File

@ -1,71 +0,0 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <console.h>
#include <gpxe/netdevice.h>
#include <gpxe/aoe.h>
#include <int13.h>
static struct aoe_device test_aoedev = {
.aoe = {
.major = 0,
.minor = 0,
},
};
static int aoe_parse ( const char *aoename, struct aoe_session *aoe ) {
char *ptr = ( ( char * ) aoename );
if ( *ptr++ != 'e' )
return -EINVAL;
aoe->major = strtoul ( ptr, &ptr, 10 );
if ( *ptr++ != '.' )
return -EINVAL;
aoe->minor = strtoul ( ptr, &ptr, 10 );
if ( *ptr )
return -EINVAL;
return 0;
}
int test_aoeboot ( struct net_device *netdev, const char *aoename,
unsigned int drivenum ) {
struct int13_drive drive;
int rc;
printf ( "Attempting to boot from AoE device %s via %s\n",
aoename, netdev->name );
if ( ( rc = aoe_parse ( aoename, &test_aoedev.aoe ) ) != 0 ) {
printf ( "Invalid AoE device name \"%s\"\n", aoename );
return rc;
}
printf ( "Initialising AoE device e%d.%d\n",
test_aoedev.aoe.major, test_aoedev.aoe.minor );
test_aoedev.aoe.netdev = netdev;
if ( ( rc = init_aoedev ( &test_aoedev ) ) != 0 ) {
printf ( "Could not reach AoE device e%d.%d\n",
test_aoedev.aoe.major, test_aoedev.aoe.minor );
return rc;
}
memset ( &drive, 0, sizeof ( drive ) );
drive.drive = drivenum;
drive.blockdev = &test_aoedev.ata.blockdev;
register_int13_drive ( &drive );
printf ( "Registered AoE device e%d.%d as BIOS drive %#02x\n",
test_aoedev.aoe.major, test_aoedev.aoe.minor, drive.drive );
printf ( "Booting from BIOS drive %#02x\n", drive.drive );
rc = int13_boot ( drive.drive );
printf ( "Boot failed\n" );
printf ( "Unregistering BIOS drive %#02x\n", drive.drive );
unregister_int13_drive ( &drive );
return rc;
}

104
src/usr/aoeboot.c Normal file
View File

@ -0,0 +1,104 @@
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <byteswap.h>
#include <gpxe/aoe.h>
#include <gpxe/ata.h>
#include <gpxe/netdevice.h>
#include <gpxe/dhcp.h>
#include <gpxe/abft.h>
#include <int13.h>
#include <usr/aoeboot.h>
/**
* AoE boot information block
*
* Must be placed at 40:f0.
*
* This structure needs to be replaced by an ACPI table or similar.
*/
struct aoe_boot_info {
/** Must be 0x01 */
uint8_t one;
/** Client MAC address */
uint8_t client[ETH_ALEN];
/** Server MAC address */
uint8_t server[ETH_ALEN];
/** Shelf number */
uint16_t shelf;
/** Slot number */
uint8_t slot;
} __attribute__ (( packed ));
/**
* Guess boot network device
*
* @ret netdev Boot network device
*/
static struct net_device * guess_boot_netdev ( void ) {
struct net_device *boot_netdev;
/* Just use the first network device */
for_each_netdev ( boot_netdev ) {
return boot_netdev;
}
return NULL;
}
int aoeboot ( const char *root_path ) {
struct ata_device ata;
struct int13_drive drive;
int rc;
memset ( &ata, 0, sizeof ( ata ) );
memset ( &drive, 0, sizeof ( drive ) );
printf ( "AoE booting from %s\n", root_path );
/* FIXME: ugly, ugly hack */
struct net_device *netdev = guess_boot_netdev();
if ( ( rc = aoe_attach ( &ata, netdev, root_path ) ) != 0 ) {
printf ( "Could not attach AoE device: %s\n",
strerror ( rc ) );
goto error_attach;
}
if ( ( rc = init_atadev ( &ata ) ) != 0 ) {
printf ( "Could not initialise AoE device: %s\n",
strerror ( rc ) );
goto error_init;
}
/* FIXME: ugly, ugly hack */
struct aoe_session *aoe =
container_of ( ata.backend, struct aoe_session, refcnt );
struct aoe_boot_info boot_info;
boot_info.one = 0x01;
memcpy ( boot_info.client, netdev->ll_addr,
sizeof ( boot_info.client ) );
memcpy ( boot_info.server, aoe->target,
sizeof ( boot_info.server ) );
boot_info.shelf = htons ( aoe->major );
boot_info.slot = aoe->minor;
copy_to_real ( 0x40, 0xf0, &boot_info, sizeof ( boot_info ) );
abft_fill_data ( aoe );
drive.drive = find_global_dhcp_num_option ( DHCP_EB_BIOS_DRIVE );
drive.blockdev = &ata.blockdev;
register_int13_drive ( &drive );
printf ( "Registered as BIOS drive %#02x\n", drive.drive );
printf ( "Booting from BIOS drive %#02x\n", drive.drive );
rc = int13_boot ( drive.drive );
printf ( "Boot failed\n" );
printf ( "Unregistering BIOS drive %#02x\n", drive.drive );
unregister_int13_drive ( &drive );
error_init:
aoe_detach ( &ata );
error_attach:
return rc;
}

View File

@ -27,6 +27,7 @@
#include <usr/dhcpmgmt.h>
#include <usr/imgmgmt.h>
#include <usr/iscsiboot.h>
#include <usr/aoeboot.h>
#include <usr/autoboot.h>
/** @file
@ -88,13 +89,15 @@ static int boot_filename ( const char *filename ) {
* @ret rc Return status code
*/
static int boot_root_path ( const char *root_path ) {
int rc;
/* Quick hack */
if ( ( rc = iscsiboot ( root_path ) ) != 0 )
return rc;
if ( strncmp ( root_path, "iscsi:", 6 ) == 0 ) {
return iscsiboot ( root_path );
} else if ( strncmp ( root_path, "aoe:", 4 ) == 0 ) {
return aoeboot ( root_path );
}
return 0;
return -ENOTSUP;
}
/**
@ -103,7 +106,7 @@ static int boot_root_path ( const char *root_path ) {
* @v netdev Network device
* @ret rc Return status code
*/
int netboot ( struct net_device *netdev ) {
static int netboot ( struct net_device *netdev ) {
char buf[256];
int rc;

View File

@ -3,9 +3,27 @@
#include <stdio.h>
#include <gpxe/iscsi.h>
#include <gpxe/dhcp.h>
#include <gpxe/netdevice.h>
#include <gpxe/ibft.h>
#include <int13.h>
#include <usr/iscsiboot.h>
/**
* Guess boot network device
*
* @ret netdev Boot network device
*/
static struct net_device * guess_boot_netdev ( void ) {
struct net_device *boot_netdev;
/* Just use the first network device */
for_each_netdev ( boot_netdev ) {
return boot_netdev;
}
return NULL;
}
int iscsiboot ( const char *root_path ) {
struct scsi_device scsi;
struct int13_drive drive;
@ -30,6 +48,12 @@ int iscsiboot ( const char *root_path ) {
drive.drive = find_global_dhcp_num_option ( DHCP_EB_BIOS_DRIVE );
drive.blockdev = &scsi.blockdev;
/* FIXME: ugly, ugly hack */
struct net_device *netdev = guess_boot_netdev();
struct iscsi_session *iscsi =
container_of ( scsi.backend, struct iscsi_session, refcnt );
ibft_fill_data ( netdev, iscsi );
register_int13_drive ( &drive );
printf ( "Registered as BIOS drive %#02x\n", drive.drive );
printf ( "Booting from BIOS drive %#02x\n", drive.drive );