2
0
mirror of https://github.com/xcat2/xNBA.git synced 2026-09-09 14:36:38 +00:00
This commit is contained in:
Jarrod Johnson
2011-08-08 11:18:19 -04:00
49 changed files with 1394 additions and 540 deletions
+8 -2
View File
@@ -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
+14 -4
View File
@@ -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 );
+2 -1
View File
@@ -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 */ )
+15
View File
@@ -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 ),
};
+7 -7
View File
@@ -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,
+1 -1
View File
@@ -160,7 +160,7 @@ relocatable_kernel:
pad2:
.byte 0, 0, 0
cmdline_size:
.long 0
.long 0x7ff
hardware_subarch:
.long 0
hardware_subarch_data:
+2 -2
View File
@@ -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
+3 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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",
-5
View File
@@ -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); }
+4 -1
View File
@@ -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;
}
+33
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+21 -9
View File
@@ -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
View File
@@ -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 */
+3 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 ) );
+1 -4
View File
@@ -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 );
/***************************************************************************
*
+11 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;