mirror of https://github.com/ipxe/ipxe.git
Merge branch 'master' into strings
commit
58f5565eb0
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 ) );
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
|
@ -24,7 +24,7 @@ Literature dealing with the network protocols:
|
|||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int main ( void ) {
|
||||
__cdecl int main ( void ) {
|
||||
|
||||
initialise();
|
||||
startup();
|
||||
|
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 );
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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[] =
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 * ));
|
||||
|
|
|
@ -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 )
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <gpxe/tables.h>
|
||||
|
||||
struct xfer_interface;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _USR_AOEBOOT_H
|
||||
#define _USR_AOEBOOT_H
|
||||
|
||||
extern int aoeboot ( const char *root_path );
|
||||
|
||||
#endif /* _USR_AOEBOOT_H */
|
|
@ -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 ) {
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
130
src/net/aoe.c
130
src/net/aoe.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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";
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in New Issue