mirror of
https://github.com/xcat2/xNBA.git
synced 2026-09-09 14:36:38 +00:00
Merge http://git.ipxe.org/ipxe
This commit is contained in:
@@ -450,14 +450,20 @@ endif
|
||||
|
||||
# Enable per-item sections and section garbage collection. Note that
|
||||
# some older versions of gcc support -fdata-sections but treat it as
|
||||
# implying -fno-common, which would break our build.
|
||||
# implying -fno-common, which would break our build. Some other older
|
||||
# versions issue a spurious and uninhibitable warning if
|
||||
# -ffunction-sections is used with -g, which would also break our
|
||||
# build since we use -Werror.
|
||||
#
|
||||
ifeq ($(CCTYPE),gcc)
|
||||
DS_TEST = $(ECHO) 'char x;' | \
|
||||
$(CC) -fdata-sections -S -x c - -o - 2>/dev/null | \
|
||||
grep -E '\.comm' > /dev/null
|
||||
DS_FLAGS := $(shell $(DS_TEST) && $(ECHO) '-fdata-sections')
|
||||
CFLAGS += -ffunction-sections $(DS_FLAGS)
|
||||
FS_TEST = $(CC) -ffunction-sections -g -c -x c /dev/null \
|
||||
-o /dev/null 2>/dev/null
|
||||
FS_FLAGS := $(shell $(FS_TEST) && $(ECHO) '-ffunction-sections')
|
||||
CFLAGS += $(FS_FLAGS) $(DS_FLAGS)
|
||||
endif
|
||||
LDFLAGS += --gc-sections
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ static void cmdline_init ( void ) {
|
||||
struct image *image = &cmdline_image;
|
||||
userptr_t cmdline_user;
|
||||
char *cmdline;
|
||||
char *tmp;
|
||||
char *boot_image;
|
||||
char *boot_image_end;
|
||||
size_t len;
|
||||
|
||||
/* Do nothing if no command line was specified */
|
||||
@@ -91,9 +92,18 @@ static void cmdline_init ( void ) {
|
||||
/* Check for unwanted cruft in the command line */
|
||||
while ( isspace ( *cmdline ) )
|
||||
cmdline++;
|
||||
if ( ( tmp = strstr ( cmdline, "BOOT_IMAGE=" ) ) != NULL ) {
|
||||
DBGC ( image, "CMDLINE stripping \"%s\"\n", tmp );
|
||||
*tmp = '\0';
|
||||
if ( ( boot_image = strstr ( cmdline, "BOOT_IMAGE=" ) ) != NULL ) {
|
||||
boot_image_end = strchr ( boot_image, ' ' );
|
||||
if ( boot_image_end ) {
|
||||
*boot_image_end = '\0';
|
||||
DBGC ( image, "CMDLINE stripping \"%s\"\n",
|
||||
boot_image );
|
||||
strcpy ( boot_image, ( boot_image_end + 1 ) );
|
||||
} else {
|
||||
DBGC ( image, "CMDLINE stripping \"%s\"\n",
|
||||
boot_image );
|
||||
*boot_image = '\0';
|
||||
}
|
||||
}
|
||||
DBGC ( image, "CMDLINE using \"%s\"\n", cmdline );
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '6', ':', \
|
||||
'U', 'N', 'D', 'I', ':', '0', '0', '3', '0', '1', '0' )
|
||||
|
||||
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_WORD ( 6 )
|
||||
#define DHCP_ARCH_CLIENT_ARCHITECTURE \
|
||||
DHCP_WORD ( DHCP_CLIENT_ARCHITECTURE_IA32 )
|
||||
|
||||
#define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 3, 10 /* v3.10 */ )
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '0', ':', \
|
||||
'U', 'N', 'D', 'I', ':', '0', '0', '2', '0', '0', '1' )
|
||||
|
||||
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_WORD ( 0 )
|
||||
#define DHCP_ARCH_CLIENT_ARCHITECTURE \
|
||||
DHCP_WORD ( DHCP_CLIENT_ARCHITECTURE_X86 )
|
||||
|
||||
#define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 2, 1 /* v2.1 */ )
|
||||
|
||||
|
||||
@@ -1333,6 +1333,20 @@ static void int13_unhook_vector ( void ) {
|
||||
&int13_vector );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check INT13 emulated drive flow control window
|
||||
*
|
||||
* @v int13 Emulated drive
|
||||
*/
|
||||
static size_t int13_block_window ( struct int13_drive *int13 __unused ) {
|
||||
|
||||
/* We are never ready to receive data via this interface.
|
||||
* This prevents objects that support both block and stream
|
||||
* interfaces from attempting to send us stream data.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle INT 13 emulated drive underlying block device closing
|
||||
*
|
||||
@@ -1357,6 +1371,7 @@ static void int13_block_close ( struct int13_drive *int13, int rc ) {
|
||||
|
||||
/** INT 13 drive interface operations */
|
||||
static struct interface_operation int13_block_op[] = {
|
||||
INTF_OP ( xfer_window, struct int13_drive *, int13_block_window ),
|
||||
INTF_OP ( intf_close, struct int13_drive *, int13_block_close ),
|
||||
};
|
||||
|
||||
|
||||
@@ -652,6 +652,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
|
||||
const void *ll_dest;
|
||||
const void *ll_source;
|
||||
uint16_t net_proto;
|
||||
unsigned int flags;
|
||||
size_t ll_hlen;
|
||||
struct net_protocol *net_protocol;
|
||||
unsigned int prottype;
|
||||
@@ -753,7 +754,8 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
|
||||
/* Strip link-layer header */
|
||||
ll_protocol = pxe_netdev->ll_protocol;
|
||||
if ( ( rc = ll_protocol->pull ( pxe_netdev, iobuf, &ll_dest,
|
||||
&ll_source, &net_proto )) !=0){
|
||||
&ll_source, &net_proto,
|
||||
&flags ) ) != 0 ) {
|
||||
/* Assume unknown net_proto and no ll_source */
|
||||
net_proto = 0;
|
||||
ll_source = NULL;
|
||||
@@ -788,14 +790,12 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
|
||||
undi_isr->Frame.segment = rm_ds;
|
||||
undi_isr->Frame.offset = __from_data16 ( basemem_packet );
|
||||
undi_isr->ProtType = prottype;
|
||||
if ( memcmp ( ll_dest, pxe_netdev->ll_addr,
|
||||
ll_protocol->ll_addr_len ) == 0 ) {
|
||||
undi_isr->PktType = P_DIRECTED;
|
||||
} else if ( memcmp ( ll_dest, pxe_netdev->ll_broadcast,
|
||||
ll_protocol->ll_addr_len ) == 0 ) {
|
||||
if ( flags & LL_BROADCAST ) {
|
||||
undi_isr->PktType = P_BROADCAST;
|
||||
} else {
|
||||
} else if ( flags & LL_MULTICAST ) {
|
||||
undi_isr->PktType = P_MULTICAST;
|
||||
} else {
|
||||
undi_isr->PktType = P_DIRECTED;
|
||||
}
|
||||
DBGC2 ( &pxenv_undi_isr, " %04x:%04x+%x(%x) %s hlen %d",
|
||||
undi_isr->Frame.segment, undi_isr->Frame.offset,
|
||||
|
||||
@@ -160,7 +160,7 @@ relocatable_kernel:
|
||||
pad2:
|
||||
.byte 0, 0, 0
|
||||
cmdline_size:
|
||||
.long 0
|
||||
.long 0x7ff
|
||||
hardware_subarch:
|
||||
.long 0
|
||||
hardware_subarch_data:
|
||||
|
||||
@@ -445,7 +445,7 @@ get_pmm:
|
||||
/* Preserve registers */
|
||||
pushl %eax
|
||||
pushw %di
|
||||
movw $' ', %di
|
||||
movw $( ' ' ), %di
|
||||
get_pmm_find:
|
||||
/* Try to find existing block */
|
||||
pushl %ebx /* PMM handle */
|
||||
@@ -474,7 +474,7 @@ get_pmm_allocate:
|
||||
pushw %dx
|
||||
pushw %ax
|
||||
popl %esi
|
||||
movw $'+', %di /* Indicate allocation attempt */
|
||||
movw $( '+' ), %di /* Indicate allocation attempt */
|
||||
testl %esi, %esi
|
||||
jnz get_pmm_done
|
||||
stc
|
||||
|
||||
@@ -30,10 +30,11 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#define DHCP_ARCH_VENDOR_CLASS_ID \
|
||||
DHCP_STRING ( 'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':', \
|
||||
'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '7', ':', \
|
||||
'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '9', ':', \
|
||||
'U', 'N', 'D', 'I', ':', '0', '0', '3', '0', '1', '0' )
|
||||
|
||||
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_WORD ( 7 )
|
||||
#define DHCP_ARCH_CLIENT_ARCHITECTURE \
|
||||
DHCP_WORD ( DHCP_CLIENT_ARCHITECTURE_X86_64 )
|
||||
|
||||
#define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 3, 10 /* v3.10 */ )
|
||||
|
||||
|
||||
+13
-10
@@ -26,15 +26,7 @@ static void hw_finished ( struct hw *hw, int rc ) {
|
||||
process_del ( &hw->process );
|
||||
}
|
||||
|
||||
static struct interface_operation hw_xfer_operations[] = {
|
||||
INTF_OP ( intf_close, struct hw *, hw_finished ),
|
||||
};
|
||||
|
||||
static struct interface_descriptor hw_xfer_desc =
|
||||
INTF_DESC ( struct hw, xfer, hw_xfer_operations );
|
||||
|
||||
static void hw_step ( struct process *process ) {
|
||||
struct hw *hw = container_of ( process, struct hw, process );
|
||||
static void hw_step ( struct hw *hw ) {
|
||||
int rc;
|
||||
|
||||
if ( xfer_window ( &hw->xfer ) ) {
|
||||
@@ -43,6 +35,17 @@ static void hw_step ( struct process *process ) {
|
||||
}
|
||||
}
|
||||
|
||||
static struct interface_operation hw_xfer_operations[] = {
|
||||
INTF_OP ( xfer_window_changed, struct hw *, hw_step ),
|
||||
INTF_OP ( intf_close, struct hw *, hw_finished ),
|
||||
};
|
||||
|
||||
static struct interface_descriptor hw_xfer_desc =
|
||||
INTF_DESC ( struct hw, xfer, hw_xfer_operations );
|
||||
|
||||
static struct process_descriptor hw_process_desc =
|
||||
PROC_DESC_ONCE ( struct hw, process, hw_step );
|
||||
|
||||
static int hw_open ( struct interface *xfer, struct uri *uri __unused ) {
|
||||
struct hw *hw;
|
||||
|
||||
@@ -52,7 +55,7 @@ static int hw_open ( struct interface *xfer, struct uri *uri __unused ) {
|
||||
return -ENOMEM;
|
||||
ref_init ( &hw->refcnt, NULL );
|
||||
intf_init ( &hw->xfer, &hw_xfer_desc, &hw->refcnt );
|
||||
process_init ( &hw->process, hw_step, &hw->refcnt );
|
||||
process_init ( &hw->process, &hw_process_desc, &hw->refcnt );
|
||||
|
||||
/* Attach parent interface, mortalise self, and return */
|
||||
intf_plug_plug ( &hw->xfer, xfer );
|
||||
|
||||
+33
-15
@@ -33,6 +33,16 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
/** Process run queue */
|
||||
static LIST_HEAD ( run_queue );
|
||||
|
||||
/**
|
||||
* Get pointer to object containing process
|
||||
*
|
||||
* @v process Process
|
||||
* @ret object Containing object
|
||||
*/
|
||||
void * process_object ( struct process *process ) {
|
||||
return ( ( ( void * ) process ) - process->desc->offset );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add process to process list
|
||||
*
|
||||
@@ -43,13 +53,13 @@ static LIST_HEAD ( run_queue );
|
||||
*/
|
||||
void process_add ( struct process *process ) {
|
||||
if ( ! process_running ( process ) ) {
|
||||
DBGC ( process, "PROCESS %p (%p) starting\n",
|
||||
process, process->step );
|
||||
DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
|
||||
" starting\n", PROC_DBG ( process ) );
|
||||
ref_get ( process->refcnt );
|
||||
list_add_tail ( &process->list, &run_queue );
|
||||
} else {
|
||||
DBGC ( process, "PROCESS %p (%p) already started\n",
|
||||
process, process->step );
|
||||
DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
|
||||
" already started\n", PROC_DBG ( process ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,14 +73,14 @@ void process_add ( struct process *process ) {
|
||||
*/
|
||||
void process_del ( struct process *process ) {
|
||||
if ( process_running ( process ) ) {
|
||||
DBGC ( process, "PROCESS %p (%p) stopping\n",
|
||||
process, process->step );
|
||||
DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
|
||||
" stopping\n", PROC_DBG ( process ) );
|
||||
list_del ( &process->list );
|
||||
INIT_LIST_HEAD ( &process->list );
|
||||
ref_put ( process->refcnt );
|
||||
} else {
|
||||
DBGC ( process, "PROCESS %p (%p) already stopped\n",
|
||||
process, process->step );
|
||||
DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
|
||||
" already stopped\n", PROC_DBG ( process ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,17 +92,25 @@ void process_del ( struct process *process ) {
|
||||
*/
|
||||
void step ( void ) {
|
||||
struct process *process;
|
||||
struct process_descriptor *desc;
|
||||
void *object;
|
||||
|
||||
if ( ( process = list_first_entry ( &run_queue, struct process,
|
||||
list ) ) ) {
|
||||
list_del ( &process->list );
|
||||
list_add_tail ( &process->list, &run_queue );
|
||||
ref_get ( process->refcnt ); /* Inhibit destruction mid-step */
|
||||
DBGC2 ( process, "PROCESS %p (%p) executing\n",
|
||||
process, process->step );
|
||||
process->step ( process );
|
||||
DBGC2 ( process, "PROCESS %p (%p) finished executing\n",
|
||||
process, process->step );
|
||||
desc = process->desc;
|
||||
object = process_object ( process );
|
||||
if ( desc->reschedule ) {
|
||||
list_del ( &process->list );
|
||||
list_add_tail ( &process->list, &run_queue );
|
||||
} else {
|
||||
process_del ( process );
|
||||
}
|
||||
DBGC2 ( PROC_COL ( process ), "PROCESS " PROC_FMT
|
||||
" executing\n", PROC_DBG ( process ) );
|
||||
desc->step ( object );
|
||||
DBGC2 ( PROC_COL ( process ), "PROCESS " PROC_FMT
|
||||
" finished executing\n", PROC_DBG ( process ) );
|
||||
ref_put ( process->refcnt ); /* Allow destruction */
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -86,16 +86,16 @@ struct numeric_resolv {
|
||||
int rc;
|
||||
};
|
||||
|
||||
static void numeric_step ( struct process *process ) {
|
||||
struct numeric_resolv *numeric =
|
||||
container_of ( process, struct numeric_resolv, process );
|
||||
static void numeric_step ( struct numeric_resolv *numeric ) {
|
||||
|
||||
process_del ( process );
|
||||
if ( numeric->rc == 0 )
|
||||
resolv_done ( &numeric->resolv, &numeric->sa );
|
||||
intf_shutdown ( &numeric->resolv, numeric->rc );
|
||||
}
|
||||
|
||||
static struct process_descriptor numeric_process_desc =
|
||||
PROC_DESC_ONCE ( struct numeric_resolv, process, numeric_step );
|
||||
|
||||
static int numeric_resolv ( struct interface *resolv,
|
||||
const char *name, struct sockaddr *sa ) {
|
||||
struct numeric_resolv *numeric;
|
||||
@@ -107,7 +107,8 @@ static int numeric_resolv ( struct interface *resolv,
|
||||
return -ENOMEM;
|
||||
ref_init ( &numeric->refcnt, NULL );
|
||||
intf_init ( &numeric->resolv, &null_intf_desc, &numeric->refcnt );
|
||||
process_init ( &numeric->process, numeric_step, &numeric->refcnt );
|
||||
process_init ( &numeric->process, &numeric_process_desc,
|
||||
&numeric->refcnt );
|
||||
memcpy ( &numeric->sa, sa, sizeof ( numeric->sa ) );
|
||||
|
||||
DBGC ( numeric, "NUMERIC %p attempting to resolve \"%s\"\n",
|
||||
|
||||
+27
-10
@@ -60,12 +60,21 @@ static uint8_t type_sizes[] = {
|
||||
*/
|
||||
#define ALT_FORM 0x02
|
||||
|
||||
/**
|
||||
* Use zero padding
|
||||
*
|
||||
* Note that this value is set to 0x10 since that allows the pad
|
||||
* character to be calculated as @c 0x20|(flags&ZPAD)
|
||||
*/
|
||||
#define ZPAD 0x10
|
||||
|
||||
/**
|
||||
* Format a hexadecimal number
|
||||
*
|
||||
* @v end End of buffer to contain number
|
||||
* @v num Number to format
|
||||
* @v width Minimum field width
|
||||
* @v flags Format flags
|
||||
* @ret ptr End of buffer
|
||||
*
|
||||
* Fills a buffer in reverse order with a formatted hexadecimal
|
||||
@@ -79,18 +88,18 @@ static uint8_t type_sizes[] = {
|
||||
static char * format_hex ( char *end, unsigned long long num, int width,
|
||||
int flags ) {
|
||||
char *ptr = end;
|
||||
int case_mod;
|
||||
int case_mod = ( flags & LCASE );
|
||||
int pad = ( ( flags & ZPAD ) | ' ' );
|
||||
|
||||
/* Generate the number */
|
||||
case_mod = flags & LCASE;
|
||||
do {
|
||||
*(--ptr) = "0123456789ABCDEF"[ num & 0xf ] | case_mod;
|
||||
num >>= 4;
|
||||
} while ( num );
|
||||
|
||||
/* Zero-pad to width */
|
||||
/* Pad to width */
|
||||
while ( ( end - ptr ) < width )
|
||||
*(--ptr) = '0';
|
||||
*(--ptr) = pad;
|
||||
|
||||
/* Add "0x" or "0X" if alternate form specified */
|
||||
if ( flags & ALT_FORM ) {
|
||||
@@ -107,6 +116,7 @@ static char * format_hex ( char *end, unsigned long long num, int width,
|
||||
* @v end End of buffer to contain number
|
||||
* @v num Number to format
|
||||
* @v width Minimum field width
|
||||
* @v flags Format flags
|
||||
* @ret ptr End of buffer
|
||||
*
|
||||
* Fills a buffer in reverse order with a formatted decimal number.
|
||||
@@ -115,9 +125,12 @@ static char * format_hex ( char *end, unsigned long long num, int width,
|
||||
* There must be enough space in the buffer to contain the largest
|
||||
* number that this function can format.
|
||||
*/
|
||||
static char * format_decimal ( char *end, signed long num, int width ) {
|
||||
static char * format_decimal ( char *end, signed long num, int width,
|
||||
int flags ) {
|
||||
char *ptr = end;
|
||||
int negative = 0;
|
||||
int zpad = ( flags & ZPAD );
|
||||
int pad = ( zpad | ' ' );
|
||||
|
||||
/* Generate the number */
|
||||
if ( num < 0 ) {
|
||||
@@ -130,12 +143,16 @@ static char * format_decimal ( char *end, signed long num, int width ) {
|
||||
} while ( num );
|
||||
|
||||
/* Add "-" if necessary */
|
||||
if ( negative )
|
||||
if ( negative && ( ! zpad ) )
|
||||
*(--ptr) = '-';
|
||||
|
||||
/* Space-pad to width */
|
||||
/* Pad to width */
|
||||
while ( ( end - ptr ) < width )
|
||||
*(--ptr) = ' ';
|
||||
*(--ptr) = pad;
|
||||
|
||||
/* Add "-" if necessary */
|
||||
if ( negative && zpad )
|
||||
*ptr = '-';
|
||||
|
||||
return ptr;
|
||||
}
|
||||
@@ -186,7 +203,7 @@ size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
|
||||
if ( *fmt == '#' ) {
|
||||
flags |= ALT_FORM;
|
||||
} else if ( *fmt == '0' ) {
|
||||
/* We always 0-pad hex and space-pad decimal */
|
||||
flags |= ZPAD;
|
||||
} else {
|
||||
/* End of flag characters */
|
||||
break;
|
||||
@@ -250,7 +267,7 @@ size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
|
||||
} else {
|
||||
decimal = va_arg ( args, signed int );
|
||||
}
|
||||
ptr = format_decimal ( ptr, decimal, width );
|
||||
ptr = format_decimal ( ptr, decimal, width, flags );
|
||||
} else {
|
||||
*(--ptr) = *fmt;
|
||||
}
|
||||
|
||||
+16
-1
@@ -54,6 +54,7 @@ static struct xfer_metadata dummy_metadata;
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int xfer_vredirect ( struct interface *intf, int type, va_list args ) {
|
||||
struct interface tmp = INTF_INIT ( null_intf_desc );
|
||||
struct interface *dest;
|
||||
xfer_vredirect_TYPE ( void * ) *op =
|
||||
intf_get_dest_op_no_passthru ( intf, xfer_vredirect, &dest );
|
||||
@@ -66,8 +67,22 @@ int xfer_vredirect ( struct interface *intf, int type, va_list args ) {
|
||||
if ( op ) {
|
||||
rc = op ( object, type, args );
|
||||
} else {
|
||||
/* Default is to reopen the interface as instructed */
|
||||
/* Default is to reopen the interface as instructed,
|
||||
* then send xfer_window_changed() messages to both
|
||||
* new child and parent interfaces. Since our
|
||||
* original child interface is likely to be closed and
|
||||
* unplugged as a result of the call to
|
||||
* xfer_vreopen(), we create a temporary interface in
|
||||
* order to be able to send xfer_window_changed() to
|
||||
* the parent.
|
||||
*/
|
||||
intf_plug ( &tmp, dest );
|
||||
rc = xfer_vreopen ( dest, type, args );
|
||||
if ( rc == 0 ) {
|
||||
xfer_window_changed ( dest );
|
||||
xfer_window_changed ( &tmp );
|
||||
}
|
||||
intf_unplug ( &tmp );
|
||||
}
|
||||
|
||||
if ( rc != 0 ) {
|
||||
|
||||
+20
-10
@@ -218,8 +218,10 @@ struct scsi_device {
|
||||
|
||||
/** SCSI device flags */
|
||||
enum scsi_device_flags {
|
||||
/** Unit is ready */
|
||||
SCSIDEV_UNIT_READY = 0x0001,
|
||||
/** TEST UNIT READY has been issued */
|
||||
SCSIDEV_UNIT_TESTED = 0x0001,
|
||||
/** TEST UNIT READY has completed successfully */
|
||||
SCSIDEV_UNIT_READY = 0x0002,
|
||||
};
|
||||
|
||||
/** A SCSI command */
|
||||
@@ -892,23 +894,25 @@ static struct interface_descriptor scsidev_ready_desc =
|
||||
/**
|
||||
* SCSI TEST UNIT READY process
|
||||
*
|
||||
* @v process Process
|
||||
* @v scsidev SCSI device
|
||||
*/
|
||||
static void scsidev_step ( struct process *process ) {
|
||||
struct scsi_device *scsidev =
|
||||
container_of ( process, struct scsi_device, process );
|
||||
static void scsidev_step ( struct scsi_device *scsidev ) {
|
||||
int rc;
|
||||
|
||||
/* Do nothing if we have already issued TEST UNIT READY */
|
||||
if ( scsidev->flags & SCSIDEV_UNIT_TESTED )
|
||||
return;
|
||||
|
||||
/* Wait until underlying SCSI device is ready */
|
||||
if ( xfer_window ( &scsidev->scsi ) == 0 )
|
||||
return;
|
||||
|
||||
/* Stop process */
|
||||
process_del ( &scsidev->process );
|
||||
|
||||
DBGC ( scsidev, "SCSI %p waiting for unit to become ready\n",
|
||||
scsidev );
|
||||
|
||||
/* Mark TEST UNIT READY as sent */
|
||||
scsidev->flags |= SCSIDEV_UNIT_TESTED;
|
||||
|
||||
/* Issue TEST UNIT READY command */
|
||||
if ( ( rc = scsidev_test_unit_ready ( scsidev, &scsidev->ready )) !=0){
|
||||
scsidev_close ( scsidev, rc );
|
||||
@@ -918,6 +922,7 @@ static void scsidev_step ( struct process *process ) {
|
||||
|
||||
/** SCSI device SCSI interface operations */
|
||||
static struct interface_operation scsidev_scsi_op[] = {
|
||||
INTF_OP ( xfer_window_changed, struct scsi_device *, scsidev_step ),
|
||||
INTF_OP ( intf_close, struct scsi_device *, scsidev_close ),
|
||||
};
|
||||
|
||||
@@ -926,6 +931,10 @@ static struct interface_descriptor scsidev_scsi_desc =
|
||||
INTF_DESC_PASSTHRU ( struct scsi_device, scsi,
|
||||
scsidev_scsi_op, block );
|
||||
|
||||
/** SCSI device process descriptor */
|
||||
static struct process_descriptor scsidev_process_desc =
|
||||
PROC_DESC_ONCE ( struct scsi_device, process, scsidev_step );
|
||||
|
||||
/**
|
||||
* Open SCSI device
|
||||
*
|
||||
@@ -946,7 +955,8 @@ int scsi_open ( struct interface *block, struct interface *scsi,
|
||||
intf_init ( &scsidev->block, &scsidev_block_desc, &scsidev->refcnt );
|
||||
intf_init ( &scsidev->scsi, &scsidev_scsi_desc, &scsidev->refcnt );
|
||||
intf_init ( &scsidev->ready, &scsidev_ready_desc, &scsidev->refcnt );
|
||||
process_init ( &scsidev->process, scsidev_step, &scsidev->refcnt );
|
||||
process_init ( &scsidev->process, &scsidev_process_desc,
|
||||
&scsidev->refcnt );
|
||||
INIT_LIST_HEAD ( &scsidev->cmds );
|
||||
memcpy ( &scsidev->lun, lun, sizeof ( scsidev->lun ) );
|
||||
DBGC ( scsidev, "SCSI %p created for LUN " SCSI_LUN_FORMAT "\n",
|
||||
|
||||
@@ -69,11 +69,6 @@ typedef enum {
|
||||
#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
|
||||
#define ETH_ADDR_LEN ETH_ALEN
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
#define E1000_BIG_ENDIAN __BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
|
||||
#define DEBUGOUT(S) if (0) { printf(S); }
|
||||
#define DEBUGOUT1(S, A...) if (0) { printf(S, A); }
|
||||
|
||||
|
||||
@@ -224,11 +224,13 @@ static int ipoib_push ( struct net_device *netdev __unused,
|
||||
* @ret ll_dest Link-layer destination address
|
||||
* @ret ll_source Source link-layer address
|
||||
* @ret net_proto Network-layer protocol, in network-byte order
|
||||
* @ret flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ipoib_pull ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf, const void **ll_dest,
|
||||
const void **ll_source, uint16_t *net_proto ) {
|
||||
const void **ll_source, uint16_t *net_proto,
|
||||
unsigned int *flags ) {
|
||||
struct ipoib_device *ipoib = netdev->priv;
|
||||
struct ipoib_hdr *ipoib_hdr = iobuf->data;
|
||||
struct ipoib_peer *dest;
|
||||
@@ -255,6 +257,7 @@ static int ipoib_pull ( struct net_device *netdev,
|
||||
*ll_dest = ( dest ? &dest->mac : &ipoib->broadcast );
|
||||
*ll_source = ( source ? &source->mac : &ipoib->broadcast );
|
||||
*net_proto = ipoib_hdr->proto;
|
||||
*flags = ( ( *ll_dest == &ipoib->broadcast ) ? LL_BROADCAST : 0 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -240,6 +240,39 @@ struct dhcp_client_id {
|
||||
/** Client system architecture */
|
||||
#define DHCP_CLIENT_ARCHITECTURE 93
|
||||
|
||||
/** DHCP client architecture */
|
||||
struct dhcp_client_architecture {
|
||||
uint16_t arch;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** DHCP client architecture values
|
||||
*
|
||||
* These are defined by the PXE specification and redefined by
|
||||
* RFC4578.
|
||||
*/
|
||||
enum dhcp_client_architecture_values {
|
||||
/** Intel x86 PC */
|
||||
DHCP_CLIENT_ARCHITECTURE_X86 = 0x0000,
|
||||
/** NEC/PC98 */
|
||||
DHCP_CLIENT_ARCHITECTURE_PC98 = 0x0001,
|
||||
/** EFI Itanium */
|
||||
DHCP_CLIENT_ARCHITECTURE_IA64 = 0x0002,
|
||||
/** DEC Alpha */
|
||||
DHCP_CLIENT_ARCHITECTURE_ALPHA = 0x0003,
|
||||
/** Arc x86 */
|
||||
DHCP_CLIENT_ARCHITECTURE_ARCX86 = 0x0004,
|
||||
/** Intel Lean Client */
|
||||
DHCP_CLIENT_ARCHITECTURE_LC = 0x0005,
|
||||
/** EFI IA32 */
|
||||
DHCP_CLIENT_ARCHITECTURE_IA32 = 0x0006,
|
||||
/** EFI BC */
|
||||
DHCP_CLIENT_ARCHITECTURE_EFI = 0x0007,
|
||||
/** EFI Xscale */
|
||||
DHCP_CLIENT_ARCHITECTURE_XSCALE = 0x0008,
|
||||
/** EFI x86-64 */
|
||||
DHCP_CLIENT_ARCHITECTURE_X86_64 = 0x0009,
|
||||
};
|
||||
|
||||
/** Client network device interface */
|
||||
#define DHCP_CLIENT_NDI 94
|
||||
|
||||
|
||||
+72
-5
@@ -357,7 +357,15 @@ struct fc_peer {
|
||||
|
||||
/** List of upper-layer protocols */
|
||||
struct list_head ulps;
|
||||
/** Active usage count */
|
||||
/** Active usage count
|
||||
*
|
||||
* A peer (and attached ULPs) may be created in response to
|
||||
* unsolicited login requests received via the fabric. We
|
||||
* track our own active usage count independently of the
|
||||
* existence of the peer, so that if the peer becomes logged
|
||||
* out (e.g. due to a link failure) then we know whether or
|
||||
* not we should attempt to relogin.
|
||||
*/
|
||||
unsigned int usage;
|
||||
};
|
||||
|
||||
@@ -424,8 +432,15 @@ struct fc_ulp {
|
||||
/** Service parameter length */
|
||||
size_t param_len;
|
||||
|
||||
/** Active usage count */
|
||||
unsigned int usage;
|
||||
/** Active users of this upper-layer protocol
|
||||
*
|
||||
* As with peers, an upper-layer protocol may be created in
|
||||
* response to an unsolicited login request received via the
|
||||
* fabric. This list records the number of active users of
|
||||
* the ULP; the number of entries in the list is equivalent to
|
||||
* the peer usage count.
|
||||
*/
|
||||
struct list_head users;
|
||||
};
|
||||
|
||||
/** Fibre Channel upper-layer protocol flags */
|
||||
@@ -434,6 +449,21 @@ enum fc_ulp_flags {
|
||||
FC_ULP_ORIGINATED_LOGIN_OK = 0x0001,
|
||||
};
|
||||
|
||||
/** A Fibre Channel upper-layer protocol user */
|
||||
struct fc_ulp_user {
|
||||
/** Fibre Channel upper layer protocol */
|
||||
struct fc_ulp *ulp;
|
||||
/** List of users */
|
||||
struct list_head list;
|
||||
/** Containing object reference count, or NULL */
|
||||
struct refcnt *refcnt;
|
||||
/** Examine link state
|
||||
*
|
||||
* @v user Fibre Channel upper-layer-protocol user
|
||||
*/
|
||||
void ( * examine ) ( struct fc_ulp_user *user );
|
||||
};
|
||||
|
||||
/**
|
||||
* Get reference to Fibre Channel upper-layer protocol
|
||||
*
|
||||
@@ -456,14 +486,51 @@ fc_ulp_put ( struct fc_ulp *ulp ) {
|
||||
ref_put ( &ulp->refcnt );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reference to Fibre Channel upper-layer protocol user
|
||||
*
|
||||
* @v user Fibre Channel upper-layer protocol user
|
||||
* @ret user Fibre Channel upper-layer protocol user
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) struct fc_ulp_user *
|
||||
fc_ulp_user_get ( struct fc_ulp_user *user ) {
|
||||
ref_get ( user->refcnt );
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop reference to Fibre Channel upper-layer protocol user
|
||||
*
|
||||
* @v user Fibre Channel upper-layer protocol user
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
fc_ulp_user_put ( struct fc_ulp_user *user ) {
|
||||
ref_put ( user->refcnt );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise Fibre Channel upper-layer protocol user
|
||||
*
|
||||
* @v user Fibre Channel upper-layer protocol user
|
||||
* @v examine Examine link state method
|
||||
* @v refcnt Containing object reference count, or NULL
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
fc_ulp_user_init ( struct fc_ulp_user *user,
|
||||
void ( * examine ) ( struct fc_ulp_user *user ),
|
||||
struct refcnt *refcnt ) {
|
||||
user->examine = examine;
|
||||
user->refcnt = refcnt;
|
||||
}
|
||||
|
||||
extern struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_wwn,
|
||||
unsigned int type );
|
||||
extern struct fc_ulp *
|
||||
fc_ulp_get_port_id_type ( struct fc_port *port,
|
||||
const struct fc_port_id *peer_port_id,
|
||||
unsigned int type );
|
||||
extern void fc_ulp_increment ( struct fc_ulp *ulp );
|
||||
extern void fc_ulp_decrement ( struct fc_ulp *ulp );
|
||||
extern void fc_ulp_attach ( struct fc_ulp *ulp, struct fc_ulp_user *user );
|
||||
extern void fc_ulp_detach ( struct fc_ulp_user *user );
|
||||
extern int fc_ulp_login ( struct fc_ulp *ulp, const void *param,
|
||||
size_t param_len, int originated );
|
||||
extern void fc_ulp_logout ( struct fc_ulp *ulp, int rc );
|
||||
|
||||
+8
-15
@@ -31,9 +31,6 @@ struct io_buffer;
|
||||
#define IP_TOS 0
|
||||
#define IP_TTL 64
|
||||
|
||||
#define IP_FRAG_IOB_SIZE 1500
|
||||
#define IP_FRAG_TIMEOUT 50
|
||||
|
||||
/** An IPv4 packet header */
|
||||
struct iphdr {
|
||||
uint8_t verhdrlen;
|
||||
@@ -73,20 +70,16 @@ struct ipv4_miniroute {
|
||||
struct in_addr gateway;
|
||||
};
|
||||
|
||||
/* Fragment reassembly buffer */
|
||||
struct frag_buffer {
|
||||
/* Identification number */
|
||||
uint16_t ident;
|
||||
/* Source network address */
|
||||
struct in_addr src;
|
||||
/* Destination network address */
|
||||
struct in_addr dest;
|
||||
/* Reassembled I/O buffer */
|
||||
struct io_buffer *frag_iob;
|
||||
/* Reassembly timer */
|
||||
struct retry_timer frag_timer;
|
||||
/* IPv4 fragment reassembly buffer */
|
||||
struct ipv4_fragment {
|
||||
/* List of fragment reassembly buffers */
|
||||
struct list_head list;
|
||||
/** Reassembled packet */
|
||||
struct io_buffer *iobuf;
|
||||
/** Current offset */
|
||||
size_t offset;
|
||||
/** Reassembly timer */
|
||||
struct retry_timer timer;
|
||||
};
|
||||
|
||||
extern struct list_head ipv4_miniroutes;
|
||||
|
||||
@@ -66,20 +66,23 @@ struct net_protocol {
|
||||
/**
|
||||
* Process received packet
|
||||
*
|
||||
* @v iobuf I/O buffer
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer source address
|
||||
* @v iobuf I/O buffer
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer source address
|
||||
* @v flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This method takes ownership of the I/O buffer.
|
||||
*/
|
||||
int ( * rx ) ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
const void *ll_dest, const void *ll_source );
|
||||
const void *ll_dest, const void *ll_source,
|
||||
unsigned int flags );
|
||||
/**
|
||||
* Transcribe network-layer address
|
||||
*
|
||||
* @v net_addr Network-layer address
|
||||
* @ret string Human-readable transcription of address
|
||||
* @v net_addr Network-layer address
|
||||
* @ret string Human-readable transcription of address
|
||||
*
|
||||
* This method should convert the network-layer address into a
|
||||
* human-readable format (e.g. dotted quad notation for IPv4).
|
||||
@@ -97,6 +100,12 @@ struct net_protocol {
|
||||
uint8_t net_addr_len;
|
||||
};
|
||||
|
||||
/** Packet is a multicast (including broadcast) packet */
|
||||
#define LL_MULTICAST 0x0001
|
||||
|
||||
/** Packet is a broadcast packet */
|
||||
#define LL_BROADCAST 0x0002
|
||||
|
||||
/**
|
||||
* A link-layer protocol
|
||||
*
|
||||
@@ -125,11 +134,12 @@ struct ll_protocol {
|
||||
* @ret ll_dest Link-layer destination address
|
||||
* @ret ll_source Source link-layer address
|
||||
* @ret net_proto Network-layer protocol, in network-byte order
|
||||
* @ret flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int ( * pull ) ( struct net_device *netdev, struct io_buffer *iobuf,
|
||||
const void **ll_dest, const void **ll_source,
|
||||
uint16_t *net_proto );
|
||||
uint16_t *net_proto, unsigned int *flags );
|
||||
/**
|
||||
* Initialise link-layer address
|
||||
*
|
||||
@@ -586,6 +596,8 @@ netdev_rx_frozen ( struct net_device *netdev ) {
|
||||
extern void netdev_link_err ( struct net_device *netdev, int rc );
|
||||
extern void netdev_link_down ( struct net_device *netdev );
|
||||
extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
|
||||
extern void netdev_tx_err ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf, int rc );
|
||||
extern void netdev_tx_complete_err ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf, int rc );
|
||||
extern void netdev_tx_complete_next_err ( struct net_device *netdev, int rc );
|
||||
@@ -609,7 +621,7 @@ extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
const void *ll_source );
|
||||
extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
uint16_t net_proto, const void *ll_dest,
|
||||
const void *ll_source );
|
||||
const void *ll_source, unsigned int flags );
|
||||
extern void net_poll ( void );
|
||||
|
||||
/**
|
||||
|
||||
+127
-13
@@ -17,6 +17,20 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
struct process {
|
||||
/** List of processes */
|
||||
struct list_head list;
|
||||
/** Process descriptor */
|
||||
struct process_descriptor *desc;
|
||||
/** Reference counter
|
||||
*
|
||||
* If this process is not part of a reference-counted object,
|
||||
* this field may be NULL.
|
||||
*/
|
||||
struct refcnt *refcnt;
|
||||
};
|
||||
|
||||
/** A process descriptor */
|
||||
struct process_descriptor {
|
||||
/** Offset of process within containing object */
|
||||
size_t offset;
|
||||
/**
|
||||
* Single-step the process
|
||||
*
|
||||
@@ -24,15 +38,81 @@ struct process {
|
||||
* Returning from this method is isomorphic to yielding the
|
||||
* CPU to another process.
|
||||
*/
|
||||
void ( * step ) ( struct process *process );
|
||||
/** Reference counter
|
||||
*
|
||||
* If this interface is not part of a reference-counted
|
||||
* object, this field may be NULL.
|
||||
*/
|
||||
struct refcnt *refcnt;
|
||||
void ( * step ) ( void *object );
|
||||
/** Automatically reschedule the process */
|
||||
int reschedule;
|
||||
};
|
||||
|
||||
/**
|
||||
* Define a process step() method
|
||||
*
|
||||
* @v object_type Implementing method's expected object type
|
||||
* @v step Implementing method
|
||||
* @ret step Process step method
|
||||
*/
|
||||
#define PROC_STEP( object_type, step ) \
|
||||
( ( ( ( typeof ( step ) * ) NULL ) == \
|
||||
( ( void ( * ) ( object_type *object ) ) NULL ) ) ? \
|
||||
( void ( * ) ( void *object ) ) step : \
|
||||
( void ( * ) ( void *object ) ) step )
|
||||
|
||||
/**
|
||||
* Calculate offset of process within containing object
|
||||
*
|
||||
* @v object_type Containing object data type
|
||||
* @v name Process name (i.e. field within object data type)
|
||||
* @ret offset Offset of process within containing object
|
||||
*/
|
||||
#define process_offset( object_type, name ) \
|
||||
( ( ( ( typeof ( ( ( object_type * ) NULL )->name ) * ) NULL ) \
|
||||
== ( ( struct process * ) NULL ) ) \
|
||||
? offsetof ( object_type, name ) \
|
||||
: offsetof ( object_type, name ) )
|
||||
|
||||
/**
|
||||
* Define a process descriptor
|
||||
*
|
||||
* @v object_type Containing object data type
|
||||
* @v process Process name (i.e. field within object data type)
|
||||
* @v step Process' step() method
|
||||
* @ret desc Object interface descriptor
|
||||
*/
|
||||
#define PROC_DESC( object_type, process, _step ) { \
|
||||
.offset = process_offset ( object_type, process ), \
|
||||
.step = PROC_STEP ( object_type, _step ), \
|
||||
.reschedule = 1, \
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a process descriptor for a process that runs only once
|
||||
*
|
||||
* @v object_type Containing object data type
|
||||
* @v process Process name (i.e. field within object data type)
|
||||
* @v step Process' step() method
|
||||
* @ret desc Object interface descriptor
|
||||
*/
|
||||
#define PROC_DESC_ONCE( object_type, process, _step ) { \
|
||||
.offset = process_offset ( object_type, process ), \
|
||||
.step = PROC_STEP ( object_type, _step ), \
|
||||
.reschedule = 0, \
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a process descriptor for a pure process
|
||||
*
|
||||
* A pure process is a process that does not have a containing object.
|
||||
*
|
||||
* @v step Process' step() method
|
||||
* @ret desc Object interface descriptor
|
||||
*/
|
||||
#define PROC_DESC_PURE( _step ) { \
|
||||
.offset = 0, \
|
||||
.step = PROC_STEP ( struct process, _step ), \
|
||||
.reschedule = 1, \
|
||||
}
|
||||
|
||||
extern void * __attribute__ (( pure ))
|
||||
process_object ( struct process *process );
|
||||
extern void process_add ( struct process *process );
|
||||
extern void process_del ( struct process *process );
|
||||
extern void step ( void );
|
||||
@@ -41,14 +121,15 @@ extern void step ( void );
|
||||
* Initialise process without adding to process list
|
||||
*
|
||||
* @v process Process
|
||||
* @v step Process' step() method
|
||||
* @v desc Process descriptor
|
||||
* @v refcnt Containing object reference count, or NULL
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
process_init_stopped ( struct process *process,
|
||||
void ( * step ) ( struct process *process ),
|
||||
struct process_descriptor *desc,
|
||||
struct refcnt *refcnt ) {
|
||||
INIT_LIST_HEAD ( &process->list );
|
||||
process->step = step;
|
||||
process->desc = desc;
|
||||
process->refcnt = refcnt;
|
||||
}
|
||||
|
||||
@@ -56,13 +137,14 @@ process_init_stopped ( struct process *process,
|
||||
* Initialise process and add to process list
|
||||
*
|
||||
* @v process Process
|
||||
* @v step Process' step() method
|
||||
* @v desc Process descriptor
|
||||
* @v refcnt Containing object reference count, or NULL
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
process_init ( struct process *process,
|
||||
void ( * step ) ( struct process *process ),
|
||||
struct process_descriptor *desc,
|
||||
struct refcnt *refcnt ) {
|
||||
process_init_stopped ( process, step, refcnt );
|
||||
process_init_stopped ( process, desc, refcnt );
|
||||
process_add ( process );
|
||||
}
|
||||
|
||||
@@ -88,4 +170,36 @@ process_running ( struct process *process ) {
|
||||
*/
|
||||
#define __permanent_process __table_entry ( PERMANENT_PROCESSES, 01 )
|
||||
|
||||
/** Define a permanent process
|
||||
*
|
||||
*/
|
||||
#define PERMANENT_PROCESS( name, step ) \
|
||||
struct process_descriptor name ## _desc = PROC_DESC_PURE ( step ); \
|
||||
struct process name __permanent_process = { \
|
||||
.list = LIST_HEAD_INIT ( name.list ), \
|
||||
.desc = & name ## _desc, \
|
||||
.refcnt = NULL, \
|
||||
};
|
||||
|
||||
/**
|
||||
* Find debugging colourisation for a process
|
||||
*
|
||||
* @v process Process
|
||||
* @ret col Debugging colourisation
|
||||
*
|
||||
* Use as the first argument to DBGC() or equivalent macro.
|
||||
*/
|
||||
#define PROC_COL( process ) process_object ( process )
|
||||
|
||||
/** printf() format string for PROC_DBG() */
|
||||
#define PROC_FMT "%p+%zx"
|
||||
|
||||
/**
|
||||
* printf() arguments for representing a process
|
||||
*
|
||||
* @v process Process
|
||||
* @ret args printf() argument list corresponding to PROC_FMT
|
||||
*/
|
||||
#define PROC_DBG( process ) process_object ( process ), (process)->desc->offset
|
||||
|
||||
#endif /* _IPXE_PROCESS_H */
|
||||
|
||||
@@ -658,6 +658,7 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
|
||||
const void *iob_ll_dest;
|
||||
const void *iob_ll_src;
|
||||
uint16_t iob_net_proto;
|
||||
unsigned int iob_flags;
|
||||
int rc;
|
||||
EFI_STATUS efirc;
|
||||
|
||||
@@ -682,7 +683,8 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
|
||||
|
||||
/* Attempt to decode link-layer header */
|
||||
if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest,
|
||||
&iob_ll_src, &iob_net_proto ) ) != 0 ){
|
||||
&iob_ll_src, &iob_net_proto,
|
||||
&iob_flags ) ) != 0 ) {
|
||||
DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
|
||||
snpdev, strerror ( rc ) );
|
||||
efirc = RC_TO_EFIRC ( rc );
|
||||
|
||||
+19
-10
@@ -135,7 +135,8 @@ static int net80211_ll_push ( struct net_device *netdev,
|
||||
const void *ll_source, uint16_t net_proto );
|
||||
static int net80211_ll_pull ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf, const void **ll_dest,
|
||||
const void **ll_source, uint16_t * net_proto );
|
||||
const void **ll_source, uint16_t * net_proto,
|
||||
unsigned int *flags );
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@@ -159,7 +160,7 @@ net80211_marshal_request_info ( struct net80211_device *dev,
|
||||
* @defgroup net80211_assoc_ll 802.11 association handling functions
|
||||
* @{
|
||||
*/
|
||||
static void net80211_step_associate ( struct process *proc );
|
||||
static void net80211_step_associate ( struct net80211_device *dev );
|
||||
static void net80211_handle_auth ( struct net80211_device *dev,
|
||||
struct io_buffer *iob );
|
||||
static void net80211_handle_assoc_reply ( struct net80211_device *dev,
|
||||
@@ -529,6 +530,7 @@ static int net80211_ll_push ( struct net_device *netdev,
|
||||
* @ret ll_dest Link-layer destination address
|
||||
* @ret ll_source Link-layer source
|
||||
* @ret net_proto Network-layer protocol, in network byte order
|
||||
* @ret flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This expects and removes both the 802.11 frame header and the 802.2
|
||||
@@ -537,7 +539,7 @@ static int net80211_ll_push ( struct net_device *netdev,
|
||||
static int net80211_ll_pull ( struct net_device *netdev __unused,
|
||||
struct io_buffer *iobuf,
|
||||
const void **ll_dest, const void **ll_source,
|
||||
uint16_t * net_proto )
|
||||
uint16_t * net_proto, unsigned int *flags )
|
||||
{
|
||||
struct ieee80211_frame *hdr = iobuf->data;
|
||||
struct ieee80211_llc_snap_header *lhdr =
|
||||
@@ -586,6 +588,10 @@ static int net80211_ll_pull ( struct net_device *netdev __unused,
|
||||
*ll_dest = hdr->addr1;
|
||||
*ll_source = hdr->addr3;
|
||||
*net_proto = lhdr->ethertype;
|
||||
*flags = ( ( is_multicast_ether_addr ( hdr->addr1 ) ?
|
||||
LL_MULTICAST : 0 ) |
|
||||
( is_broadcast_ether_addr ( hdr->addr1 ) ?
|
||||
LL_BROADCAST : 0 ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -729,6 +735,11 @@ int net80211_tx_mgmt ( struct net80211_device *dev, u16 fc, u8 dest[6],
|
||||
|
||||
/* ---------- Driver API ---------- */
|
||||
|
||||
/** 802.11 association process descriptor */
|
||||
static struct process_descriptor net80211_process_desc =
|
||||
PROC_DESC ( struct net80211_device, proc_assoc,
|
||||
net80211_step_associate );
|
||||
|
||||
/**
|
||||
* Allocate 802.11 device
|
||||
*
|
||||
@@ -760,7 +771,7 @@ struct net80211_device * net80211_alloc ( size_t priv_size )
|
||||
dev->priv = ( u8 * ) dev + sizeof ( *dev );
|
||||
dev->op = &net80211_null_ops;
|
||||
|
||||
process_init_stopped ( &dev->proc_assoc, net80211_step_associate,
|
||||
process_init_stopped ( &dev->proc_assoc, &net80211_process_desc,
|
||||
&netdev->refcnt );
|
||||
INIT_LIST_HEAD ( &dev->mgmt_queue );
|
||||
INIT_LIST_HEAD ( &dev->mgmt_info_queue );
|
||||
@@ -1630,12 +1641,10 @@ void net80211_free_wlanlist ( struct list_head *list )
|
||||
/**
|
||||
* Step 802.11 association process
|
||||
*
|
||||
* @v proc Association process
|
||||
* @v dev 802.11 device
|
||||
*/
|
||||
static void net80211_step_associate ( struct process *proc )
|
||||
static void net80211_step_associate ( struct net80211_device *dev )
|
||||
{
|
||||
struct net80211_device *dev =
|
||||
container_of ( proc, struct net80211_device, proc_assoc );
|
||||
int rc = 0;
|
||||
int status = dev->state & NET80211_STATUS_MASK;
|
||||
|
||||
@@ -1836,7 +1845,7 @@ static void net80211_step_associate ( struct process *proc )
|
||||
|
||||
dev->rctl = rc80211_init ( dev );
|
||||
|
||||
process_del ( proc );
|
||||
process_del ( &dev->proc_assoc );
|
||||
|
||||
DBGC ( dev, "802.11 %p associated with %s (%s)\n", dev,
|
||||
dev->essid, eth_ntoa ( dev->bssid ) );
|
||||
@@ -1861,7 +1870,7 @@ static void net80211_step_associate ( struct process *proc )
|
||||
net80211_free_wlan ( dev->associating );
|
||||
dev->associating = NULL;
|
||||
|
||||
process_del ( proc );
|
||||
process_del ( &dev->proc_assoc );
|
||||
|
||||
DBGC ( dev, "802.11 %p association failed (state=%04x): "
|
||||
"%s\n", dev, dev->state, strerror ( dev->assoc_rc ) );
|
||||
|
||||
+3
-2
@@ -906,13 +906,14 @@ static int aoedev_open ( struct interface *parent, struct net_device *netdev,
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer source address
|
||||
* @v flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*
|
||||
*/
|
||||
static int aoe_rx ( struct io_buffer *iobuf,
|
||||
struct net_device *netdev __unused,
|
||||
const void *ll_dest __unused,
|
||||
const void *ll_source ) {
|
||||
const void *ll_source,
|
||||
unsigned int flags __unused ) {
|
||||
struct aoehdr *aoehdr = iobuf->data;
|
||||
struct aoe_command *aoecmd;
|
||||
int rc;
|
||||
|
||||
+3
-1
@@ -186,6 +186,7 @@ static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) {
|
||||
* @v iobuf I/O buffer
|
||||
* @v netdev Network device
|
||||
* @v ll_source Link-layer source address
|
||||
* @v flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This handles ARP requests and responses as detailed in RFC826. The
|
||||
@@ -196,7 +197,8 @@ static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) {
|
||||
*/
|
||||
static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
const void *ll_dest __unused,
|
||||
const void *ll_source __unused ) {
|
||||
const void *ll_source __unused,
|
||||
unsigned int flags __unused ) {
|
||||
struct arphdr *arphdr = iobuf->data;
|
||||
struct arp_net_protocol *arp_net_protocol;
|
||||
struct net_protocol *net_protocol;
|
||||
|
||||
+3
-1
@@ -38,11 +38,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer source address
|
||||
* @v flags Packet flags
|
||||
*
|
||||
* This function takes ownership of the I/O buffer passed to it.
|
||||
*/
|
||||
static int eapol_rx ( struct io_buffer *iob, struct net_device *netdev,
|
||||
const void *ll_dest, const void *ll_source ) {
|
||||
const void *ll_dest, const void *ll_source,
|
||||
unsigned int flags __unused ) {
|
||||
struct eapol_frame *eapol = iob->data;
|
||||
struct eapol_handler *handler;
|
||||
|
||||
|
||||
+3
-1
@@ -234,12 +234,14 @@ static int eth_slow_marker_rx ( struct io_buffer *iobuf,
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer source address
|
||||
* @v flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int eth_slow_rx ( struct io_buffer *iobuf,
|
||||
struct net_device *netdev,
|
||||
const void *ll_dest __unused,
|
||||
const void *ll_source __unused ) {
|
||||
const void *ll_source __unused,
|
||||
unsigned int flags __unused ) {
|
||||
union eth_slow_packet *eth_slow = iobuf->data;
|
||||
|
||||
/* Sanity checks */
|
||||
|
||||
+7
-1
@@ -71,11 +71,13 @@ static int eth_push ( struct net_device *netdev __unused,
|
||||
* @ret ll_dest Link-layer destination address
|
||||
* @ret ll_source Source link-layer address
|
||||
* @ret net_proto Network-layer protocol, in network-byte order
|
||||
* @ret flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int eth_pull ( struct net_device *netdev __unused,
|
||||
struct io_buffer *iobuf, const void **ll_dest,
|
||||
const void **ll_source, uint16_t *net_proto ) {
|
||||
const void **ll_source, uint16_t *net_proto,
|
||||
unsigned int *flags ) {
|
||||
struct ethhdr *ethhdr = iobuf->data;
|
||||
|
||||
/* Sanity check */
|
||||
@@ -92,6 +94,10 @@ static int eth_pull ( struct net_device *netdev __unused,
|
||||
*ll_dest = ethhdr->h_dest;
|
||||
*ll_source = ethhdr->h_source;
|
||||
*net_proto = ethhdr->h_protocol;
|
||||
*flags = ( ( is_multicast_ether_addr ( ethhdr->h_dest ) ?
|
||||
LL_MULTICAST : 0 ) |
|
||||
( is_broadcast_ether_addr ( ethhdr->h_dest ) ?
|
||||
LL_BROADCAST : 0 ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+62
-26
@@ -1580,7 +1580,7 @@ static void fc_ulp_close ( struct fc_ulp *ulp, int rc ) {
|
||||
fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
|
||||
|
||||
/* Sanity check */
|
||||
assert ( ulp->usage == 0 );
|
||||
assert ( list_empty ( &ulp->users ) );
|
||||
|
||||
/* Stop link monitor */
|
||||
fc_link_stop ( &ulp->link );
|
||||
@@ -1594,35 +1594,50 @@ static void fc_ulp_close ( struct fc_ulp *ulp, int rc ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment Fibre Channel upper-layer protocol active usage count
|
||||
* Attach Fibre Channel upper-layer protocol user
|
||||
*
|
||||
* @v ulp Fibre Channel ulp
|
||||
* @v ulp Fibre Channel upper-layer protocol
|
||||
* @v user Fibre Channel upper-layer protocol user
|
||||
*/
|
||||
void fc_ulp_increment ( struct fc_ulp *ulp ) {
|
||||
void fc_ulp_attach ( struct fc_ulp *ulp, struct fc_ulp_user *user ) {
|
||||
|
||||
/* Sanity check */
|
||||
assert ( user->ulp == NULL );
|
||||
|
||||
/* Increment peer's usage count */
|
||||
fc_peer_increment ( ulp->peer );
|
||||
|
||||
/* Increment our usage count */
|
||||
ulp->usage++;
|
||||
/* Attach user */
|
||||
user->ulp = fc_ulp_get ( ulp );
|
||||
list_add ( &user->list, &ulp->users );
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement Fibre Channel upper-layer protocol active usage count
|
||||
* Detach Fibre Channel upper-layer protocol user
|
||||
*
|
||||
* @v ulp Fibre Channel ulp
|
||||
* @v user Fibre Channel upper-layer protocol user
|
||||
*/
|
||||
void fc_ulp_decrement ( struct fc_ulp *ulp ) {
|
||||
void fc_ulp_detach ( struct fc_ulp_user *user ) {
|
||||
struct fc_ulp *ulp = user->ulp;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( ulp->usage > 0 );
|
||||
/* Do nothing if not attached */
|
||||
if ( ! ulp )
|
||||
return;
|
||||
|
||||
/* Decrement our usage count and log out if we reach zero */
|
||||
if ( --(ulp->usage) == 0 )
|
||||
/* Sanity checks */
|
||||
list_check_contains ( user, &ulp->users, list );
|
||||
|
||||
/* Detach user and log out if no users remain */
|
||||
list_del ( &user->list );
|
||||
if ( list_empty ( &ulp->users ) )
|
||||
fc_ulp_logout ( ulp, 0 );
|
||||
|
||||
/* Decrement our peer's usage count */
|
||||
fc_peer_decrement ( ulp->peer );
|
||||
|
||||
/* Drop reference */
|
||||
user->ulp = NULL;
|
||||
fc_ulp_put ( ulp );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1636,6 +1651,8 @@ void fc_ulp_decrement ( struct fc_ulp *ulp ) {
|
||||
*/
|
||||
int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
|
||||
int originated ) {
|
||||
struct fc_ulp_user *user;
|
||||
struct fc_ulp_user *tmp;
|
||||
|
||||
/* Perform implicit logout if logged in and service parameters differ */
|
||||
if ( fc_link_ok ( &ulp->link ) &&
|
||||
@@ -1644,6 +1661,22 @@ int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
|
||||
fc_ulp_logout ( ulp, 0 );
|
||||
}
|
||||
|
||||
/* Work around a bug in some versions of the Linux Fibre
|
||||
* Channel stack, which fail to fully initialise image pairs
|
||||
* established via a PRLI originated by the Linux stack
|
||||
* itself.
|
||||
*/
|
||||
if ( originated )
|
||||
ulp->flags |= FC_ULP_ORIGINATED_LOGIN_OK;
|
||||
if ( ! ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) ) {
|
||||
DBGC ( ulp, "FCULP %s/%02x sending extra PRLI to work around "
|
||||
"Linux bug\n",
|
||||
fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
|
||||
fc_link_stop ( &ulp->link );
|
||||
fc_link_start ( &ulp->link );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Log in, if applicable */
|
||||
if ( ! fc_link_ok ( &ulp->link ) ) {
|
||||
|
||||
@@ -1670,18 +1703,11 @@ int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
|
||||
/* Record login */
|
||||
fc_link_up ( &ulp->link );
|
||||
|
||||
/* Work around a bug in some versions of the Linux Fibre
|
||||
* Channel stack, which fail to fully initialise image pairs
|
||||
* established via a PRLI originated by the Linux stack
|
||||
* itself.
|
||||
*/
|
||||
if ( originated )
|
||||
ulp->flags |= FC_ULP_ORIGINATED_LOGIN_OK;
|
||||
if ( ! ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) ) {
|
||||
DBGC ( ulp, "FCULP %s/%02x sending extra PRLI to work around "
|
||||
"Linux bug\n",
|
||||
fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
|
||||
fc_link_start ( &ulp->link );
|
||||
/* Notify users of link state change */
|
||||
list_for_each_entry_safe ( user, tmp, &ulp->users, list ) {
|
||||
fc_ulp_user_get ( user );
|
||||
user->examine ( user );
|
||||
fc_ulp_user_put ( user );
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1694,6 +1720,8 @@ int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
|
||||
* @v rc Reason for logout
|
||||
*/
|
||||
void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) {
|
||||
struct fc_ulp_user *user;
|
||||
struct fc_ulp_user *tmp;
|
||||
|
||||
DBGC ( ulp, "FCULP %s/%02x logged out: %s\n",
|
||||
fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
|
||||
@@ -1711,8 +1739,15 @@ void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) {
|
||||
/* Record logout */
|
||||
fc_link_err ( &ulp->link, rc );
|
||||
|
||||
/* Notify users of link state change */
|
||||
list_for_each_entry_safe ( user, tmp, &ulp->users, list ) {
|
||||
fc_ulp_user_get ( user );
|
||||
user->examine ( user );
|
||||
fc_ulp_user_put ( user );
|
||||
}
|
||||
|
||||
/* Close ULP if there are no clients attached */
|
||||
if ( ulp->usage == 0 )
|
||||
if ( list_empty ( &ulp->users ) )
|
||||
fc_ulp_close ( ulp, rc );
|
||||
}
|
||||
|
||||
@@ -1795,6 +1830,7 @@ static struct fc_ulp * fc_ulp_create ( struct fc_peer *peer,
|
||||
ulp->peer = fc_peer_get ( peer );
|
||||
list_add_tail ( &ulp->list, &peer->ulps );
|
||||
ulp->type = type;
|
||||
INIT_LIST_HEAD ( &ulp->users );
|
||||
|
||||
/* Start link state monitor */
|
||||
fc_link_start ( &ulp->link );
|
||||
|
||||
+8
-8
@@ -244,20 +244,15 @@ static struct interface_descriptor fc_els_job_desc =
|
||||
/**
|
||||
* Fibre Channel ELS process
|
||||
*
|
||||
* @v process Process
|
||||
* @v els Fibre Channel ELS transaction
|
||||
*/
|
||||
static void fc_els_step ( struct process *process ) {
|
||||
struct fc_els *els =
|
||||
container_of ( process, struct fc_els, process );
|
||||
static void fc_els_step ( struct fc_els *els ) {
|
||||
int xchg_id;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( fc_els_is_request ( els ) );
|
||||
|
||||
/* Stop process */
|
||||
process_del ( &els->process );
|
||||
|
||||
/* Create exchange */
|
||||
if ( ( xchg_id = fc_xchg_originate ( &els->xchg, els->port,
|
||||
&els->peer_port_id,
|
||||
@@ -278,6 +273,10 @@ static void fc_els_step ( struct process *process ) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Fibre Channel ELS process descriptor */
|
||||
static struct process_descriptor fc_els_process_desc =
|
||||
PROC_DESC_ONCE ( struct fc_els, process, fc_els_step );
|
||||
|
||||
/**
|
||||
* Create ELS transaction
|
||||
*
|
||||
@@ -298,7 +297,8 @@ static struct fc_els * fc_els_create ( struct fc_port *port,
|
||||
ref_init ( &els->refcnt, fc_els_free );
|
||||
intf_init ( &els->job, &fc_els_job_desc, &els->refcnt );
|
||||
intf_init ( &els->xchg, &fc_els_xchg_desc, &els->refcnt );
|
||||
process_init_stopped ( &els->process, fc_els_step, &els->refcnt );
|
||||
process_init_stopped ( &els->process, &fc_els_process_desc,
|
||||
&els->refcnt );
|
||||
els->port = fc_port_get ( port );
|
||||
memcpy ( &els->port_id, port_id, sizeof ( els->port_id ) );
|
||||
memcpy ( &els->peer_port_id, peer_port_id,
|
||||
|
||||
+8
-8
@@ -153,19 +153,14 @@ static int fc_ns_query_deliver ( struct fc_ns_query *query,
|
||||
/**
|
||||
* Name server query process
|
||||
*
|
||||
* @v process Process
|
||||
* @v query Name server query
|
||||
*/
|
||||
static void fc_ns_query_step ( struct process *process ) {
|
||||
struct fc_ns_query *query =
|
||||
container_of ( process, struct fc_ns_query, process );
|
||||
static void fc_ns_query_step ( struct fc_ns_query *query ) {
|
||||
struct xfer_metadata meta;
|
||||
struct fc_ns_gid_pn_request gid_pn;
|
||||
int xchg_id;
|
||||
int rc;
|
||||
|
||||
/* Stop process */
|
||||
process_del ( &query->process );
|
||||
|
||||
/* Create exchange */
|
||||
if ( ( xchg_id = fc_xchg_originate ( &query->xchg, query->port,
|
||||
&fc_gs_port_id,
|
||||
@@ -208,6 +203,10 @@ static struct interface_operation fc_ns_query_xchg_op[] = {
|
||||
static struct interface_descriptor fc_ns_query_xchg_desc =
|
||||
INTF_DESC ( struct fc_ns_query, xchg, fc_ns_query_xchg_op );
|
||||
|
||||
/** Name server process descriptor */
|
||||
static struct process_descriptor fc_ns_query_process_desc =
|
||||
PROC_DESC_ONCE ( struct fc_ns_query, process, fc_ns_query_step );
|
||||
|
||||
/**
|
||||
* Issue Fibre Channel name server query
|
||||
*
|
||||
@@ -226,7 +225,8 @@ int fc_ns_query ( struct fc_peer *peer, struct fc_port *port,
|
||||
return -ENOMEM;
|
||||
ref_init ( &query->refcnt, fc_ns_query_free );
|
||||
intf_init ( &query->xchg, &fc_ns_query_xchg_desc, &query->refcnt );
|
||||
process_init ( &query->process, fc_ns_query_step, &query->refcnt );
|
||||
process_init ( &query->process, &fc_ns_query_process_desc,
|
||||
&query->refcnt );
|
||||
query->peer = fc_peer_get ( peer );
|
||||
query->port = fc_port_get ( port );
|
||||
query->done = done;
|
||||
|
||||
+6
-2
@@ -331,10 +331,12 @@ static struct io_buffer * fcoe_alloc_iob ( struct fcoe_port *fcoe __unused,
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer source address
|
||||
* @v flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
const void *ll_dest, const void *ll_source ) {
|
||||
const void *ll_dest, const void *ll_source,
|
||||
unsigned int flags __unused ) {
|
||||
struct fcoe_header *fcoehdr;
|
||||
struct fcoe_footer *fcoeftr;
|
||||
struct fcoe_port *fcoe;
|
||||
@@ -924,12 +926,14 @@ static struct fip_handler fip_handlers[] = {
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer source address
|
||||
* @v flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int fcoe_fip_rx ( struct io_buffer *iobuf,
|
||||
struct net_device *netdev,
|
||||
const void *ll_dest,
|
||||
const void *ll_source __unused ) {
|
||||
const void *ll_source __unused,
|
||||
unsigned int flags __unused ) {
|
||||
struct fip_header *fiphdr = iobuf->data;
|
||||
struct fip_descriptors descs;
|
||||
struct fip_handler *handler;
|
||||
|
||||
+45
-23
@@ -146,8 +146,8 @@ struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor = {
|
||||
struct fcp_device {
|
||||
/** Reference count */
|
||||
struct refcnt refcnt;
|
||||
/** Fibre Channel upper-layer protocol */
|
||||
struct fc_ulp *ulp;
|
||||
/** Fibre Channel upper-layer protocol user */
|
||||
struct fc_ulp_user user;
|
||||
/** SCSI command issuing interface */
|
||||
struct interface scsi;
|
||||
/** List of active commands */
|
||||
@@ -649,11 +649,9 @@ static int fcpcmd_recv_unknown ( struct fcp_command *fcpcmd,
|
||||
/**
|
||||
* Transmit FCP frame
|
||||
*
|
||||
* @v process FCP command process
|
||||
* @v fcpcmd FCP command
|
||||
*/
|
||||
static void fcpcmd_step ( struct process *process ) {
|
||||
struct fcp_command *fcpcmd =
|
||||
container_of ( process, struct fcp_command, process );
|
||||
static void fcpcmd_step ( struct fcp_command *fcpcmd ) {
|
||||
int rc;
|
||||
|
||||
/* Send the current IU */
|
||||
@@ -723,6 +721,10 @@ static struct interface_operation fcpcmd_xchg_op[] = {
|
||||
static struct interface_descriptor fcpcmd_xchg_desc =
|
||||
INTF_DESC_PASSTHRU ( struct fcp_command, xchg, fcpcmd_xchg_op, scsi );
|
||||
|
||||
/** FCP command process descriptor */
|
||||
static struct process_descriptor fcpcmd_process_desc =
|
||||
PROC_DESC ( struct fcp_command, process, fcpcmd_step );
|
||||
|
||||
/**
|
||||
* Issue FCP SCSI command
|
||||
*
|
||||
@@ -734,13 +736,13 @@ static struct interface_descriptor fcpcmd_xchg_desc =
|
||||
static int fcpdev_scsi_command ( struct fcp_device *fcpdev,
|
||||
struct interface *parent,
|
||||
struct scsi_cmd *command ) {
|
||||
struct fcp_prli_service_parameters *param = fcpdev->ulp->param;
|
||||
struct fcp_prli_service_parameters *param = fcpdev->user.ulp->param;
|
||||
struct fcp_command *fcpcmd;
|
||||
int xchg_id;
|
||||
int rc;
|
||||
|
||||
/* Check link */
|
||||
if ( ( rc = fcpdev->ulp->link.rc ) != 0 ) {
|
||||
if ( ( rc = fcpdev->user.ulp->link.rc ) != 0 ) {
|
||||
DBGC ( fcpdev, "FCP %p could not issue command while link is "
|
||||
"down: %s\n", fcpdev, strerror ( rc ) );
|
||||
goto err_link;
|
||||
@@ -748,7 +750,7 @@ static int fcpdev_scsi_command ( struct fcp_device *fcpdev,
|
||||
|
||||
/* Check target capability */
|
||||
assert ( param != NULL );
|
||||
assert ( fcpdev->ulp->param_len >= sizeof ( *param ) );
|
||||
assert ( fcpdev->user.ulp->param_len >= sizeof ( *param ) );
|
||||
if ( ! ( param->flags & htonl ( FCP_PRLI_TARGET ) ) ) {
|
||||
DBGC ( fcpdev, "FCP %p could not issue command: not a target\n",
|
||||
fcpdev );
|
||||
@@ -765,15 +767,16 @@ static int fcpdev_scsi_command ( struct fcp_device *fcpdev,
|
||||
ref_init ( &fcpcmd->refcnt, fcpcmd_free );
|
||||
intf_init ( &fcpcmd->scsi, &fcpcmd_scsi_desc, &fcpcmd->refcnt );
|
||||
intf_init ( &fcpcmd->xchg, &fcpcmd_xchg_desc, &fcpcmd->refcnt );
|
||||
process_init_stopped ( &fcpcmd->process, fcpcmd_step, &fcpcmd->refcnt );
|
||||
process_init_stopped ( &fcpcmd->process, &fcpcmd_process_desc,
|
||||
&fcpcmd->refcnt );
|
||||
fcpcmd->fcpdev = fcpdev_get ( fcpdev );
|
||||
list_add ( &fcpcmd->list, &fcpdev->fcpcmds );
|
||||
memcpy ( &fcpcmd->command, command, sizeof ( fcpcmd->command ) );
|
||||
|
||||
/* Create new exchange */
|
||||
if ( ( xchg_id = fc_xchg_originate ( &fcpcmd->xchg,
|
||||
fcpdev->ulp->peer->port,
|
||||
&fcpdev->ulp->peer->port_id,
|
||||
fcpdev->user.ulp->peer->port,
|
||||
&fcpdev->user.ulp->peer->port_id,
|
||||
FC_TYPE_FCP ) ) < 0 ) {
|
||||
rc = xchg_id;
|
||||
DBGC ( fcpdev, "FCP %p could not create exchange: %s\n",
|
||||
@@ -822,11 +825,7 @@ static void fcpdev_close ( struct fcp_device *fcpdev, int rc ) {
|
||||
}
|
||||
|
||||
/* Drop reference to ULP */
|
||||
if ( fcpdev->ulp ) {
|
||||
fc_ulp_decrement ( fcpdev->ulp );
|
||||
fc_ulp_put ( fcpdev->ulp );
|
||||
fcpdev->ulp = NULL;
|
||||
}
|
||||
fc_ulp_detach ( &fcpdev->user );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -836,7 +835,8 @@ static void fcpdev_close ( struct fcp_device *fcpdev, int rc ) {
|
||||
* @ret len Length of window
|
||||
*/
|
||||
static size_t fcpdev_window ( struct fcp_device *fcpdev ) {
|
||||
return ( fc_link_ok ( &fcpdev->ulp->link ) ? ~( ( size_t ) 0 ) : 0 );
|
||||
return ( fc_link_ok ( &fcpdev->user.ulp->link ) ?
|
||||
~( ( size_t ) 0 ) : 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -897,15 +897,15 @@ static struct device * fcpdev_identify_device ( struct fcp_device *fcpdev ) {
|
||||
/* We know the underlying device only if the link is up;
|
||||
* otherwise we don't have a port to examine.
|
||||
*/
|
||||
if ( ! fc_link_ok ( &fcpdev->ulp->link ) ) {
|
||||
if ( ! fc_link_ok ( &fcpdev->user.ulp->link ) ) {
|
||||
DBGC ( fcpdev, "FCP %p doesn't know underlying device "
|
||||
"until link is up\n", fcpdev );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Hand off to port's transport interface */
|
||||
assert ( fcpdev->ulp->peer->port != NULL );
|
||||
return identify_device ( &fcpdev->ulp->peer->port->transport );
|
||||
assert ( fcpdev->user.ulp->peer->port != NULL );
|
||||
return identify_device ( &fcpdev->user.ulp->peer->port->transport );
|
||||
}
|
||||
|
||||
/** FCP device SCSI interface operations */
|
||||
@@ -923,6 +923,26 @@ static struct interface_operation fcpdev_scsi_op[] = {
|
||||
static struct interface_descriptor fcpdev_scsi_desc =
|
||||
INTF_DESC ( struct fcp_device, scsi, fcpdev_scsi_op );
|
||||
|
||||
/**
|
||||
* Examine FCP ULP link state
|
||||
*
|
||||
* @v user Fibre Channel upper-layer protocol user
|
||||
*/
|
||||
static void fcpdev_examine ( struct fc_ulp_user *user ) {
|
||||
struct fcp_device *fcpdev =
|
||||
container_of ( user, struct fcp_device, user );
|
||||
|
||||
if ( fc_link_ok ( &fcpdev->user.ulp->link ) ) {
|
||||
DBGC ( fcpdev, "FCP %p link is up\n", fcpdev );
|
||||
} else {
|
||||
DBGC ( fcpdev, "FCP %p link is down: %s\n",
|
||||
fcpdev, strerror ( fcpdev->user.ulp->link.rc ) );
|
||||
}
|
||||
|
||||
/* Notify SCSI layer of window change */
|
||||
xfer_window_changed ( &fcpdev->scsi );
|
||||
}
|
||||
|
||||
/**
|
||||
* Open FCP device
|
||||
*
|
||||
@@ -953,11 +973,13 @@ static int fcpdev_open ( struct interface *parent, struct fc_name *wwn,
|
||||
ref_init ( &fcpdev->refcnt, NULL );
|
||||
intf_init ( &fcpdev->scsi, &fcpdev_scsi_desc, &fcpdev->refcnt );
|
||||
INIT_LIST_HEAD ( &fcpdev->fcpcmds );
|
||||
fcpdev->ulp = fc_ulp_get ( ulp );
|
||||
fc_ulp_increment ( fcpdev->ulp );
|
||||
fc_ulp_user_init ( &fcpdev->user, fcpdev_examine, &fcpdev->refcnt );
|
||||
|
||||
DBGC ( fcpdev, "FCP %p opened for %s\n", fcpdev, fc_ntoa ( wwn ) );
|
||||
|
||||
/* Attach to Fibre Channel ULP */
|
||||
fc_ulp_attach ( ulp, &fcpdev->user );
|
||||
|
||||
/* Preserve parameters required for boot firmware table */
|
||||
memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) );
|
||||
memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) );
|
||||
|
||||
@@ -866,10 +866,7 @@ static void ib_step ( struct process *process __unused ) {
|
||||
}
|
||||
|
||||
/** Infiniband event queue process */
|
||||
struct process ib_process __permanent_process = {
|
||||
.list = LIST_HEAD_INIT ( ib_process.list ),
|
||||
.step = ib_step,
|
||||
};
|
||||
PERMANENT_PROCESS ( ib_process, ib_step );
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
|
||||
@@ -92,7 +92,7 @@ struct ib_cmrc_connection {
|
||||
/**
|
||||
* Shut down CMRC connection gracefully
|
||||
*
|
||||
* @v process Process
|
||||
* @v cmrc Communication-Managed Reliable Connection
|
||||
*
|
||||
* The Infiniband data structures are not reference-counted or
|
||||
* guarded. It is therefore unsafe to shut them down while we may be
|
||||
@@ -107,9 +107,7 @@ struct ib_cmrc_connection {
|
||||
* connection, ensuring that the structure is not freed before the
|
||||
* shutdown process has run.
|
||||
*/
|
||||
static void ib_cmrc_shutdown ( struct process *process ) {
|
||||
struct ib_cmrc_connection *cmrc =
|
||||
container_of ( process, struct ib_cmrc_connection, shutdown );
|
||||
static void ib_cmrc_shutdown ( struct ib_cmrc_connection *cmrc ) {
|
||||
|
||||
DBGC ( cmrc, "CMRC %p shutting down\n", cmrc );
|
||||
|
||||
@@ -119,9 +117,6 @@ static void ib_cmrc_shutdown ( struct process *process ) {
|
||||
ib_destroy_cq ( cmrc->ibdev, cmrc->cq );
|
||||
ib_close ( cmrc->ibdev );
|
||||
|
||||
/* Remove process from run queue */
|
||||
process_del ( &cmrc->shutdown );
|
||||
|
||||
/* Drop the remaining reference */
|
||||
ref_put ( &cmrc->refcnt );
|
||||
}
|
||||
@@ -180,6 +175,9 @@ static void ib_cmrc_changed ( struct ib_device *ibdev __unused,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Notify upper connection of window change */
|
||||
xfer_window_changed ( &cmrc->xfer );
|
||||
|
||||
/* If we are disconnected, close the upper connection */
|
||||
if ( rc_cm != 0 ) {
|
||||
ib_cmrc_close ( cmrc, rc_cm );
|
||||
@@ -360,6 +358,11 @@ static struct interface_operation ib_cmrc_xfer_operations[] = {
|
||||
static struct interface_descriptor ib_cmrc_xfer_desc =
|
||||
INTF_DESC ( struct ib_cmrc_connection, xfer, ib_cmrc_xfer_operations );
|
||||
|
||||
/** CMRC shutdown process descriptor */
|
||||
static struct process_descriptor ib_cmrc_shutdown_desc =
|
||||
PROC_DESC_ONCE ( struct ib_cmrc_connection, shutdown,
|
||||
ib_cmrc_shutdown );
|
||||
|
||||
/**
|
||||
* Open CMRC connection
|
||||
*
|
||||
@@ -385,7 +388,7 @@ int ib_cmrc_open ( struct interface *xfer, struct ib_device *ibdev,
|
||||
cmrc->ibdev = ibdev;
|
||||
memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) );
|
||||
memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) );
|
||||
process_init_stopped ( &cmrc->shutdown, ib_cmrc_shutdown,
|
||||
process_init_stopped ( &cmrc->shutdown, &ib_cmrc_shutdown_desc,
|
||||
&cmrc->refcnt );
|
||||
|
||||
/* Open Infiniband device */
|
||||
|
||||
+227
-148
@@ -14,6 +14,7 @@
|
||||
#include <ipxe/tcpip.h>
|
||||
#include <ipxe/dhcp.h>
|
||||
#include <ipxe/settings.h>
|
||||
#include <ipxe/timer.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
@@ -30,7 +31,10 @@ static uint8_t next_ident_high = 0;
|
||||
struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
|
||||
|
||||
/** List of fragment reassembly buffers */
|
||||
static LIST_HEAD ( frag_buffers );
|
||||
static LIST_HEAD ( ipv4_fragments );
|
||||
|
||||
/** Fragment reassembly timeout */
|
||||
#define IP_FRAG_TIMEOUT ( TICKS_PER_SEC / 2 )
|
||||
|
||||
/**
|
||||
* Add IPv4 minirouting table entry
|
||||
@@ -46,16 +50,16 @@ add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
|
||||
struct in_addr netmask, struct in_addr gateway ) {
|
||||
struct ipv4_miniroute *miniroute;
|
||||
|
||||
DBG ( "IPv4 add %s", inet_ntoa ( address ) );
|
||||
DBG ( "/%s ", inet_ntoa ( netmask ) );
|
||||
DBGC ( netdev, "IPv4 add %s", inet_ntoa ( address ) );
|
||||
DBGC ( netdev, "/%s ", inet_ntoa ( netmask ) );
|
||||
if ( gateway.s_addr )
|
||||
DBG ( "gw %s ", inet_ntoa ( gateway ) );
|
||||
DBG ( "via %s\n", netdev->name );
|
||||
DBGC ( netdev, "gw %s ", inet_ntoa ( gateway ) );
|
||||
DBGC ( netdev, "via %s\n", netdev->name );
|
||||
|
||||
/* Allocate and populate miniroute structure */
|
||||
miniroute = malloc ( sizeof ( *miniroute ) );
|
||||
if ( ! miniroute ) {
|
||||
DBG ( "IPv4 could not add miniroute\n" );
|
||||
DBGC ( netdev, "IPv4 could not add miniroute\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -83,12 +87,13 @@ add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
|
||||
* @v miniroute Routing table entry
|
||||
*/
|
||||
static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
|
||||
struct net_device *netdev = miniroute->netdev;
|
||||
|
||||
DBG ( "IPv4 del %s", inet_ntoa ( miniroute->address ) );
|
||||
DBG ( "/%s ", inet_ntoa ( miniroute->netmask ) );
|
||||
DBGC ( netdev, "IPv4 del %s", inet_ntoa ( miniroute->address ) );
|
||||
DBGC ( netdev, "/%s ", inet_ntoa ( miniroute->netmask ) );
|
||||
if ( miniroute->gateway.s_addr )
|
||||
DBG ( "gw %s ", inet_ntoa ( miniroute->gateway ) );
|
||||
DBG ( "via %s\n", miniroute->netdev->name );
|
||||
DBGC ( netdev, "gw %s ", inet_ntoa ( miniroute->gateway ) );
|
||||
DBGC ( netdev, "via %s\n", miniroute->netdev->name );
|
||||
|
||||
netdev_put ( miniroute->netdev );
|
||||
list_del ( &miniroute->list );
|
||||
@@ -110,10 +115,6 @@ static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
|
||||
int local;
|
||||
int has_gw;
|
||||
|
||||
/* Never attempt to route the broadcast address */
|
||||
if ( dest->s_addr == INADDR_BROADCAST )
|
||||
return NULL;
|
||||
|
||||
/* Find first usable route in routing table */
|
||||
list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
|
||||
if ( ! netdev_is_open ( miniroute->netdev ) )
|
||||
@@ -132,103 +133,128 @@ static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fragment reassembly counter timeout
|
||||
* Expire fragment reassembly buffer
|
||||
*
|
||||
* @v timer Retry timer
|
||||
* @v over If asserted, the timer is greater than @c MAX_TIMEOUT
|
||||
* @v timer Retry timer
|
||||
* @v fail Failure indicator
|
||||
*/
|
||||
static void ipv4_frag_expired ( struct retry_timer *timer __unused,
|
||||
int over ) {
|
||||
if ( over ) {
|
||||
DBG ( "Fragment reassembly timeout" );
|
||||
/* Free the fragment buffer */
|
||||
}
|
||||
static void ipv4_fragment_expired ( struct retry_timer *timer,
|
||||
int fail __unused ) {
|
||||
struct ipv4_fragment *frag =
|
||||
container_of ( timer, struct ipv4_fragment, timer );
|
||||
struct iphdr *iphdr = frag->iobuf->data;
|
||||
|
||||
DBGC ( iphdr->src, "IPv4 fragment %04x expired\n",
|
||||
ntohs ( iphdr->ident ) );
|
||||
free_iob ( frag->iobuf );
|
||||
list_del ( &frag->list );
|
||||
free ( frag );
|
||||
}
|
||||
|
||||
/**
|
||||
* Free fragment buffer
|
||||
* Find matching fragment reassembly buffer
|
||||
*
|
||||
* @v fragbug Fragment buffer
|
||||
* @v iphdr IPv4 header
|
||||
* @ret frag Fragment reassembly buffer, or NULL
|
||||
*/
|
||||
static void free_fragbuf ( struct frag_buffer *fragbuf ) {
|
||||
free ( fragbuf );
|
||||
static struct ipv4_fragment * ipv4_fragment ( struct iphdr *iphdr ) {
|
||||
struct ipv4_fragment *frag;
|
||||
struct iphdr *frag_iphdr;
|
||||
|
||||
list_for_each_entry ( frag, &ipv4_fragments, list ) {
|
||||
frag_iphdr = frag->iobuf->data;
|
||||
|
||||
if ( ( iphdr->src.s_addr == frag_iphdr->src.s_addr ) &&
|
||||
( iphdr->ident == frag_iphdr->ident ) ) {
|
||||
return frag;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fragment reassembler
|
||||
*
|
||||
* @v iobuf I/O buffer, fragment of the datagram
|
||||
* @ret frag_iob Reassembled packet, or NULL
|
||||
* @v iobuf I/O buffer
|
||||
* @ret iobuf Reassembled packet, or NULL
|
||||
*/
|
||||
static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
|
||||
static struct io_buffer * ipv4_reassemble ( struct io_buffer *iobuf ) {
|
||||
struct iphdr *iphdr = iobuf->data;
|
||||
struct frag_buffer *fragbuf;
|
||||
|
||||
/**
|
||||
* Check if the fragment belongs to any fragment series
|
||||
*/
|
||||
list_for_each_entry ( fragbuf, &frag_buffers, list ) {
|
||||
if ( fragbuf->ident == iphdr->ident &&
|
||||
fragbuf->src.s_addr == iphdr->src.s_addr ) {
|
||||
/**
|
||||
* Check if the packet is the expected fragment
|
||||
*
|
||||
* The offset of the new packet must be equal to the
|
||||
* length of the data accumulated so far (the length of
|
||||
* the reassembled I/O buffer
|
||||
*/
|
||||
if ( iob_len ( fragbuf->frag_iob ) ==
|
||||
( iphdr->frags & IP_MASK_OFFSET ) ) {
|
||||
/**
|
||||
* Append the contents of the fragment to the
|
||||
* reassembled I/O buffer
|
||||
*/
|
||||
iob_pull ( iobuf, sizeof ( *iphdr ) );
|
||||
memcpy ( iob_put ( fragbuf->frag_iob,
|
||||
iob_len ( iobuf ) ),
|
||||
iobuf->data, iob_len ( iobuf ) );
|
||||
free_iob ( iobuf );
|
||||
size_t offset = ( ( ntohs ( iphdr->frags ) & IP_MASK_OFFSET ) << 3 );
|
||||
unsigned int more_frags = ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ));
|
||||
size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
|
||||
struct ipv4_fragment *frag;
|
||||
size_t expected_offset;
|
||||
struct io_buffer *new_iobuf;
|
||||
|
||||
/** Check if the fragment series is over */
|
||||
if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) {
|
||||
iobuf = fragbuf->frag_iob;
|
||||
free_fragbuf ( fragbuf );
|
||||
return iobuf;
|
||||
}
|
||||
/* Find matching fragment reassembly buffer, if any */
|
||||
frag = ipv4_fragment ( iphdr );
|
||||
|
||||
} else {
|
||||
/* Discard the fragment series */
|
||||
free_fragbuf ( fragbuf );
|
||||
free_iob ( iobuf );
|
||||
}
|
||||
return NULL;
|
||||
/* Drop out-of-order fragments */
|
||||
expected_offset = ( frag ? frag->offset : 0 );
|
||||
if ( offset != expected_offset ) {
|
||||
DBGC ( iphdr->src, "IPv4 dropping out-of-sequence fragment "
|
||||
"%04x (%zd+%zd, expected %zd)\n",
|
||||
ntohs ( iphdr->ident ), offset,
|
||||
( iob_len ( iobuf ) - hdrlen ), expected_offset );
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/* Create or extend fragment reassembly buffer as applicable */
|
||||
if ( frag == NULL ) {
|
||||
|
||||
/* Create new fragment reassembly buffer */
|
||||
frag = zalloc ( sizeof ( *frag ) );
|
||||
if ( ! frag )
|
||||
goto drop;
|
||||
list_add ( &frag->list, &ipv4_fragments );
|
||||
frag->iobuf = iobuf;
|
||||
frag->offset = ( iob_len ( iobuf ) - hdrlen );
|
||||
timer_init ( &frag->timer, ipv4_fragment_expired, NULL );
|
||||
|
||||
} else {
|
||||
|
||||
/* Extend reassembly buffer */
|
||||
iob_pull ( iobuf, hdrlen );
|
||||
new_iobuf = alloc_iob ( iob_len ( frag->iobuf ) +
|
||||
iob_len ( iobuf ) );
|
||||
if ( ! new_iobuf ) {
|
||||
DBGC ( iphdr->src, "IPv4 could not extend reassembly "
|
||||
"buffer to %zd bytes\n",
|
||||
iob_len ( frag->iobuf ) + iob_len ( iobuf ) );
|
||||
goto drop;
|
||||
}
|
||||
memcpy ( iob_put ( new_iobuf, iob_len ( frag->iobuf ) ),
|
||||
frag->iobuf->data, iob_len ( frag->iobuf ) );
|
||||
memcpy ( iob_put ( new_iobuf, iob_len ( iobuf ) ),
|
||||
iobuf->data, iob_len ( iobuf ) );
|
||||
free_iob ( frag->iobuf );
|
||||
frag->iobuf = new_iobuf;
|
||||
frag->offset += iob_len ( iobuf );
|
||||
free_iob ( iobuf );
|
||||
iphdr = frag->iobuf->data;
|
||||
iphdr->len = ntohs ( iob_len ( frag->iobuf ) );
|
||||
|
||||
/* Stop fragment reassembly timer */
|
||||
stop_timer ( &frag->timer );
|
||||
|
||||
/* If this is the final fragment, return it */
|
||||
if ( ! more_frags ) {
|
||||
iobuf = frag->iobuf;
|
||||
list_del ( &frag->list );
|
||||
free ( frag );
|
||||
return iobuf;
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if the fragment is the first in the fragment series */
|
||||
if ( iphdr->frags & IP_MASK_MOREFRAGS &&
|
||||
( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) {
|
||||
|
||||
/** Create a new fragment buffer */
|
||||
fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) );
|
||||
fragbuf->ident = iphdr->ident;
|
||||
fragbuf->src = iphdr->src;
|
||||
|
||||
/* Set up the reassembly I/O buffer */
|
||||
fragbuf->frag_iob = alloc_iob ( IP_FRAG_IOB_SIZE );
|
||||
iob_pull ( iobuf, sizeof ( *iphdr ) );
|
||||
memcpy ( iob_put ( fragbuf->frag_iob, iob_len ( iobuf ) ),
|
||||
iobuf->data, iob_len ( iobuf ) );
|
||||
free_iob ( iobuf );
|
||||
/* (Re)start fragment reassembly timer */
|
||||
start_timer_fixed ( &frag->timer, IP_FRAG_TIMEOUT );
|
||||
|
||||
/* Set the reassembly timer */
|
||||
timer_init ( &fragbuf->frag_timer, ipv4_frag_expired, NULL );
|
||||
start_timer_fixed ( &fragbuf->frag_timer, IP_FRAG_TIMEOUT );
|
||||
return NULL;
|
||||
|
||||
/* Add the fragment buffer to the list of fragment buffers */
|
||||
list_add ( &fragbuf->list, &frag_buffers );
|
||||
}
|
||||
|
||||
drop:
|
||||
free_iob ( iobuf );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -260,15 +286,17 @@ static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
|
||||
*
|
||||
* @v dest IPv4 destination address
|
||||
* @v src IPv4 source address
|
||||
* @v netmask IPv4 subnet mask
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
|
||||
struct net_device *netdev, uint8_t *ll_dest ) {
|
||||
struct in_addr netmask, struct net_device *netdev,
|
||||
uint8_t *ll_dest ) {
|
||||
struct ll_protocol *ll_protocol = netdev->ll_protocol;
|
||||
|
||||
if ( dest.s_addr == INADDR_BROADCAST ) {
|
||||
if ( ( ( dest.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0 ) {
|
||||
/* Broadcast address */
|
||||
memcpy ( ll_dest, netdev->ll_broadcast,
|
||||
ll_protocol->ll_addr_len );
|
||||
@@ -306,6 +334,7 @@ static int ipv4_tx ( struct io_buffer *iobuf,
|
||||
struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
|
||||
struct ipv4_miniroute *miniroute;
|
||||
struct in_addr next_hop;
|
||||
struct in_addr netmask = { .s_addr = 0 };
|
||||
uint8_t ll_dest[MAX_LL_ADDR_LEN];
|
||||
int rc;
|
||||
|
||||
@@ -326,10 +355,12 @@ static int ipv4_tx ( struct io_buffer *iobuf,
|
||||
( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) &&
|
||||
( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
|
||||
iphdr->src = miniroute->address;
|
||||
netmask = miniroute->netmask;
|
||||
netdev = miniroute->netdev;
|
||||
}
|
||||
if ( ! netdev ) {
|
||||
DBG ( "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) );
|
||||
DBGC ( sin_dest->sin_addr, "IPv4 has no route to %s\n",
|
||||
inet_ntoa ( iphdr->dest ) );
|
||||
rc = -ENETUNREACH;
|
||||
goto err;
|
||||
}
|
||||
@@ -343,10 +374,12 @@ static int ipv4_tx ( struct io_buffer *iobuf,
|
||||
( ( netdev->rx_stats.good & 0xf ) << 0 ) );
|
||||
|
||||
/* Determine link-layer destination address */
|
||||
if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netdev,
|
||||
if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netmask, netdev,
|
||||
ll_dest ) ) != 0 ) {
|
||||
DBG ( "IPv4 has no link-layer address for %s: %s\n",
|
||||
inet_ntoa ( next_hop ), strerror ( rc ) );
|
||||
DBGC ( sin_dest->sin_addr, "IPv4 has no link-layer address for "
|
||||
"%s: %s\n", inet_ntoa ( next_hop ), strerror ( rc ) );
|
||||
/* Record error for diagnosis */
|
||||
netdev_tx_err ( netdev, iob_disown ( iobuf ), rc );
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -356,16 +389,17 @@ static int ipv4_tx ( struct io_buffer *iobuf,
|
||||
iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
|
||||
|
||||
/* Print IP4 header for debugging */
|
||||
DBG ( "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
|
||||
DBG ( "%s len %d proto %d id %04x csum %04x\n",
|
||||
inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
|
||||
ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
|
||||
DBGC2 ( sin_dest->sin_addr, "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
|
||||
DBGC2 ( sin_dest->sin_addr, "%s len %d proto %d id %04x csum %04x\n",
|
||||
inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ),
|
||||
iphdr->protocol, ntohs ( iphdr->ident ),
|
||||
ntohs ( iphdr->chksum ) );
|
||||
|
||||
/* Hand off to link layer */
|
||||
if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest,
|
||||
netdev->ll_addr ) ) != 0 ) {
|
||||
DBG ( "IPv4 could not transmit packet via %s: %s\n",
|
||||
netdev->name, strerror ( rc ) );
|
||||
DBGC ( sin_dest->sin_addr, "IPv4 could not transmit packet "
|
||||
"via %s: %s\n", netdev->name, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -376,21 +410,60 @@ static int ipv4_tx ( struct io_buffer *iobuf,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if network device has any IPv4 address
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret has_any_addr Network device has any IPv4 address
|
||||
*/
|
||||
static int ipv4_has_any_addr ( struct net_device *netdev ) {
|
||||
struct ipv4_miniroute *miniroute;
|
||||
|
||||
list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
|
||||
if ( miniroute->netdev == netdev )
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if network device has a specific IPv4 address
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v addr IPv4 address
|
||||
* @ret has_addr Network device has this IPv4 address
|
||||
*/
|
||||
static int ipv4_has_addr ( struct net_device *netdev, struct in_addr addr ) {
|
||||
struct ipv4_miniroute *miniroute;
|
||||
|
||||
list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
|
||||
if ( ( miniroute->netdev == netdev ) &&
|
||||
( miniroute->address.s_addr == addr.s_addr ) ) {
|
||||
/* Found matching address */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process incoming packets
|
||||
*
|
||||
* @v iobuf I/O buffer
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer destination source
|
||||
* @v iobuf I/O buffer
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer destination source
|
||||
* @v flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This function expects an IP4 network datagram. It processes the headers
|
||||
* and sends it to the transport layer.
|
||||
*/
|
||||
static int ipv4_rx ( struct io_buffer *iobuf,
|
||||
struct net_device *netdev __unused,
|
||||
struct net_device *netdev,
|
||||
const void *ll_dest __unused,
|
||||
const void *ll_source __unused ) {
|
||||
const void *ll_source __unused,
|
||||
unsigned int flags ) {
|
||||
struct iphdr *iphdr = iobuf->data;
|
||||
size_t hdrlen;
|
||||
size_t len;
|
||||
@@ -404,77 +477,88 @@ static int ipv4_rx ( struct io_buffer *iobuf,
|
||||
|
||||
/* Sanity check the IPv4 header */
|
||||
if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
|
||||
DBG ( "IPv4 packet too short at %zd bytes (min %zd bytes)\n",
|
||||
iob_len ( iobuf ), sizeof ( *iphdr ) );
|
||||
DBGC ( iphdr->src, "IPv4 packet too short at %zd bytes (min "
|
||||
"%zd bytes)\n", iob_len ( iobuf ), sizeof ( *iphdr ) );
|
||||
goto err;
|
||||
}
|
||||
if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
|
||||
DBG ( "IPv4 version %#02x not supported\n", iphdr->verhdrlen );
|
||||
DBGC ( iphdr->src, "IPv4 version %#02x not supported\n",
|
||||
iphdr->verhdrlen );
|
||||
goto err;
|
||||
}
|
||||
hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
|
||||
if ( hdrlen < sizeof ( *iphdr ) ) {
|
||||
DBG ( "IPv4 header too short at %zd bytes (min %zd bytes)\n",
|
||||
hdrlen, sizeof ( *iphdr ) );
|
||||
DBGC ( iphdr->src, "IPv4 header too short at %zd bytes (min "
|
||||
"%zd bytes)\n", hdrlen, sizeof ( *iphdr ) );
|
||||
goto err;
|
||||
}
|
||||
if ( hdrlen > iob_len ( iobuf ) ) {
|
||||
DBG ( "IPv4 header too long at %zd bytes "
|
||||
"(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
|
||||
DBGC ( iphdr->src, "IPv4 header too long at %zd bytes "
|
||||
"(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
|
||||
goto err;
|
||||
}
|
||||
if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
|
||||
DBG ( "IPv4 checksum incorrect (is %04x including checksum "
|
||||
"field, should be 0000)\n", csum );
|
||||
DBGC ( iphdr->src, "IPv4 checksum incorrect (is %04x "
|
||||
"including checksum field, should be 0000)\n", csum );
|
||||
goto err;
|
||||
}
|
||||
len = ntohs ( iphdr->len );
|
||||
if ( len < hdrlen ) {
|
||||
DBG ( "IPv4 length too short at %zd bytes "
|
||||
"(header is %zd bytes)\n", len, hdrlen );
|
||||
DBGC ( iphdr->src, "IPv4 length too short at %zd bytes "
|
||||
"(header is %zd bytes)\n", len, hdrlen );
|
||||
goto err;
|
||||
}
|
||||
if ( len > iob_len ( iobuf ) ) {
|
||||
DBG ( "IPv4 length too long at %zd bytes "
|
||||
"(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
|
||||
DBGC ( iphdr->src, "IPv4 length too long at %zd bytes "
|
||||
"(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Print IPv4 header for debugging */
|
||||
DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
|
||||
DBG ( "%s len %d proto %d id %04x csum %04x\n",
|
||||
inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
|
||||
ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
|
||||
|
||||
/* Truncate packet to correct length, calculate pseudo-header
|
||||
* checksum and then strip off the IPv4 header.
|
||||
*/
|
||||
/* Truncate packet to correct length */
|
||||
iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
|
||||
pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
|
||||
iob_pull ( iobuf, hdrlen );
|
||||
|
||||
/* Fragment reassembly */
|
||||
if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) ||
|
||||
( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
|
||||
/* Pass the fragment to ipv4_reassemble() which either
|
||||
* returns a fully reassembled I/O buffer or NULL.
|
||||
/* Print IPv4 header for debugging */
|
||||
DBGC2 ( iphdr->src, "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
|
||||
DBGC2 ( iphdr->src, "%s len %d proto %d id %04x csum %04x\n",
|
||||
inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
|
||||
ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
|
||||
|
||||
/* Discard unicast packets not destined for us */
|
||||
if ( ( ! ( flags & LL_MULTICAST ) ) &&
|
||||
ipv4_has_any_addr ( netdev ) &&
|
||||
( ! ipv4_has_addr ( netdev, iphdr->dest ) ) ) {
|
||||
DBGC ( iphdr->src, "IPv4 discarding non-local unicast packet "
|
||||
"for %s\n", inet_ntoa ( iphdr->dest ) );
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Perform fragment reassembly if applicable */
|
||||
if ( iphdr->frags & htons ( IP_MASK_OFFSET | IP_MASK_MOREFRAGS ) ) {
|
||||
/* Pass the fragment to ipv4_reassemble() which returns
|
||||
* either a fully reassembled I/O buffer or NULL.
|
||||
*/
|
||||
iobuf = ipv4_reassemble ( iobuf );
|
||||
if ( ! iobuf )
|
||||
return 0;
|
||||
iphdr = iobuf->data;
|
||||
hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
|
||||
}
|
||||
|
||||
/* Construct socket addresses and hand off to transport layer */
|
||||
/* Construct socket addresses, calculate pseudo-header
|
||||
* checksum, and hand off to transport layer
|
||||
*/
|
||||
memset ( &src, 0, sizeof ( src ) );
|
||||
src.sin.sin_family = AF_INET;
|
||||
src.sin.sin_addr = iphdr->src;
|
||||
memset ( &dest, 0, sizeof ( dest ) );
|
||||
dest.sin.sin_family = AF_INET;
|
||||
dest.sin.sin_addr = iphdr->dest;
|
||||
pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
|
||||
iob_pull ( iobuf, hdrlen );
|
||||
if ( ( rc = tcpip_rx ( iobuf, iphdr->protocol, &src.st,
|
||||
&dest.st, pshdr_csum ) ) != 0 ) {
|
||||
DBG ( "IPv4 received packet rejected by stack: %s\n",
|
||||
strerror ( rc ) );
|
||||
DBGC ( src.sin.sin_addr, "IPv4 received packet rejected by "
|
||||
"stack: %s\n", strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -494,15 +578,10 @@ static int ipv4_rx ( struct io_buffer *iobuf,
|
||||
*/
|
||||
static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
|
||||
const struct in_addr *address = net_addr;
|
||||
struct ipv4_miniroute *miniroute;
|
||||
|
||||
list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
|
||||
if ( ( miniroute->netdev == netdev ) &&
|
||||
( miniroute->address.s_addr == address->s_addr ) ) {
|
||||
/* Found matching address */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if ( ipv4_has_addr ( netdev, *address ) )
|
||||
return 0;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -288,13 +288,15 @@ static int ipv6_process_nxt_hdr ( struct io_buffer *iobuf, uint8_t nxt_hdr,
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer source address
|
||||
* @v flags Packet flags
|
||||
*
|
||||
* This function processes a IPv6 packet
|
||||
*/
|
||||
static int ipv6_rx ( struct io_buffer *iobuf,
|
||||
__unused struct net_device *netdev,
|
||||
__unused const void *ll_dest,
|
||||
__unused const void *ll_source ) {
|
||||
__unused const void *ll_source,
|
||||
__unused unsigned int flags ) {
|
||||
|
||||
struct ip6_header *ip6hdr = iobuf->data;
|
||||
union {
|
||||
|
||||
+34
-15
@@ -194,16 +194,17 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete network transmission
|
||||
* Discard transmitted packet
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v iobuf I/O buffer
|
||||
* @v iobuf I/O buffer, or NULL
|
||||
* @v rc Packet status code
|
||||
*
|
||||
* The packet must currently be in the network device's TX queue.
|
||||
* The packet is discarded and a TX error is recorded. This function
|
||||
* takes ownership of the I/O buffer.
|
||||
*/
|
||||
void netdev_tx_complete_err ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf, int rc ) {
|
||||
void netdev_tx_err ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf, int rc ) {
|
||||
|
||||
/* Update statistics counter */
|
||||
netdev_record_stat ( &netdev->tx_stats, rc );
|
||||
@@ -215,12 +216,28 @@ void netdev_tx_complete_err ( struct net_device *netdev,
|
||||
netdev->name, iobuf, strerror ( rc ) );
|
||||
}
|
||||
|
||||
/* Discard packet */
|
||||
free_iob ( iobuf );
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete network transmission
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v iobuf I/O buffer
|
||||
* @v rc Packet status code
|
||||
*
|
||||
* The packet must currently be in the network device's TX queue.
|
||||
*/
|
||||
void netdev_tx_complete_err ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf, int rc ) {
|
||||
|
||||
/* Catch data corruption as early as possible */
|
||||
list_check_contains ( iobuf, &netdev->tx_queue, list );
|
||||
|
||||
/* Dequeue and free I/O buffer */
|
||||
list_del ( &iobuf->list );
|
||||
free_iob ( iobuf );
|
||||
netdev_tx_err ( netdev, iobuf, rc );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -644,7 +661,8 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
/* Add link-layer header */
|
||||
if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest, ll_source,
|
||||
net_protocol->net_proto ) ) != 0 ) {
|
||||
free_iob ( iobuf );
|
||||
/* Record error for diagnosis */
|
||||
netdev_tx_err ( netdev, iobuf, rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -660,17 +678,19 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
* @v net_proto Network-layer protocol, in network-byte order
|
||||
* @v ll_dest Destination link-layer address
|
||||
* @v ll_source Source link-layer address
|
||||
* @v flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
uint16_t net_proto, const void *ll_dest, const void *ll_source ) {
|
||||
uint16_t net_proto, const void *ll_dest, const void *ll_source,
|
||||
unsigned int flags ) {
|
||||
struct net_protocol *net_protocol;
|
||||
|
||||
/* Hand off to network-layer protocol, if any */
|
||||
for_each_table_entry ( net_protocol, NET_PROTOCOLS ) {
|
||||
if ( net_protocol->net_proto == net_proto )
|
||||
return net_protocol->rx ( iobuf, netdev, ll_dest,
|
||||
ll_source );
|
||||
ll_source, flags );
|
||||
}
|
||||
|
||||
DBGC ( netdev, "NETDEV %s unknown network protocol %04x\n",
|
||||
@@ -692,6 +712,7 @@ void net_poll ( void ) {
|
||||
const void *ll_dest;
|
||||
const void *ll_source;
|
||||
uint16_t net_proto;
|
||||
unsigned int flags;
|
||||
int rc;
|
||||
|
||||
/* Poll and process each network device */
|
||||
@@ -725,7 +746,8 @@ void net_poll ( void ) {
|
||||
ll_protocol = netdev->ll_protocol;
|
||||
if ( ( rc = ll_protocol->pull ( netdev, iobuf,
|
||||
&ll_dest, &ll_source,
|
||||
&net_proto ) ) != 0 ) {
|
||||
&net_proto,
|
||||
&flags ) ) != 0 ) {
|
||||
free_iob ( iobuf );
|
||||
continue;
|
||||
}
|
||||
@@ -733,7 +755,7 @@ void net_poll ( void ) {
|
||||
/* Hand packet to network layer */
|
||||
if ( ( rc = net_rx ( iob_disown ( iobuf ), netdev,
|
||||
net_proto, ll_dest,
|
||||
ll_source ) ) != 0 ) {
|
||||
ll_source, flags ) ) != 0 ) {
|
||||
/* Record error for diagnosis */
|
||||
netdev_rx_err ( netdev, NULL, rc );
|
||||
}
|
||||
@@ -751,7 +773,4 @@ static void net_step ( struct process *process __unused ) {
|
||||
}
|
||||
|
||||
/** Networking stack process */
|
||||
struct process net_process __permanent_process = {
|
||||
.list = LIST_HEAD_INIT ( net_process.list ),
|
||||
.step = net_step,
|
||||
};
|
||||
PERMANENT_PROCESS ( net_process, net_step );
|
||||
|
||||
+3
-1
@@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer source address
|
||||
* @v flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This is a dummy method which simply discards RARP packets.
|
||||
@@ -45,7 +46,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
static int rarp_rx ( struct io_buffer *iobuf,
|
||||
struct net_device *netdev __unused,
|
||||
const void *ll_dest __unused,
|
||||
const void *ll_source __unused ) {
|
||||
const void *ll_source __unused,
|
||||
unsigned int flags __unused ) {
|
||||
free_iob ( iobuf );
|
||||
return 0;
|
||||
}
|
||||
|
||||
+4
-5
@@ -148,6 +148,7 @@ void stop_timer ( struct retry_timer *timer ) {
|
||||
* @v timer Retry timer
|
||||
*/
|
||||
static void timer_expired ( struct retry_timer *timer ) {
|
||||
struct refcnt *refcnt = timer->refcnt;
|
||||
int fail;
|
||||
|
||||
/* Stop timer without performing RTT calculations */
|
||||
@@ -169,8 +170,9 @@ static void timer_expired ( struct retry_timer *timer ) {
|
||||
|
||||
/* Call expiry callback */
|
||||
timer->expired ( timer, fail );
|
||||
/* If refcnt is NULL, then timer may already have been freed */
|
||||
|
||||
ref_put ( timer->refcnt );
|
||||
ref_put ( refcnt );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +200,4 @@ static void retry_step ( struct process *process __unused ) {
|
||||
}
|
||||
|
||||
/** Retry timer process */
|
||||
struct process retry_process __permanent_process = {
|
||||
.list = LIST_HEAD_INIT ( retry_process.list ),
|
||||
.step = retry_step,
|
||||
};
|
||||
PERMANENT_PROCESS ( retry_process, retry_step );
|
||||
|
||||
+27
-19
@@ -391,6 +391,25 @@ static size_t tcp_xmit_win ( struct tcp_connection *tcp ) {
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check data-transfer flow control window
|
||||
*
|
||||
* @v tcp TCP connection
|
||||
* @ret len Length of window
|
||||
*/
|
||||
static size_t tcp_xfer_window ( struct tcp_connection *tcp ) {
|
||||
|
||||
/* Not ready if data queue is non-empty. This imposes a limit
|
||||
* of only one unACKed packet in the TX queue at any time; we
|
||||
* do this to conserve memory usage.
|
||||
*/
|
||||
if ( ! list_empty ( &tcp->tx_queue ) )
|
||||
return 0;
|
||||
|
||||
/* Return TCP window length */
|
||||
return tcp_xmit_win ( tcp );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process TCP transmit queue
|
||||
*
|
||||
@@ -1084,6 +1103,7 @@ static int tcp_rx ( struct io_buffer *iobuf,
|
||||
unsigned int flags;
|
||||
size_t len;
|
||||
uint32_t seq_len;
|
||||
size_t old_xfer_window;
|
||||
int rc;
|
||||
|
||||
/* Sanity check packet */
|
||||
@@ -1146,6 +1166,9 @@ static int tcp_rx ( struct io_buffer *iobuf,
|
||||
goto discard;
|
||||
}
|
||||
|
||||
/* Record old data-transfer window */
|
||||
old_xfer_window = tcp_xfer_window ( tcp );
|
||||
|
||||
/* Handle ACK, if present */
|
||||
if ( flags & TCP_ACK ) {
|
||||
if ( ( rc = tcp_rx_ack ( tcp, ack, win ) ) != 0 ) {
|
||||
@@ -1192,6 +1215,10 @@ static int tcp_rx ( struct io_buffer *iobuf,
|
||||
start_timer_fixed ( &tcp->wait, ( 2 * TCP_MSL ) );
|
||||
}
|
||||
|
||||
/* Notify application if window has changed */
|
||||
if ( tcp_xfer_window ( tcp ) != old_xfer_window )
|
||||
xfer_window_changed ( &tcp->xfer );
|
||||
|
||||
return 0;
|
||||
|
||||
discard:
|
||||
@@ -1257,25 +1284,6 @@ static void tcp_xfer_close ( struct tcp_connection *tcp, int rc ) {
|
||||
tcp_xmit ( tcp );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check flow control window
|
||||
*
|
||||
* @v tcp TCP connection
|
||||
* @ret len Length of window
|
||||
*/
|
||||
static size_t tcp_xfer_window ( struct tcp_connection *tcp ) {
|
||||
|
||||
/* Not ready if data queue is non-empty. This imposes a limit
|
||||
* of only one unACKed packet in the TX queue at any time; we
|
||||
* do this to conserve memory usage.
|
||||
*/
|
||||
if ( ! list_empty ( &tcp->tx_queue ) )
|
||||
return 0;
|
||||
|
||||
/* Return TCP window length */
|
||||
return tcp_xmit_win ( tcp );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deliver datagram as I/O buffer
|
||||
*
|
||||
|
||||
+4
-25
@@ -378,37 +378,15 @@ static void ftp_data_closed ( struct ftp_request *ftp, int rc ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle data delivery via FTP data channel
|
||||
*
|
||||
* @v ftp FTP request
|
||||
* @v iobuf I/O buffer
|
||||
* @v meta Data transfer metadata
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ftp_data_deliver ( struct ftp_request *ftp,
|
||||
struct io_buffer *iobuf,
|
||||
struct xfer_metadata *meta __unused ) {
|
||||
int rc;
|
||||
|
||||
if ( ( rc = xfer_deliver_iob ( &ftp->xfer, iobuf ) ) != 0 ) {
|
||||
DBGC ( ftp, "FTP %p failed to deliver data: %s\n",
|
||||
ftp, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** FTP data channel interface operations */
|
||||
static struct interface_operation ftp_data_operations[] = {
|
||||
INTF_OP ( xfer_deliver, struct ftp_request *, ftp_data_deliver ),
|
||||
INTF_OP ( intf_close, struct ftp_request *, ftp_data_closed ),
|
||||
};
|
||||
|
||||
/** FTP data channel interface descriptor */
|
||||
static struct interface_descriptor ftp_data_desc =
|
||||
INTF_DESC ( struct ftp_request, data, ftp_data_operations );
|
||||
INTF_DESC_PASSTHRU ( struct ftp_request, data, ftp_data_operations,
|
||||
xfer );
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
@@ -423,7 +401,8 @@ static struct interface_operation ftp_xfer_operations[] = {
|
||||
|
||||
/** FTP data transfer interface descriptor */
|
||||
static struct interface_descriptor ftp_xfer_desc =
|
||||
INTF_DESC ( struct ftp_request, xfer, ftp_xfer_operations );
|
||||
INTF_DESC_PASSTHRU ( struct ftp_request, xfer, ftp_xfer_operations,
|
||||
data );
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
|
||||
+351
-82
@@ -44,10 +44,25 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <ipxe/linebuf.h>
|
||||
#include <ipxe/features.h>
|
||||
#include <ipxe/base64.h>
|
||||
#include <ipxe/blockdev.h>
|
||||
#include <ipxe/acpi.h>
|
||||
#include <ipxe/http.h>
|
||||
|
||||
FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 );
|
||||
|
||||
/** Block size used for HTTP block device request */
|
||||
#define HTTP_BLKSIZE 512
|
||||
|
||||
/** HTTP flags */
|
||||
enum http_flags {
|
||||
/** Request is waiting to be transmitted */
|
||||
HTTP_TX_PENDING = 0x0001,
|
||||
/** Fetch header only */
|
||||
HTTP_HEAD_ONLY = 0x0002,
|
||||
/** Keep connection alive */
|
||||
HTTP_KEEPALIVE = 0x0004,
|
||||
};
|
||||
|
||||
/** HTTP receive state */
|
||||
enum http_rx_state {
|
||||
HTTP_RX_RESPONSE = 0,
|
||||
@@ -55,6 +70,7 @@ enum http_rx_state {
|
||||
HTTP_RX_CHUNK_LEN,
|
||||
HTTP_RX_DATA,
|
||||
HTTP_RX_TRAILER,
|
||||
HTTP_RX_IDLE,
|
||||
HTTP_RX_DEAD,
|
||||
};
|
||||
|
||||
@@ -67,29 +83,38 @@ struct http_request {
|
||||
struct refcnt refcnt;
|
||||
/** Data transfer interface */
|
||||
struct interface xfer;
|
||||
/** Partial transfer interface */
|
||||
struct interface partial;
|
||||
|
||||
/** URI being fetched */
|
||||
struct uri *uri;
|
||||
/** Transport layer interface */
|
||||
struct interface socket;
|
||||
|
||||
/** Flags */
|
||||
unsigned int flags;
|
||||
/** Starting offset of partial transfer (if applicable) */
|
||||
size_t partial_start;
|
||||
/** Length of partial transfer (if applicable) */
|
||||
size_t partial_len;
|
||||
|
||||
/** TX process */
|
||||
struct process process;
|
||||
|
||||
/** HTTP response code */
|
||||
unsigned int response;
|
||||
/** HTTP Content-Length */
|
||||
size_t content_length;
|
||||
/** HTTP is using Transfer-Encoding: chunked */
|
||||
int chunked;
|
||||
/** Current chunk length */
|
||||
size_t chunk_len;
|
||||
/** Received length */
|
||||
size_t rx_len;
|
||||
/** RX state */
|
||||
enum http_rx_state rx_state;
|
||||
/** Received length */
|
||||
size_t rx_len;
|
||||
/** Length remaining (or 0 if unknown) */
|
||||
size_t remaining;
|
||||
/** HTTP is using Transfer-Encoding: chunked */
|
||||
int chunked;
|
||||
/** Current chunk length remaining (if applicable) */
|
||||
size_t chunk_remaining;
|
||||
/** Line buffer for received header lines */
|
||||
struct line_buffer linebuf;
|
||||
/** Receive data buffer (if applicable) */
|
||||
userptr_t rx_buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -107,12 +132,12 @@ static void http_free ( struct refcnt *refcnt ) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark HTTP request as complete
|
||||
* Close HTTP request
|
||||
*
|
||||
* @v http HTTP request
|
||||
* @v rc Return status code
|
||||
*/
|
||||
static void http_done ( struct http_request *http, int rc ) {
|
||||
static void http_close ( struct http_request *http, int rc ) {
|
||||
|
||||
/* Prevent further processing of any current packet */
|
||||
http->rx_state = HTTP_RX_DEAD;
|
||||
@@ -120,11 +145,11 @@ static void http_done ( struct http_request *http, int rc ) {
|
||||
/* If we had a Content-Length, and the received content length
|
||||
* isn't correct, flag an error
|
||||
*/
|
||||
if ( http->content_length &&
|
||||
( http->content_length != http->rx_len ) ) {
|
||||
if ( http->remaining != 0 ) {
|
||||
DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
|
||||
http, http->rx_len, http->content_length );
|
||||
rc = -EIO;
|
||||
http, http->rx_len, ( http->rx_len + http->remaining ) );
|
||||
if ( rc == 0 )
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
/* Remove process */
|
||||
@@ -132,9 +157,40 @@ static void http_done ( struct http_request *http, int rc ) {
|
||||
|
||||
/* Close all data transfer interfaces */
|
||||
intf_shutdown ( &http->socket, rc );
|
||||
intf_shutdown ( &http->partial, rc );
|
||||
intf_shutdown ( &http->xfer, rc );
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark HTTP request as completed successfully
|
||||
*
|
||||
* @v http HTTP request
|
||||
*/
|
||||
static void http_done ( struct http_request *http ) {
|
||||
|
||||
/* If we had a Content-Length, and the received content length
|
||||
* isn't correct, force an error
|
||||
*/
|
||||
if ( http->remaining != 0 ) {
|
||||
http_close ( http, -EIO );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enter idle state */
|
||||
http->rx_state = HTTP_RX_IDLE;
|
||||
http->rx_len = 0;
|
||||
assert ( http->remaining == 0 );
|
||||
assert ( http->chunked == 0 );
|
||||
assert ( http->chunk_remaining == 0 );
|
||||
|
||||
/* Close partial transfer interface */
|
||||
intf_restart ( &http->partial, 0 );
|
||||
|
||||
/* Close everything unless we are keeping the connection alive */
|
||||
if ( ! ( http->flags & HTTP_KEEPALIVE ) )
|
||||
http_close ( http, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTTP response code to return status code
|
||||
*
|
||||
@@ -144,6 +200,7 @@ static void http_done ( struct http_request *http, int rc ) {
|
||||
static int http_response_to_rc ( unsigned int response ) {
|
||||
switch ( response ) {
|
||||
case 200:
|
||||
case 206:
|
||||
case 301:
|
||||
case 302:
|
||||
return 0;
|
||||
@@ -167,6 +224,7 @@ static int http_response_to_rc ( unsigned int response ) {
|
||||
*/
|
||||
static int http_rx_response ( struct http_request *http, char *response ) {
|
||||
char *spc;
|
||||
unsigned int code;
|
||||
int rc;
|
||||
|
||||
DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
|
||||
@@ -179,8 +237,8 @@ static int http_rx_response ( struct http_request *http, char *response ) {
|
||||
spc = strchr ( response, ' ' );
|
||||
if ( ! spc )
|
||||
return -EIO;
|
||||
http->response = strtoul ( spc, NULL, 10 );
|
||||
if ( ( rc = http_response_to_rc ( http->response ) ) != 0 )
|
||||
code = strtoul ( spc, NULL, 10 );
|
||||
if ( ( rc = http_response_to_rc ( code ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Move to received headers */
|
||||
@@ -219,19 +277,40 @@ static int http_rx_location ( struct http_request *http, const char *value ) {
|
||||
*/
|
||||
static int http_rx_content_length ( struct http_request *http,
|
||||
const char *value ) {
|
||||
struct block_device_capacity capacity;
|
||||
size_t content_len;
|
||||
char *endp;
|
||||
|
||||
http->content_length = strtoul ( value, &endp, 10 );
|
||||
/* Parse content length */
|
||||
content_len = strtoul ( value, &endp, 10 );
|
||||
if ( *endp != '\0' ) {
|
||||
DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
|
||||
http, value );
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* If we already have an expected content length, and this
|
||||
* isn't it, then complain
|
||||
*/
|
||||
if ( http->remaining && ( http->remaining != content_len ) ) {
|
||||
DBGC ( http, "HTTP %p incorrect Content-Length %zd (expected "
|
||||
"%zd)\n", http, content_len, http->remaining );
|
||||
return -EIO;
|
||||
}
|
||||
if ( ! ( http->flags & HTTP_HEAD_ONLY ) )
|
||||
http->remaining = content_len;
|
||||
|
||||
/* Use seek() to notify recipient of filesize */
|
||||
xfer_seek ( &http->xfer, http->content_length );
|
||||
xfer_seek ( &http->xfer, http->remaining );
|
||||
xfer_seek ( &http->xfer, 0 );
|
||||
|
||||
/* Report block device capacity if applicable */
|
||||
if ( http->flags & HTTP_HEAD_ONLY ) {
|
||||
capacity.blocks = ( content_len / HTTP_BLKSIZE );
|
||||
capacity.blksize = HTTP_BLKSIZE;
|
||||
capacity.max_count = -1U;
|
||||
block_capacity ( &http->partial, &capacity );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -301,14 +380,15 @@ static int http_rx_header ( struct http_request *http, char *header ) {
|
||||
/* An empty header line marks the end of this phase */
|
||||
if ( ! header[0] ) {
|
||||
empty_line_buffer ( &http->linebuf );
|
||||
if ( http->rx_state == HTTP_RX_HEADER ) {
|
||||
if ( ( http->rx_state == HTTP_RX_HEADER ) &&
|
||||
( ! ( http->flags & HTTP_HEAD_ONLY ) ) ) {
|
||||
DBGC ( http, "HTTP %p start of data\n", http );
|
||||
http->rx_state = ( http->chunked ?
|
||||
HTTP_RX_CHUNK_LEN : HTTP_RX_DATA );
|
||||
return 0;
|
||||
} else {
|
||||
DBGC ( http, "HTTP %p end of trailer\n", http );
|
||||
http_done ( http, 0 );
|
||||
http_done ( http );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -350,7 +430,7 @@ static int http_rx_chunk_len ( struct http_request *http, char *length ) {
|
||||
return 0;
|
||||
|
||||
/* Parse chunk length */
|
||||
http->chunk_len = strtoul ( length, &endp, 16 );
|
||||
http->chunk_remaining = strtoul ( length, &endp, 16 );
|
||||
if ( *endp != '\0' ) {
|
||||
DBGC ( http, "HTTP %p invalid chunk length \"%s\"\n",
|
||||
http, length );
|
||||
@@ -358,7 +438,7 @@ static int http_rx_chunk_len ( struct http_request *http, char *length ) {
|
||||
}
|
||||
|
||||
/* Terminate chunked encoding if applicable */
|
||||
if ( http->chunk_len == 0 ) {
|
||||
if ( http->chunk_remaining == 0 ) {
|
||||
DBGC ( http, "HTTP %p end of chunks\n", http );
|
||||
http->chunked = 0;
|
||||
http->rx_state = HTTP_RX_TRAILER;
|
||||
@@ -367,8 +447,8 @@ static int http_rx_chunk_len ( struct http_request *http, char *length ) {
|
||||
|
||||
/* Use seek() to notify recipient of new filesize */
|
||||
DBGC ( http, "HTTP %p start of chunk of length %zd\n",
|
||||
http, http->chunk_len );
|
||||
xfer_seek ( &http->xfer, ( http->rx_len + http->chunk_len ) );
|
||||
http, http->chunk_remaining );
|
||||
xfer_seek ( &http->xfer, ( http->rx_len + http->chunk_remaining ) );
|
||||
xfer_seek ( &http->xfer, http->rx_len );
|
||||
|
||||
/* Start receiving data */
|
||||
@@ -414,34 +494,60 @@ static int http_socket_deliver ( struct http_request *http,
|
||||
int rc = 0;
|
||||
|
||||
while ( iobuf && iob_len ( iobuf ) ) {
|
||||
|
||||
switch ( http->rx_state ) {
|
||||
case HTTP_RX_IDLE:
|
||||
/* Receiving any data in this state is an error */
|
||||
DBGC ( http, "HTTP %p received %zd bytes while %s\n",
|
||||
http, iob_len ( iobuf ),
|
||||
( ( http->rx_state == HTTP_RX_IDLE ) ?
|
||||
"idle" : "dead" ) );
|
||||
rc = -EPROTO;
|
||||
goto done;
|
||||
case HTTP_RX_DEAD:
|
||||
/* Do no further processing */
|
||||
goto done;
|
||||
case HTTP_RX_DATA:
|
||||
/* Pass received data to caller */
|
||||
data_len = iob_len ( iobuf );
|
||||
if ( http->chunk_len && ( http->chunk_len < data_len )){
|
||||
data_len = http->chunk_len;
|
||||
if ( http->chunk_remaining &&
|
||||
( http->chunk_remaining < data_len ) ) {
|
||||
data_len = http->chunk_remaining;
|
||||
}
|
||||
if ( http->remaining &&
|
||||
( http->remaining < data_len ) ) {
|
||||
data_len = http->remaining;
|
||||
}
|
||||
if ( http->rx_buffer != UNULL ) {
|
||||
/* Copy to partial transfer buffer */
|
||||
copy_to_user ( http->rx_buffer, http->rx_len,
|
||||
iobuf->data, data_len );
|
||||
iob_pull ( iobuf, data_len );
|
||||
} else if ( data_len < iob_len ( iobuf ) ) {
|
||||
/* Deliver partial buffer as raw data */
|
||||
rc = xfer_deliver_raw ( &http->xfer,
|
||||
iobuf->data, data_len );
|
||||
iob_pull ( iobuf, data_len );
|
||||
if ( rc != 0 )
|
||||
goto done;
|
||||
} else {
|
||||
rc = xfer_deliver_iob ( &http->xfer,
|
||||
iob_disown ( iobuf ) );
|
||||
}
|
||||
if ( rc != 0 )
|
||||
goto done;
|
||||
if ( http->chunk_len ) {
|
||||
http->chunk_len -= data_len;
|
||||
if ( http->chunk_len == 0 )
|
||||
http->rx_state = HTTP_RX_CHUNK_LEN;
|
||||
/* Deliver whole I/O buffer */
|
||||
if ( ( rc = xfer_deliver_iob ( &http->xfer,
|
||||
iob_disown ( iobuf ) ) ) != 0 )
|
||||
goto done;
|
||||
}
|
||||
http->rx_len += data_len;
|
||||
if ( http->content_length &&
|
||||
( http->rx_len >= http->content_length ) ) {
|
||||
http_done ( http, 0 );
|
||||
goto done;
|
||||
if ( http->chunk_remaining ) {
|
||||
http->chunk_remaining -= data_len;
|
||||
if ( http->chunk_remaining == 0 )
|
||||
http->rx_state = HTTP_RX_CHUNK_LEN;
|
||||
}
|
||||
if ( http->remaining ) {
|
||||
http->remaining -= data_len;
|
||||
if ( ( http->remaining == 0 ) &&
|
||||
( http->rx_state == HTTP_RX_DATA ) ) {
|
||||
http_done ( http );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HTTP_RX_RESPONSE:
|
||||
@@ -475,19 +581,31 @@ static int http_socket_deliver ( struct http_request *http,
|
||||
|
||||
done:
|
||||
if ( rc )
|
||||
http_done ( http, rc );
|
||||
http_close ( http, rc );
|
||||
free_iob ( iobuf );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check HTTP socket flow control window
|
||||
*
|
||||
* @v http HTTP request
|
||||
* @ret len Length of window
|
||||
*/
|
||||
static size_t http_socket_window ( struct http_request *http __unused ) {
|
||||
|
||||
/* Window is always open. This is to prevent TCP from
|
||||
* stalling if our parent window is not currently open.
|
||||
*/
|
||||
return ( ~( ( size_t ) 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP process
|
||||
*
|
||||
* @v process Process
|
||||
* @v http HTTP request
|
||||
*/
|
||||
static void http_step ( struct process *process ) {
|
||||
struct http_request *http =
|
||||
container_of ( process, struct http_request, process );
|
||||
static void http_step ( struct http_request *http ) {
|
||||
const char *host = http->uri->host;
|
||||
const char *user = http->uri->user;
|
||||
const char *password =
|
||||
@@ -500,50 +618,181 @@ static void http_step ( struct process *process ) {
|
||||
int rc;
|
||||
int request_len = unparse_uri ( NULL, 0, http->uri,
|
||||
URI_PATH_BIT | URI_QUERY_BIT );
|
||||
char request[ request_len + 1 /* NUL */ ];
|
||||
char range[48]; /* Enough for two 64-bit integers in decimal */
|
||||
int partial;
|
||||
|
||||
if ( xfer_window ( &http->socket ) ) {
|
||||
char request[request_len + 1];
|
||||
/* Do nothing if we have already transmitted the request */
|
||||
if ( ! ( http->flags & HTTP_TX_PENDING ) )
|
||||
return;
|
||||
|
||||
/* Construct path?query request */
|
||||
unparse_uri ( request, sizeof ( request ), http->uri,
|
||||
URI_PATH_BIT | URI_QUERY_BIT );
|
||||
/* Do nothing until socket is ready */
|
||||
if ( ! xfer_window ( &http->socket ) )
|
||||
return;
|
||||
|
||||
/* We want to execute only once */
|
||||
process_del ( &http->process );
|
||||
/* Construct path?query request */
|
||||
unparse_uri ( request, sizeof ( request ), http->uri,
|
||||
URI_PATH_BIT | URI_QUERY_BIT );
|
||||
|
||||
/* Construct authorisation, if applicable */
|
||||
if ( user ) {
|
||||
/* Make "user:password" string from decoded fields */
|
||||
snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ),
|
||||
"%s:%s", user, password );
|
||||
/* Construct authorisation, if applicable */
|
||||
if ( user ) {
|
||||
/* Make "user:password" string from decoded fields */
|
||||
snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ),
|
||||
"%s:%s", user, password );
|
||||
|
||||
/* Base64-encode the "user:password" string */
|
||||
base64_encode ( user_pw, user_pw_len, user_pw_base64 );
|
||||
}
|
||||
|
||||
/* Send GET request */
|
||||
if ( ( rc = xfer_printf ( &http->socket,
|
||||
"GET %s%s HTTP/1.1\r\n"
|
||||
"User-Agent: iPXE/" VERSION "\r\n"
|
||||
"%s%s%s"
|
||||
"Host: %s\r\n"
|
||||
"\r\n",
|
||||
http->uri->path ? "" : "/",
|
||||
request,
|
||||
( user ?
|
||||
"Authorization: Basic " : "" ),
|
||||
( user ? user_pw_base64 : "" ),
|
||||
( user ? "\r\n" : "" ),
|
||||
host ) ) != 0 ) {
|
||||
http_done ( http, rc );
|
||||
}
|
||||
/* Base64-encode the "user:password" string */
|
||||
base64_encode ( user_pw, user_pw_len, user_pw_base64 );
|
||||
}
|
||||
|
||||
/* Force a HEAD request if we have nowhere to send any received data */
|
||||
if ( ( xfer_window ( &http->xfer ) == 0 ) &&
|
||||
( http->rx_buffer == UNULL ) ) {
|
||||
http->flags |= ( HTTP_HEAD_ONLY | HTTP_KEEPALIVE );
|
||||
}
|
||||
|
||||
/* Determine type of request */
|
||||
partial = ( http->partial_len != 0 );
|
||||
snprintf ( range, sizeof ( range ), "%zd-%zd", http->partial_start,
|
||||
( http->partial_start + http->partial_len - 1 ) );
|
||||
|
||||
/* Mark request as transmitted */
|
||||
http->flags &= ~HTTP_TX_PENDING;
|
||||
|
||||
/* Send GET request */
|
||||
if ( ( rc = xfer_printf ( &http->socket,
|
||||
"%s %s%s HTTP/1.1\r\n"
|
||||
"User-Agent: iPXE/" VERSION "\r\n"
|
||||
"Host: %s%s%s\r\n"
|
||||
"%s%s%s%s%s%s%s"
|
||||
"\r\n",
|
||||
( ( http->flags & HTTP_HEAD_ONLY ) ?
|
||||
"HEAD" : "GET" ),
|
||||
( http->uri->path ? "" : "/" ),
|
||||
request, host,
|
||||
( http->uri->port ?
|
||||
":" : "" ),
|
||||
( http->uri->port ?
|
||||
http->uri->port : "" ),
|
||||
( ( http->flags & HTTP_KEEPALIVE ) ?
|
||||
"Connection: Keep-Alive\r\n" : "" ),
|
||||
( partial ? "Range: bytes=" : "" ),
|
||||
( partial ? range : "" ),
|
||||
( partial ? "\r\n" : "" ),
|
||||
( user ?
|
||||
"Authorization: Basic " : "" ),
|
||||
( user ? user_pw_base64 : "" ),
|
||||
( user ? "\r\n" : "" ) ) ) != 0 ) {
|
||||
http_close ( http, rc );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check HTTP data transfer flow control window
|
||||
*
|
||||
* @v http HTTP request
|
||||
* @ret len Length of window
|
||||
*/
|
||||
static size_t http_xfer_window ( struct http_request *http ) {
|
||||
|
||||
/* New block commands may be issued only when we are idle */
|
||||
return ( ( http->rx_state == HTTP_RX_IDLE ) ? 1 : 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate HTTP partial read
|
||||
*
|
||||
* @v http HTTP request
|
||||
* @v partial Partial transfer interface
|
||||
* @v offset Starting offset
|
||||
* @v buffer Data buffer
|
||||
* @v len Length
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int http_partial_read ( struct http_request *http,
|
||||
struct interface *partial,
|
||||
size_t offset, userptr_t buffer, size_t len ) {
|
||||
|
||||
/* Sanity check */
|
||||
if ( http_xfer_window ( http ) == 0 )
|
||||
return -EBUSY;
|
||||
|
||||
/* Initialise partial transfer parameters */
|
||||
http->rx_buffer = buffer;
|
||||
http->partial_start = offset;
|
||||
http->partial_len = len;
|
||||
http->remaining = len;
|
||||
|
||||
/* Schedule request */
|
||||
http->rx_state = HTTP_RX_RESPONSE;
|
||||
http->flags = ( HTTP_TX_PENDING | HTTP_KEEPALIVE );
|
||||
if ( ! len )
|
||||
http->flags |= HTTP_HEAD_ONLY;
|
||||
process_add ( &http->process );
|
||||
|
||||
/* Attach to parent interface and return */
|
||||
intf_plug_plug ( &http->partial, partial );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue HTTP block device read
|
||||
*
|
||||
* @v http HTTP request
|
||||
* @v block Block data interface
|
||||
* @v lba Starting logical block address
|
||||
* @v count Number of blocks to transfer
|
||||
* @v buffer Data buffer
|
||||
* @v len Length of data buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int http_block_read ( struct http_request *http,
|
||||
struct interface *block,
|
||||
uint64_t lba, unsigned int count,
|
||||
userptr_t buffer, size_t len __unused ) {
|
||||
|
||||
return http_partial_read ( http, block, ( lba * HTTP_BLKSIZE ),
|
||||
buffer, ( count * HTTP_BLKSIZE ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read HTTP block device capacity
|
||||
*
|
||||
* @v http HTTP request
|
||||
* @v block Block data interface
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int http_block_read_capacity ( struct http_request *http,
|
||||
struct interface *block ) {
|
||||
|
||||
return http_partial_read ( http, block, 0, 0, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe HTTP device in an ACPI table
|
||||
*
|
||||
* @v http HTTP request
|
||||
* @v acpi ACPI table
|
||||
* @v len Length of ACPI table
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int http_acpi_describe ( struct http_request *http,
|
||||
struct acpi_description_header *acpi,
|
||||
size_t len ) {
|
||||
|
||||
DBGC ( http, "HTTP %p cannot yet describe device in an ACPI table\n",
|
||||
http );
|
||||
( void ) acpi;
|
||||
( void ) len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** HTTP socket interface operations */
|
||||
static struct interface_operation http_socket_operations[] = {
|
||||
INTF_OP ( xfer_window, struct http_request *, http_socket_window ),
|
||||
INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ),
|
||||
INTF_OP ( intf_close, struct http_request *, http_done ),
|
||||
INTF_OP ( xfer_window_changed, struct http_request *, http_step ),
|
||||
INTF_OP ( intf_close, struct http_request *, http_close ),
|
||||
};
|
||||
|
||||
/** HTTP socket interface descriptor */
|
||||
@@ -551,9 +800,23 @@ static struct interface_descriptor http_socket_desc =
|
||||
INTF_DESC_PASSTHRU ( struct http_request, socket,
|
||||
http_socket_operations, xfer );
|
||||
|
||||
/** HTTP partial transfer interface operations */
|
||||
static struct interface_operation http_partial_operations[] = {
|
||||
INTF_OP ( intf_close, struct http_request *, http_close ),
|
||||
};
|
||||
|
||||
/** HTTP partial transfer interface descriptor */
|
||||
static struct interface_descriptor http_partial_desc =
|
||||
INTF_DESC ( struct http_request, partial, http_partial_operations );
|
||||
|
||||
/** HTTP data transfer interface operations */
|
||||
static struct interface_operation http_xfer_operations[] = {
|
||||
INTF_OP ( intf_close, struct http_request *, http_done ),
|
||||
INTF_OP ( xfer_window, struct http_request *, http_xfer_window ),
|
||||
INTF_OP ( block_read, struct http_request *, http_block_read ),
|
||||
INTF_OP ( block_read_capacity, struct http_request *,
|
||||
http_block_read_capacity ),
|
||||
INTF_OP ( intf_close, struct http_request *, http_close ),
|
||||
INTF_OP ( acpi_describe, struct http_request *, http_acpi_describe ),
|
||||
};
|
||||
|
||||
/** HTTP data transfer interface descriptor */
|
||||
@@ -561,6 +824,10 @@ static struct interface_descriptor http_xfer_desc =
|
||||
INTF_DESC_PASSTHRU ( struct http_request, xfer,
|
||||
http_xfer_operations, socket );
|
||||
|
||||
/** HTTP process descriptor */
|
||||
static struct process_descriptor http_process_desc =
|
||||
PROC_DESC_ONCE ( struct http_request, process, http_step );
|
||||
|
||||
/**
|
||||
* Initiate an HTTP connection, with optional filter
|
||||
*
|
||||
@@ -589,9 +856,11 @@ int http_open_filter ( struct interface *xfer, struct uri *uri,
|
||||
return -ENOMEM;
|
||||
ref_init ( &http->refcnt, http_free );
|
||||
intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt );
|
||||
intf_init ( &http->partial, &http_partial_desc, &http->refcnt );
|
||||
http->uri = uri_get ( uri );
|
||||
intf_init ( &http->socket, &http_socket_desc, &http->refcnt );
|
||||
process_init ( &http->process, http_step, &http->refcnt );
|
||||
process_init ( &http->process, &http_process_desc, &http->refcnt );
|
||||
http->flags = HTTP_TX_PENDING;
|
||||
|
||||
/* Open socket */
|
||||
memset ( &server, 0, sizeof ( server ) );
|
||||
@@ -614,7 +883,7 @@ int http_open_filter ( struct interface *xfer, struct uri *uri,
|
||||
err:
|
||||
DBGC ( http, "HTTP %p could not create request: %s\n",
|
||||
http, strerror ( rc ) );
|
||||
http_done ( http, rc );
|
||||
http_close ( http, rc );
|
||||
ref_put ( &http->refcnt );
|
||||
return rc;
|
||||
}
|
||||
|
||||
+41
-11
@@ -1304,6 +1304,24 @@ static int iscsi_rx_login_response ( struct iscsi_session *iscsi,
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pause TX engine
|
||||
*
|
||||
* @v iscsi iSCSI session
|
||||
*/
|
||||
static void iscsi_tx_pause ( struct iscsi_session *iscsi ) {
|
||||
process_del ( &iscsi->process );
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume TX engine
|
||||
*
|
||||
* @v iscsi iSCSI session
|
||||
*/
|
||||
static void iscsi_tx_resume ( struct iscsi_session *iscsi ) {
|
||||
process_add ( &iscsi->process );
|
||||
}
|
||||
|
||||
/**
|
||||
* Start up a new TX PDU
|
||||
*
|
||||
@@ -1315,8 +1333,7 @@ static int iscsi_rx_login_response ( struct iscsi_session *iscsi,
|
||||
static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
|
||||
|
||||
assert ( iscsi->tx_state == ISCSI_TX_IDLE );
|
||||
assert ( ! process_running ( &iscsi->process ) );
|
||||
|
||||
|
||||
/* Initialise TX BHS */
|
||||
memset ( &iscsi->tx_bhs, 0, sizeof ( iscsi->tx_bhs ) );
|
||||
|
||||
@@ -1324,7 +1341,7 @@ static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
|
||||
iscsi->tx_state = ISCSI_TX_BHS;
|
||||
|
||||
/* Start transmission process */
|
||||
process_add ( &iscsi->process );
|
||||
iscsi_tx_resume ( iscsi );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1405,7 +1422,7 @@ static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
|
||||
struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
|
||||
|
||||
/* Stop transmission process */
|
||||
process_del ( &iscsi->process );
|
||||
iscsi_tx_pause ( iscsi );
|
||||
|
||||
switch ( common->opcode & ISCSI_OPCODE_MASK ) {
|
||||
case ISCSI_OPCODE_DATA_OUT:
|
||||
@@ -1427,9 +1444,7 @@ static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
|
||||
*
|
||||
* Constructs data to be sent for the current TX state
|
||||
*/
|
||||
static void iscsi_tx_step ( struct process *process ) {
|
||||
struct iscsi_session *iscsi =
|
||||
container_of ( process, struct iscsi_session, process );
|
||||
static void iscsi_tx_step ( struct iscsi_session *iscsi ) {
|
||||
struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
|
||||
int ( * tx ) ( struct iscsi_session *iscsi );
|
||||
enum iscsi_tx_state next_state;
|
||||
@@ -1460,8 +1475,8 @@ static void iscsi_tx_step ( struct process *process ) {
|
||||
next_state = ISCSI_TX_IDLE;
|
||||
break;
|
||||
case ISCSI_TX_IDLE:
|
||||
/* Stop processing */
|
||||
iscsi_tx_done ( iscsi );
|
||||
/* Nothing to do; pause processing */
|
||||
iscsi_tx_pause ( iscsi );
|
||||
return;
|
||||
default:
|
||||
assert ( 0 );
|
||||
@@ -1470,7 +1485,10 @@ static void iscsi_tx_step ( struct process *process ) {
|
||||
|
||||
/* Check for window availability, if needed */
|
||||
if ( tx_len && ( xfer_window ( &iscsi->socket ) == 0 ) ) {
|
||||
/* Cannot transmit at this point; stop processing */
|
||||
/* Cannot transmit at this point; pause
|
||||
* processing and wait for window to reopen
|
||||
*/
|
||||
iscsi_tx_pause ( iscsi );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1485,9 +1503,19 @@ static void iscsi_tx_step ( struct process *process ) {
|
||||
|
||||
/* Move to next state */
|
||||
iscsi->tx_state = next_state;
|
||||
|
||||
/* If we have moved to the idle state, mark
|
||||
* transmission as complete
|
||||
*/
|
||||
if ( iscsi->tx_state == ISCSI_TX_IDLE )
|
||||
iscsi_tx_done ( iscsi );
|
||||
}
|
||||
}
|
||||
|
||||
/** iSCSI TX process descriptor */
|
||||
static struct process_descriptor iscsi_process_desc =
|
||||
PROC_DESC ( struct iscsi_session, process, iscsi_tx_step );
|
||||
|
||||
/**
|
||||
* Receive basic header segment of an iSCSI PDU
|
||||
*
|
||||
@@ -1694,6 +1722,8 @@ static int iscsi_vredirect ( struct iscsi_session *iscsi, int type,
|
||||
/** iSCSI socket interface operations */
|
||||
static struct interface_operation iscsi_socket_operations[] = {
|
||||
INTF_OP ( xfer_deliver, struct iscsi_session *, iscsi_socket_deliver ),
|
||||
INTF_OP ( xfer_window_changed, struct iscsi_session *,
|
||||
iscsi_tx_resume ),
|
||||
INTF_OP ( xfer_vredirect, struct iscsi_session *, iscsi_vredirect ),
|
||||
INTF_OP ( intf_close, struct iscsi_session *, iscsi_close ),
|
||||
};
|
||||
@@ -2034,7 +2064,7 @@ static int iscsi_open ( struct interface *parent, struct uri *uri ) {
|
||||
intf_init ( &iscsi->control, &iscsi_control_desc, &iscsi->refcnt );
|
||||
intf_init ( &iscsi->data, &iscsi_data_desc, &iscsi->refcnt );
|
||||
intf_init ( &iscsi->socket, &iscsi_socket_desc, &iscsi->refcnt );
|
||||
process_init_stopped ( &iscsi->process, iscsi_tx_step,
|
||||
process_init_stopped ( &iscsi->process, &iscsi_process_desc,
|
||||
&iscsi->refcnt );
|
||||
|
||||
/* Parse root path */
|
||||
|
||||
+72
-12
@@ -580,6 +580,62 @@ static void tls_verify_handshake ( struct tls_session *tls, void *out ) {
|
||||
digest_final ( sha1, sha1_ctx, sha1_digest );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* TX state machine transitions
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resume TX state machine
|
||||
*
|
||||
* @v tls TLS session
|
||||
*/
|
||||
static void tls_tx_resume ( struct tls_session *tls ) {
|
||||
process_add ( &tls->process );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter TX state machine active state
|
||||
*
|
||||
* @v tls TLS session
|
||||
* @v state TX state
|
||||
*/
|
||||
static void tls_tx_start ( struct tls_session *tls, enum tls_tx_state state ) {
|
||||
|
||||
/* Enter specified state */
|
||||
tls->tx_state = state;
|
||||
|
||||
/* Resume state machine */
|
||||
tls_tx_resume ( tls );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter TX state machine idle state
|
||||
*
|
||||
* @v tls TLS session
|
||||
*/
|
||||
static void tls_tx_none ( struct tls_session *tls ) {
|
||||
|
||||
/* Enter idle state */
|
||||
tls->tx_state = TLS_TX_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter TX state machine data state
|
||||
*
|
||||
* @v tls TLS session
|
||||
*/
|
||||
static void tls_tx_data ( struct tls_session *tls ) {
|
||||
|
||||
/* Enter data state */
|
||||
tls->tx_state = TLS_TX_DATA;
|
||||
|
||||
/* Send notification of a window change */
|
||||
xfer_window_changed ( &tls->plainstream );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Record handling
|
||||
@@ -929,7 +985,7 @@ static int tls_new_server_hello_done ( struct tls_session *tls,
|
||||
}
|
||||
|
||||
/* Start sending the Client Key Exchange */
|
||||
tls->tx_state = TLS_TX_CLIENT_KEY_EXCHANGE;
|
||||
tls_tx_start ( tls, TLS_TX_CLIENT_KEY_EXCHANGE );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -946,9 +1002,10 @@ static int tls_new_finished ( struct tls_session *tls,
|
||||
void *data, size_t len ) {
|
||||
|
||||
/* FIXME: Handle this properly */
|
||||
tls->tx_state = TLS_TX_DATA;
|
||||
tls_tx_data ( tls );
|
||||
( void ) data;
|
||||
( void ) len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1623,6 +1680,7 @@ static int tls_cipherstream_deliver ( struct tls_session *tls,
|
||||
static struct interface_operation tls_cipherstream_ops[] = {
|
||||
INTF_OP ( xfer_deliver, struct tls_session *,
|
||||
tls_cipherstream_deliver ),
|
||||
INTF_OP ( xfer_window_changed, struct tls_session *, tls_tx_resume ),
|
||||
INTF_OP ( intf_close, struct tls_session *, tls_close ),
|
||||
};
|
||||
|
||||
@@ -1641,11 +1699,9 @@ static struct interface_descriptor tls_cipherstream_desc =
|
||||
/**
|
||||
* TLS TX state machine
|
||||
*
|
||||
* @v process TLS process
|
||||
* @v tls TLS session
|
||||
*/
|
||||
static void tls_step ( struct process *process ) {
|
||||
struct tls_session *tls =
|
||||
container_of ( process, struct tls_session, process );
|
||||
static void tls_tx_step ( struct tls_session *tls ) {
|
||||
int rc;
|
||||
|
||||
/* Wait for cipherstream to become ready */
|
||||
@@ -1663,7 +1719,7 @@ static void tls_step ( struct process *process ) {
|
||||
tls, strerror ( rc ) );
|
||||
goto err;
|
||||
}
|
||||
tls->tx_state = TLS_TX_NONE;
|
||||
tls_tx_none ( tls );
|
||||
break;
|
||||
case TLS_TX_CLIENT_KEY_EXCHANGE:
|
||||
/* Send Client Key Exchange */
|
||||
@@ -1672,7 +1728,7 @@ static void tls_step ( struct process *process ) {
|
||||
"%s\n", tls, strerror ( rc ) );
|
||||
goto err;
|
||||
}
|
||||
tls->tx_state = TLS_TX_CHANGE_CIPHER;
|
||||
tls_tx_start ( tls, TLS_TX_CHANGE_CIPHER );
|
||||
break;
|
||||
case TLS_TX_CHANGE_CIPHER:
|
||||
/* Send Change Cipher, and then change the cipher in use */
|
||||
@@ -1689,7 +1745,7 @@ static void tls_step ( struct process *process ) {
|
||||
goto err;
|
||||
}
|
||||
tls->tx_seq = 0;
|
||||
tls->tx_state = TLS_TX_FINISHED;
|
||||
tls_tx_start ( tls, TLS_TX_FINISHED );
|
||||
break;
|
||||
case TLS_TX_FINISHED:
|
||||
/* Send Finished */
|
||||
@@ -1698,7 +1754,7 @@ static void tls_step ( struct process *process ) {
|
||||
tls, strerror ( rc ) );
|
||||
goto err;
|
||||
}
|
||||
tls->tx_state = TLS_TX_NONE;
|
||||
tls_tx_none ( tls );
|
||||
break;
|
||||
case TLS_TX_DATA:
|
||||
/* Nothing to do */
|
||||
@@ -1713,6 +1769,10 @@ static void tls_step ( struct process *process ) {
|
||||
tls_close ( tls, rc );
|
||||
}
|
||||
|
||||
/** TLS TX process descriptor */
|
||||
static struct process_descriptor tls_process_desc =
|
||||
PROC_DESC_ONCE ( struct tls_session, process, tls_tx_step );
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Instantiator
|
||||
@@ -1743,8 +1803,8 @@ int add_tls ( struct interface *xfer, struct interface **next ) {
|
||||
( sizeof ( tls->pre_master_secret.random ) ) );
|
||||
digest_init ( &md5_algorithm, tls->handshake_md5_ctx );
|
||||
digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx );
|
||||
tls->tx_state = TLS_TX_CLIENT_HELLO;
|
||||
process_init ( &tls->process, tls_step, &tls->refcnt );
|
||||
process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt );
|
||||
tls_tx_start ( tls, TLS_TX_CLIENT_HELLO );
|
||||
|
||||
/* Attach to parent interface, mortalise self, and return */
|
||||
intf_plug_plug ( &tls->plainstream, xfer );
|
||||
|
||||
+5
-2
@@ -91,12 +91,13 @@ static int vlan_transmit ( struct net_device *netdev,
|
||||
const void *ll_dest;
|
||||
const void *ll_source;
|
||||
uint16_t net_proto;
|
||||
unsigned int flags;
|
||||
int rc;
|
||||
|
||||
/* Strip link-layer header and preserve link-layer header fields */
|
||||
ll_protocol = netdev->ll_protocol;
|
||||
if ( ( rc = ll_protocol->pull ( netdev, iobuf, &ll_dest, &ll_source,
|
||||
&net_proto ) ) != 0 ) {
|
||||
&net_proto, &flags ) ) != 0 ) {
|
||||
DBGC ( netdev, "VLAN %s could not parse link-layer header: "
|
||||
"%s\n", netdev->name, strerror ( rc ) );
|
||||
return rc;
|
||||
@@ -214,10 +215,12 @@ struct net_device * vlan_find ( struct net_device *trunk, unsigned int tag ) {
|
||||
* @v trunk Trunk network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer source address
|
||||
* @v flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int vlan_rx ( struct io_buffer *iobuf, struct net_device *trunk,
|
||||
const void *ll_dest, const void *ll_source ) {
|
||||
const void *ll_dest, const void *ll_source,
|
||||
unsigned int flags __unused ) {
|
||||
struct vlan_header *vlanhdr = iobuf->data;
|
||||
struct net_device *netdev;
|
||||
struct ll_protocol *ll_protocol;
|
||||
|
||||
+1
-2
@@ -74,8 +74,7 @@ void fcpeerstat ( struct fc_peer *peer ) {
|
||||
}
|
||||
|
||||
list_for_each_entry ( ulp, &peer->ulps, list ) {
|
||||
printf ( " [Type %02x usage %d link:",
|
||||
ulp->type, ulp->usage );
|
||||
printf ( " [Type %02x link:", ulp->type );
|
||||
if ( fc_link_ok ( &ulp->link ) ) {
|
||||
printf ( " up, params" );
|
||||
param = ulp->param;
|
||||
|
||||
+6
-2
@@ -47,12 +47,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
* @v netdev Network device
|
||||
* @v ll_dest Link-layer destination address
|
||||
* @v ll_source Link-layer source address
|
||||
* @v flags Packet flags
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int lotest_rx ( struct io_buffer *iobuf,
|
||||
struct net_device *netdev __unused,
|
||||
const void *ll_dest __unused,
|
||||
const void *ll_source __unused ) {
|
||||
const void *ll_source __unused,
|
||||
unsigned int flags __unused ) {
|
||||
free_iob ( iobuf );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
@@ -97,6 +99,7 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver,
|
||||
const void *ll_dest;
|
||||
const void *ll_source;
|
||||
uint16_t net_proto;
|
||||
unsigned int flags;
|
||||
unsigned int i;
|
||||
unsigned int successes;
|
||||
int rc;
|
||||
@@ -166,7 +169,8 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver,
|
||||
/* Check received packet */
|
||||
if ( ( rc = receiver->ll_protocol->pull ( receiver, iobuf,
|
||||
&ll_dest, &ll_source,
|
||||
&net_proto ) ) != 0 ){
|
||||
&net_proto,
|
||||
&flags ) ) != 0 ) {
|
||||
printf ( "\nFailed to strip link-layer header: %s",
|
||||
strerror ( rc ) );
|
||||
goto done;
|
||||
|
||||
Reference in New Issue
Block a user