diff options
Diffstat (limited to 'src/net')
| -rw-r--r-- | src/net/80211/wpa.c | 25 | ||||
| -rw-r--r-- | src/net/aoe.c | 31 | ||||
| -rw-r--r-- | src/net/eap.c | 142 | ||||
| -rw-r--r-- | src/net/eapol.c | 139 | ||||
| -rw-r--r-- | src/net/eth_slow.c | 11 | ||||
| -rw-r--r-- | src/net/fcp.c | 28 | ||||
| -rw-r--r-- | src/net/infiniband.c | 20 | ||||
| -rw-r--r-- | src/net/infiniband/ib_sma.c | 2 | ||||
| -rw-r--r-- | src/net/infiniband/ib_srp.c | 35 | ||||
| -rw-r--r-- | src/net/ndp.c | 29 | ||||
| -rw-r--r-- | src/net/netdevice.c | 34 | ||||
| -rw-r--r-- | src/net/tcp/httpconn.c | 13 | ||||
| -rw-r--r-- | src/net/tcp/httpcore.c | 15 | ||||
| -rw-r--r-- | src/net/tcp/https.c | 14 | ||||
| -rw-r--r-- | src/net/tcp/iscsi.c | 2 | ||||
| -rw-r--r-- | src/net/tcp/syslogs.c | 29 | ||||
| -rw-r--r-- | src/net/tls.c | 143 | ||||
| -rw-r--r-- | src/net/udp/dhcp.c | 23 | ||||
| -rw-r--r-- | src/net/udp/dns.c | 18 | ||||
| -rw-r--r-- | src/net/udp/tftp.c | 24 | ||||
| -rw-r--r-- | src/net/validator.c | 12 |
21 files changed, 556 insertions, 233 deletions
diff --git a/src/net/80211/wpa.c b/src/net/80211/wpa.c index 5ec5005bf..1484d0e80 100644 --- a/src/net/80211/wpa.c +++ b/src/net/80211/wpa.c @@ -414,12 +414,13 @@ static int wpa_maybe_install_gtk ( struct wpa_common_ctx *ctx, static struct io_buffer * wpa_alloc_frame ( int kdlen ) { struct io_buffer *ret = alloc_iob ( sizeof ( struct eapol_key_pkt ) + - kdlen + EAPOL_HDR_LEN + + kdlen + + sizeof ( struct eapol_header ) + MAX_LL_HEADER_LEN ); if ( ! ret ) return NULL; - iob_reserve ( ret, MAX_LL_HEADER_LEN + EAPOL_HDR_LEN ); + iob_reserve ( ret, MAX_LL_HEADER_LEN + sizeof ( struct eapol_header ) ); memset ( iob_put ( ret, sizeof ( struct eapol_key_pkt ) ), 0, sizeof ( struct eapol_key_pkt ) ); @@ -442,19 +443,19 @@ static int wpa_send_eapol ( struct io_buffer *iob, struct wpa_common_ctx *ctx, struct wpa_kie *kie ) { struct eapol_key_pkt *pkt = iob->data; - struct eapol_frame *eapol = iob_push ( iob, EAPOL_HDR_LEN ); + struct eapol_header *eapol = iob_push ( iob, sizeof ( *eapol ) ); pkt->info = htons ( pkt->info ); pkt->keysize = htons ( pkt->keysize ); pkt->datalen = htons ( pkt->datalen ); pkt->replay = cpu_to_be64 ( pkt->replay ); - eapol->version = EAPOL_THIS_VERSION; + eapol->version = EAPOL_VERSION_2001; eapol->type = EAPOL_TYPE_KEY; - eapol->length = htons ( iob->tail - iob->data - sizeof ( *eapol ) ); + eapol->len = htons ( iob->tail - iob->data - sizeof ( *eapol ) ); memset ( pkt->mic, 0, sizeof ( pkt->mic ) ); if ( kie ) - kie->mic ( &ctx->ptk.kck, eapol, EAPOL_HDR_LEN + + kie->mic ( &ctx->ptk.kck, eapol, sizeof ( *eapol ) + sizeof ( *pkt ) + ntohs ( pkt->datalen ), pkt->mic ); @@ -762,21 +763,23 @@ static int wpa_handle_1_of_2 ( struct wpa_common_ctx *ctx, * * @v iob I/O buffer * @v netdev Network device - * @v ll_dest Link-layer destination address * @v ll_source Source link-layer address */ static int eapol_key_rx ( struct io_buffer *iob, struct net_device *netdev, - const void *ll_dest __unused, const void *ll_source ) { struct net80211_device *dev = net80211_get ( netdev ); - struct eapol_key_pkt *pkt = iob->data; + struct eapol_header *eapol; + struct eapol_key_pkt *pkt; int is_rsn, found_ctx; struct wpa_common_ctx *ctx; int rc = 0; struct wpa_kie *kie; u8 their_mic[16], our_mic[16]; + eapol = iob->data; + pkt = ( ( ( void * ) eapol ) + sizeof ( *eapol ) ); + if ( pkt->type != EAPOL_KEY_TYPE_WPA && pkt->type != EAPOL_KEY_TYPE_RSN ) { DBG ( "EAPOL-Key: packet not of 802.11 type\n" ); @@ -840,8 +843,8 @@ static int eapol_key_rx ( struct io_buffer *iob, struct net_device *netdev, if ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_KEY_MIC ) { memcpy ( their_mic, pkt->mic, sizeof ( pkt->mic ) ); memset ( pkt->mic, 0, sizeof ( pkt->mic ) ); - kie->mic ( &ctx->ptk.kck, ( void * ) pkt - EAPOL_HDR_LEN, - EAPOL_HDR_LEN + sizeof ( *pkt ) + + kie->mic ( &ctx->ptk.kck, eapol, + sizeof ( *eapol ) + sizeof ( *pkt ) + ntohs ( pkt->datalen ), our_mic ); DBGC2 ( ctx, "WPA %p MIC comparison (theirs, ours):\n", ctx ); DBGC2_HD ( ctx, their_mic, 16 ); diff --git a/src/net/aoe.c b/src/net/aoe.c index 3a6611d04..e785e8979 100644 --- a/src/net/aoe.c +++ b/src/net/aoe.c @@ -42,6 +42,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/open.h> #include <ipxe/ata.h> #include <ipxe/device.h> +#include <ipxe/efi/efi_path.h> #include <ipxe/aoe.h> /** @file @@ -68,35 +69,6 @@ static LIST_HEAD ( aoe_devices ); /** List of active AoE commands */ static LIST_HEAD ( aoe_commands ); -/** An AoE device */ -struct aoe_device { - /** Reference counter */ - struct refcnt refcnt; - - /** Network device */ - struct net_device *netdev; - /** ATA command issuing interface */ - struct interface ata; - - /** Major number */ - uint16_t major; - /** Minor number */ - uint8_t minor; - /** Target MAC address */ - uint8_t target[MAX_LL_ADDR_LEN]; - - /** Saved timeout value */ - unsigned long timeout; - - /** Configuration command interface */ - struct interface config; - /** Device is configued */ - int configured; - - /** ACPI descriptor */ - struct acpi_descriptor desc; -}; - /** An AoE command */ struct aoe_command { /** Reference count */ @@ -811,6 +783,7 @@ static struct interface_operation aoedev_ata_op[] = { INTF_OP ( acpi_describe, struct aoe_device *, aoedev_describe ), INTF_OP ( identify_device, struct aoe_device *, aoedev_identify_device ), + EFI_INTF_OP ( efi_describe, struct aoe_device *, efi_aoe_path ), }; /** AoE device ATA interface descriptor */ diff --git a/src/net/eap.c b/src/net/eap.c new file mode 100644 index 000000000..8d1d540fb --- /dev/null +++ b/src/net/eap.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <errno.h> +#include <ipxe/netdevice.h> +#include <ipxe/eap.h> + +/** @file + * + * Extensible Authentication Protocol + * + */ + +/** + * Handle EAP Request-Identity + * + * @v netdev Network device + * @ret rc Return status code + */ +static int eap_rx_request_identity ( struct net_device *netdev ) { + + /* Treat Request-Identity as blocking the link */ + DBGC ( netdev, "EAP %s Request-Identity blocking link\n", + netdev->name ); + netdev_link_block ( netdev, EAP_BLOCK_TIMEOUT ); + + return 0; +} + +/** + * Handle EAP Request + * + * @v netdev Network device + * @v req EAP request + * @v len Length of EAP request + * @ret rc Return status code + */ +static int eap_rx_request ( struct net_device *netdev, + const struct eap_request *req, size_t len ) { + + /* Sanity check */ + if ( len < sizeof ( *req ) ) { + DBGC ( netdev, "EAP %s underlength request:\n", netdev->name ); + DBGC_HDA ( netdev, 0, req, len ); + return -EINVAL; + } + + /* Handle according to type */ + switch ( req->type ) { + case EAP_TYPE_IDENTITY: + return eap_rx_request_identity ( netdev ); + default: + DBGC ( netdev, "EAP %s requested type %d unknown:\n", + netdev->name, req->type ); + DBGC_HDA ( netdev, 0, req, len ); + return -ENOTSUP; + } +} + +/** + * Handle EAP Success + * + * @v netdev Network device + * @ret rc Return status code + */ +static int eap_rx_success ( struct net_device *netdev ) { + + /* Mark link as unblocked */ + DBGC ( netdev, "EAP %s Success\n", netdev->name ); + netdev_link_unblock ( netdev ); + + return 0; +} + +/** + * Handle EAP Failure + * + * @v netdev Network device + * @ret rc Return status code + */ +static int eap_rx_failure ( struct net_device *netdev ) { + + /* Record error */ + DBGC ( netdev, "EAP %s Failure\n", netdev->name ); + return -EPERM; +} + +/** + * Handle EAP packet + * + * @v netdev Network device + * @v data EAP packet + * @v len Length of EAP packet + * @ret rc Return status code + */ +int eap_rx ( struct net_device *netdev, const void *data, size_t len ) { + const union eap_packet *eap = data; + + /* Sanity check */ + if ( len < sizeof ( eap->hdr ) ) { + DBGC ( netdev, "EAP %s underlength header:\n", netdev->name ); + DBGC_HDA ( netdev, 0, eap, len ); + return -EINVAL; + } + + /* Handle according to code */ + switch ( eap->hdr.code ) { + case EAP_CODE_REQUEST: + return eap_rx_request ( netdev, &eap->req, len ); + case EAP_CODE_SUCCESS: + return eap_rx_success ( netdev ); + case EAP_CODE_FAILURE: + return eap_rx_failure ( netdev ); + default: + DBGC ( netdev, "EAP %s unsupported code %d\n", + netdev->name, eap->hdr.code ); + DBGC_HDA ( netdev, 0, eap, len ); + return -ENOTSUP; + } +} diff --git a/src/net/eapol.c b/src/net/eapol.c index eb0362994..3578f0e37 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>. + * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,74 +15,127 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. */ -FILE_LICENCE ( GPL2_OR_LATER ); +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <assert.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/iobuf.h> +#include <ipxe/if_ether.h> +#include <ipxe/netdevice.h> +#include <ipxe/eap.h> +#include <ipxe/eapol.h> /** @file * - * 802.1X Extensible Authentication Protocol over LANs demultiplexer + * Extensible Authentication Protocol over LAN (EAPoL) * */ -#include <ipxe/netdevice.h> -#include <ipxe/iobuf.h> -#include <ipxe/if_ether.h> -#include <ipxe/eapol.h> -#include <errno.h> -#include <byteswap.h> - /** - * Receive EAPOL network-layer packet + * Process EAPoL packet * - * @v iob 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 - * - * This function takes ownership of the I/O buffer passed to it. + * @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 */ -static int eapol_rx ( struct io_buffer *iob, struct net_device *netdev, - const void *ll_dest, const void *ll_source, +static int eapol_rx ( struct io_buffer *iobuf, struct net_device *netdev, + const void *ll_dest __unused, const void *ll_source, unsigned int flags __unused ) { - struct eapol_frame *eapol = iob->data; + struct eapol_header *eapol; struct eapol_handler *handler; + size_t remaining; + size_t len; + int rc; - if ( iob_len ( iob ) < EAPOL_HDR_LEN ) { - free_iob ( iob ); - return -EINVAL; + /* Sanity checks */ + if ( iob_len ( iobuf ) < sizeof ( *eapol ) ) { + DBGC ( netdev, "EAPOL %s underlength header:\n", + netdev->name ); + DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); + rc = -EINVAL; + goto drop; + } + eapol = iobuf->data; + remaining = ( iob_len ( iobuf ) - sizeof ( *eapol ) ); + len = ntohs ( eapol->len ); + if ( len > remaining ) { + DBGC ( netdev, "EAPOL %s v%d type %d len %zd underlength " + "payload:\n", netdev->name, eapol->version, + eapol->type, len ); + DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); + rc = -EINVAL; + goto drop; } + /* Strip any trailing padding */ + iob_unput ( iobuf, ( len - remaining ) ); + + /* Handle according to type */ for_each_table_entry ( handler, EAPOL_HANDLERS ) { if ( handler->type == eapol->type ) { - iob_pull ( iob, EAPOL_HDR_LEN ); - return handler->rx ( iob, netdev, ll_dest, ll_source ); + return handler->rx ( iob_disown ( iobuf ) , netdev, + ll_source ); } } + rc = -ENOTSUP; + DBGC ( netdev, "EAPOL %s v%d type %d unsupported\n", + netdev->name, eapol->version, eapol->type ); + DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); - free_iob ( iob ); - return -( ENOTSUP | ( ( eapol->type & 0x1f ) << 8 ) ); + drop: + free_iob ( iobuf ); + return rc; } +/** EAPoL protocol */ +struct net_protocol eapol_protocol __net_protocol = { + .name = "EAPOL", + .net_proto = htons ( ETH_P_EAPOL ), + .rx = eapol_rx, +}; + /** - * Transcribe EAPOL network-layer address + * Process EAPoL-encapsulated EAP packet * - * @v net_addr Network-layer address - * @ret str String representation of network-layer address - * - * EAPOL doesn't have network-layer addresses, so we just return the - * string @c "<EAPOL>". + * @v netdev Network device + * @v ll_source Link-layer source address + * @ret rc Return status code */ -static const char * eapol_ntoa ( const void *net_addr __unused ) -{ - return "<EAPOL>"; +static int eapol_eap_rx ( struct io_buffer *iobuf, struct net_device *netdev, + const void *ll_source __unused ) { + struct eapol_header *eapol; + int rc; + + /* Sanity check */ + assert ( iob_len ( iobuf ) >= sizeof ( *eapol ) ); + + /* Strip EAPoL header */ + eapol = iob_pull ( iobuf, sizeof ( *eapol ) ); + + /* Process EAP packet */ + if ( ( rc = eap_rx ( netdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 ) { + DBGC ( netdev, "EAPOL %s v%d EAP failed: %s\n", + netdev->name, eapol->version, strerror ( rc ) ); + goto drop; + } + + drop: + free_iob ( iobuf ); + return rc; } -/** EAPOL network protocol */ -struct net_protocol eapol_protocol __net_protocol = { - .name = "EAPOL", - .rx = eapol_rx, - .ntoa = eapol_ntoa, - .net_proto = htons ( ETH_P_EAPOL ), +/** EAPoL handler for EAP packets */ +struct eapol_handler eapol_eap __eapol_handler = { + .type = EAPOL_TYPE_EAP, + .rx = eapol_eap_rx, }; diff --git a/src/net/eth_slow.c b/src/net/eth_slow.c index baa51dbc1..1103a49f3 100644 --- a/src/net/eth_slow.c +++ b/src/net/eth_slow.c @@ -153,6 +153,14 @@ static int eth_slow_lacp_rx ( struct io_buffer *iobuf, eth_slow_lacp_dump ( iobuf, netdev, "RX" ); + /* Check for looped-back packets */ + if ( memcmp ( lacp->actor.system, netdev->ll_addr, + sizeof ( lacp->actor.system ) ) == 0 ) { + DBGC ( netdev, "SLOW %s RX loopback detected\n", + netdev->name ); + return -ELOOP; + } + /* If partner is not in sync, collecting, and distributing, * then block the link until after the next expected LACP * packet. @@ -278,6 +286,9 @@ static int eth_slow_rx ( struct io_buffer *iobuf, return -EINVAL; } + /* Strip any trailing padding */ + iob_unput ( iobuf, ( sizeof ( *eth_slow ) - iob_len ( iobuf ) ) ); + /* Handle according to subtype */ switch ( eth_slow->header.subtype ) { case ETH_SLOW_SUBTYPE_LACP: diff --git a/src/net/fcp.c b/src/net/fcp.c index d92cfdcf3..f78f7bd9b 100644 --- a/src/net/fcp.c +++ b/src/net/fcp.c @@ -43,6 +43,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/scsi.h> #include <ipxe/device.h> #include <ipxe/edd.h> +#include <ipxe/efi/efi_path.h> #include <ipxe/fc.h> #include <ipxe/fcels.h> #include <ipxe/fcp.h> @@ -158,10 +159,8 @@ struct fcp_device { /** List of active commands */ struct list_head fcpcmds; - /** Fibre Channel WWN (for boot firmware table) */ - struct fc_name wwn; - /** SCSI LUN (for boot firmware table) */ - struct scsi_lun lun; + /** Device description (for boot firmware table) */ + struct fcp_description desc; }; /** An FCP command */ @@ -864,9 +863,9 @@ static int fcpdev_edd_describe ( struct fcp_device *fcpdev, } lun; type->type = cpu_to_le64 ( EDD_INTF_TYPE_FIBRE ); - memcpy ( &wwn.fc, &fcpdev->wwn, sizeof ( wwn.fc ) ); + memcpy ( &wwn.fc, &fcpdev->desc.wwn, sizeof ( wwn.fc ) ); path->fibre.wwn = be64_to_cpu ( wwn.u64 ); - memcpy ( &lun.scsi, &fcpdev->lun, sizeof ( lun.scsi ) ); + memcpy ( &lun.scsi, &fcpdev->desc.lun, sizeof ( lun.scsi ) ); path->fibre.lun = be64_to_cpu ( lun.u64 ); return 0; } @@ -893,6 +892,18 @@ static struct device * fcpdev_identify_device ( struct fcp_device *fcpdev ) { return identify_device ( &fcpdev->user.ulp->peer->port->transport ); } +/** + * Describe as an EFI device path + * + * @v fcp FCP device + * @ret path EFI device path, or NULL on error + */ +static EFI_DEVICE_PATH_PROTOCOL * +fcpdev_efi_describe ( struct fcp_device *fcpdev ) { + + return efi_fcp_path ( &fcpdev->desc ); +} + /** FCP device SCSI interface operations */ static struct interface_operation fcpdev_scsi_op[] = { INTF_OP ( scsi_command, struct fcp_device *, fcpdev_scsi_command ), @@ -901,6 +912,7 @@ static struct interface_operation fcpdev_scsi_op[] = { INTF_OP ( edd_describe, struct fcp_device *, fcpdev_edd_describe ), INTF_OP ( identify_device, struct fcp_device *, fcpdev_identify_device ), + EFI_INTF_OP ( efi_describe, struct fcp_device *, fcpdev_efi_describe ), }; /** FCP device SCSI interface descriptor */ @@ -965,8 +977,8 @@ static int fcpdev_open ( struct interface *parent, struct fc_name *wwn, 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 ) ); + memcpy ( &fcpdev->desc.wwn, wwn, sizeof ( fcpdev->desc.wwn ) ); + memcpy ( &fcpdev->desc.lun, lun, sizeof ( fcpdev->desc.lun ) ); /* Attach SCSI device to parent interface */ if ( ( rc = scsi_open ( parent, &fcpdev->scsi, lun ) ) != 0 ) { diff --git a/src/net/infiniband.c b/src/net/infiniband.c index 3b79a660c..e19e121c1 100644 --- a/src/net/infiniband.c +++ b/src/net/infiniband.c @@ -814,26 +814,6 @@ void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp, */ /** - * Count Infiniband HCA ports - * - * @v ibdev Infiniband device - * @ret num_ports Number of ports - */ -int ib_count_ports ( struct ib_device *ibdev ) { - struct ib_device *tmp; - int num_ports = 0; - - /* Search for IB devices with the same physical device to - * identify port count. - */ - for_each_ibdev ( tmp ) { - if ( tmp->dev == ibdev->dev ) - num_ports++; - } - return num_ports; -} - -/** * Set port information * * @v ibdev Infiniband device diff --git a/src/net/infiniband/ib_sma.c b/src/net/infiniband/ib_sma.c index 24ec9f4e0..b553e66b1 100644 --- a/src/net/infiniband/ib_sma.c +++ b/src/net/infiniband/ib_sma.c @@ -63,7 +63,7 @@ static void ib_sma_node_info ( struct ib_device *ibdev, node_info->base_version = IB_MGMT_BASE_VERSION; node_info->class_version = IB_SMP_CLASS_VERSION; node_info->node_type = IB_NODE_TYPE_HCA; - node_info->num_ports = ib_count_ports ( ibdev ); + node_info->num_ports = ibdev->ports; memcpy ( &node_info->sys_guid, &ibdev->node_guid, sizeof ( node_info->sys_guid ) ); memcpy ( &node_info->node_guid, &ibdev->node_guid, diff --git a/src/net/infiniband/ib_srp.c b/src/net/infiniband/ib_srp.c index 4913f449c..e6b43291f 100644 --- a/src/net/infiniband/ib_srp.c +++ b/src/net/infiniband/ib_srp.c @@ -37,6 +37,7 @@ FILE_LICENCE ( BSD2 ); #include <ipxe/open.h> #include <ipxe/base16.h> #include <ipxe/acpi.h> +#include <ipxe/efi/efi_path.h> #include <ipxe/srp.h> #include <ipxe/infiniband.h> #include <ipxe/ib_cmrc.h> @@ -70,39 +71,6 @@ struct acpi_model ib_sbft_model __acpi_model; */ /** - * An IB SRP sBFT created by iPXE - */ -struct ipxe_ib_sbft { - /** The table header */ - struct sbft_table table; - /** The SCSI subtable */ - struct sbft_scsi_subtable scsi; - /** The SRP subtable */ - struct sbft_srp_subtable srp; - /** The Infiniband subtable */ - struct sbft_ib_subtable ib; -}; - -/** An Infiniband SRP device */ -struct ib_srp_device { - /** Reference count */ - struct refcnt refcnt; - - /** SRP transport interface */ - struct interface srp; - /** CMRC interface */ - struct interface cmrc; - - /** Infiniband device */ - struct ib_device *ibdev; - - /** ACPI descriptor */ - struct acpi_descriptor desc; - /** Boot firmware table parameters */ - struct ipxe_ib_sbft sbft; -}; - -/** * Free IB SRP device * * @v refcnt Reference count @@ -153,6 +121,7 @@ static struct interface_descriptor ib_srp_cmrc_desc = static struct interface_operation ib_srp_srp_op[] = { INTF_OP ( acpi_describe, struct ib_srp_device *, ib_srp_describe ), INTF_OP ( intf_close, struct ib_srp_device *, ib_srp_close ), + EFI_INTF_OP ( efi_describe, struct ib_srp_device *, efi_ib_srp_path ), }; /** IB SRP SRP interface descriptor */ diff --git a/src/net/ndp.c b/src/net/ndp.c index f28e71cbd..75e531648 100644 --- a/src/net/ndp.c +++ b/src/net/ndp.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/icmpv6.h> #include <ipxe/neighbour.h> #include <ipxe/dhcpv6.h> +#include <ipxe/timer.h> #include <ipxe/ndp.h> /** @file @@ -39,6 +40,18 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** Router discovery minimum timeout */ +#define IPV6CONF_MIN_TIMEOUT ( TICKS_PER_SEC / 8 ) + +/** Router discovery maximum timeout */ +#define IPV6CONF_MAX_TIMEOUT ( TICKS_PER_SEC * 3 ) + +/** Router discovery blocked link retry timeout */ +#define IPV6CONF_BLOCK_TIMEOUT ( TICKS_PER_SEC ) + +/** Router discovery maximum number of deferrals */ +#define IPV6CONF_MAX_DEFERRALS 180 + static struct ipv6conf * ipv6conf_demux ( struct net_device *netdev ); static int ipv6conf_rx_router_advertisement ( struct net_device *netdev, @@ -1061,6 +1074,9 @@ struct ipv6conf { /** Retransmission timer */ struct retry_timer timer; + + /** Deferred discovery counter */ + unsigned int deferred; }; /** List of IPv6 configurators */ @@ -1124,6 +1140,7 @@ static void ipv6conf_done ( struct ipv6conf *ipv6conf, int rc ) { static void ipv6conf_expired ( struct retry_timer *timer, int fail ) { struct ipv6conf *ipv6conf = container_of ( timer, struct ipv6conf, timer ); + struct net_device *netdev = ipv6conf->netdev; /* If we have failed, terminate autoconfiguration */ if ( fail ) { @@ -1133,7 +1150,15 @@ static void ipv6conf_expired ( struct retry_timer *timer, int fail ) { /* Otherwise, transmit router solicitation and restart timer */ start_timer ( &ipv6conf->timer ); - ndp_tx_router_solicitation ( ipv6conf->netdev ); + ndp_tx_router_solicitation ( netdev ); + + /* If link is blocked, defer router discovery timeout */ + if ( netdev_link_blocked ( netdev ) && + ( ipv6conf->deferred++ <= IPV6CONF_MAX_DEFERRALS ) ) { + DBGC ( netdev, "NDP %s deferring discovery timeout\n", + netdev->name ); + start_timer_fixed ( &ipv6conf->timer, IPV6CONF_BLOCK_TIMEOUT ); + } } /** @@ -1235,6 +1260,8 @@ int start_ipv6conf ( struct interface *job, struct net_device *netdev ) { intf_init ( &ipv6conf->job, &ipv6conf_job_desc, &ipv6conf->refcnt ); intf_init ( &ipv6conf->dhcp, &ipv6conf_dhcp_desc, &ipv6conf->refcnt ); timer_init ( &ipv6conf->timer, ipv6conf_expired, &ipv6conf->refcnt ); + set_timer_limits ( &ipv6conf->timer, IPV6CONF_MIN_TIMEOUT, + IPV6CONF_MAX_TIMEOUT ); ipv6conf->netdev = netdev_get ( netdev ); /* Start timer to initiate router solicitation */ diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 3b02e64bd..6e685630c 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -307,6 +307,12 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { if ( ( rc = inject_fault ( NETDEV_DISCARD_RATE ) ) != 0 ) goto err; + /* Map for DMA, if required */ + if ( netdev->dma && ( ! dma_mapped ( &iobuf->map ) ) ) { + if ( ( rc = iob_map_tx ( iobuf, netdev->dma ) ) != 0 ) + goto err; + } + /* Transmit packet */ if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 ) goto err; @@ -340,6 +346,9 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { * Failure to do this will cause the retransmitted packet to be * immediately redeferred (which will result in out-of-order * transmissions and other nastiness). + * + * I/O buffers that have been mapped for DMA will remain mapped while + * present in the deferred transmit queue. */ void netdev_tx_defer ( struct net_device *netdev, struct io_buffer *iobuf ) { @@ -365,6 +374,9 @@ void netdev_tx_defer ( struct net_device *netdev, struct io_buffer *iobuf ) { * * The packet is discarded and a TX error is recorded. This function * takes ownership of the I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_tx_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { @@ -379,6 +391,10 @@ void netdev_tx_err ( struct net_device *netdev, netdev->name, iobuf, strerror ( rc ) ); } + /* Unmap I/O buffer, if required */ + if ( iobuf && dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Discard packet */ free_iob ( iobuf ); } @@ -462,10 +478,13 @@ static void netdev_tx_flush ( struct net_device *netdev ) { * Add packet to receive queue * * @v netdev Network device - * @v iobuf I/O buffer, or NULL + * @v iobuf I/O buffer * * The packet is added to the network device's RX queue. This * function takes ownership of the I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { int rc; @@ -479,6 +498,10 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { return; } + /* Unmap I/O buffer, if required */ + if ( dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Enqueue packet */ list_add_tail ( &iobuf->list, &netdev->rx_queue ); @@ -497,6 +520,9 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { * takes ownership of the I/O buffer. @c iobuf may be NULL if, for * example, the net device wishes to report an error due to being * unable to allocate an I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_rx_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { @@ -504,6 +530,10 @@ void netdev_rx_err ( struct net_device *netdev, DBGC ( netdev, "NETDEV %s failed to receive %p: %s\n", netdev->name, iobuf, strerror ( rc ) ); + /* Unmap I/O buffer, if required */ + if ( iobuf && dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Discard packet */ free_iob ( iobuf ); @@ -1178,6 +1208,8 @@ static unsigned int net_discard ( void ) { /* Discard first deferred packet */ list_del ( &iobuf->list ); + if ( dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); free_iob ( iobuf ); /* Report discard */ diff --git a/src/net/tcp/httpconn.c b/src/net/tcp/httpconn.c index 5121ff6c2..f9221b27e 100644 --- a/src/net/tcp/httpconn.c +++ b/src/net/tcp/httpconn.c @@ -236,7 +236,6 @@ int http_connect ( struct interface *xfer, struct uri *uri ) { struct http_connection *conn; struct http_scheme *scheme; struct sockaddr_tcpip server; - struct interface *socket; unsigned int port; int rc; @@ -296,15 +295,15 @@ int http_connect ( struct interface *xfer, struct uri *uri ) { /* Open socket */ memset ( &server, 0, sizeof ( server ) ); server.st_port = htons ( port ); - socket = &conn->socket; - if ( scheme->filter && - ( ( rc = scheme->filter ( socket, uri->host, &socket ) ) != 0 ) ) - goto err_filter; - if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM, + if ( ( rc = xfer_open_named_socket ( &conn->socket, SOCK_STREAM, ( struct sockaddr * ) &server, uri->host, NULL ) ) != 0 ) goto err_open; + /* Add filter, if any */ + if ( scheme->filter && ( ( rc = scheme->filter ( conn ) ) != 0 ) ) + goto err_filter; + /* Attach to parent interface, mortalise self, and return */ intf_plug_plug ( &conn->xfer, xfer ); ref_put ( &conn->refcnt ); @@ -313,8 +312,8 @@ int http_connect ( struct interface *xfer, struct uri *uri ) { conn->scheme->name, conn->uri->host, port ); return 0; - err_open: err_filter: + err_open: DBGC2 ( conn, "HTTPCONN %p could not create %s://%s:%d: %s\n", conn, conn->scheme->name, conn->uri->host, port, strerror ( rc ) ); http_conn_close ( conn, rc ); diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c index f755fb72d..01bb496b2 100644 --- a/src/net/tcp/httpcore.c +++ b/src/net/tcp/httpcore.c @@ -56,6 +56,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/profile.h> #include <ipxe/vsprintf.h> #include <ipxe/errortab.h> +#include <ipxe/efi/efi_path.h> #include <ipxe/http.h> /* Disambiguate the various error causes */ @@ -519,6 +520,18 @@ __weak int http_block_read_capacity ( struct http_transaction *http __unused, return -ENOTSUP; } +/** + * Describe as an EFI device path + * + * @v http HTTP transaction + * @ret path EFI device path, or NULL on error + */ +static EFI_DEVICE_PATH_PROTOCOL * +http_efi_describe ( struct http_transaction *http ) { + + return efi_uri_path ( http->uri ); +} + /** HTTP data transfer interface operations */ static struct interface_operation http_xfer_operations[] = { INTF_OP ( block_read, struct http_transaction *, http_block_read ), @@ -526,6 +539,8 @@ static struct interface_operation http_xfer_operations[] = { http_block_read_capacity ), INTF_OP ( xfer_window_changed, struct http_transaction *, http_step ), INTF_OP ( intf_close, struct http_transaction *, http_close ), + EFI_INTF_OP ( efi_describe, struct http_transaction *, + http_efi_describe ), }; /** HTTP data transfer interface descriptor */ diff --git a/src/net/tcp/https.c b/src/net/tcp/https.c index e91000322..85f1f124f 100644 --- a/src/net/tcp/https.c +++ b/src/net/tcp/https.c @@ -31,12 +31,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include <ipxe/open.h> +#include <ipxe/uri.h> #include <ipxe/tls.h> #include <ipxe/http.h> #include <ipxe/features.h> FEATURE ( FEATURE_PROTOCOL, "HTTPS", DHCP_EB_FEATURE_HTTPS, 1 ); +/** + * Add HTTPS filter + * + * @v conn HTTP connection + * @ret rc Return status code + */ +static int https_filter ( struct http_connection *conn ) { + + return add_tls ( &conn->socket, conn->uri->host, NULL, NULL ); +} + /** HTTPS URI opener */ struct uri_opener https_uri_opener __uri_opener = { .scheme = "https", @@ -47,5 +59,5 @@ struct uri_opener https_uri_opener __uri_opener = { struct http_scheme https_scheme __http_scheme = { .name = "https", .port = HTTPS_PORT, - .filter = add_tls, + .filter = https_filter, }; diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index 3a44b90f0..e36d5619d 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -46,6 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/base16.h> #include <ipxe/base64.h> #include <ipxe/ibft.h> +#include <ipxe/efi/efi_path.h> #include <ipxe/iscsi.h> /** @file @@ -1863,6 +1864,7 @@ static struct interface_operation iscsi_control_op[] = { INTF_OP ( xfer_window, struct iscsi_session *, iscsi_scsi_window ), INTF_OP ( intf_close, struct iscsi_session *, iscsi_close ), INTF_OP ( acpi_describe, struct iscsi_session *, iscsi_describe ), + EFI_INTF_OP ( efi_describe, struct iscsi_session *, efi_iscsi_path ), }; /** iSCSI SCSI command-issuing interface descriptor */ diff --git a/src/net/tcp/syslogs.c b/src/net/tcp/syslogs.c index 0c07f86d5..f1f70d59e 100644 --- a/src/net/tcp/syslogs.c +++ b/src/net/tcp/syslogs.c @@ -62,9 +62,10 @@ static struct sockaddr_tcpip logserver = { * @v intf Interface * @v rc Reason for close */ -static void syslogs_close ( struct interface *intf __unused, int rc ) { +static void syslogs_close ( struct interface *intf, int rc ) { DBG ( "SYSLOGS console disconnected: %s\n", strerror ( rc ) ); + intf_restart ( intf, rc ); } /** @@ -208,7 +209,6 @@ const struct setting syslogs_setting __setting ( SETTING_MISC, syslogs ) = { static int apply_syslogs_settings ( void ) { static char *old_server; char *server; - struct interface *socket; int rc; /* Fetch log server */ @@ -234,33 +234,32 @@ static int apply_syslogs_settings ( void ) { rc = 0; goto out_no_server; } - - /* Add TLS filter */ - if ( ( rc = add_tls ( &syslogs, server, &socket ) ) != 0 ) { - DBG ( "SYSLOGS cannot create TLS filter: %s\n", - strerror ( rc ) ); - goto err_add_tls; - } + DBG ( "SYSLOGS using log server %s\n", server ); /* Connect to log server */ - if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM, + if ( ( rc = xfer_open_named_socket ( &syslogs, SOCK_STREAM, (( struct sockaddr *) &logserver ), server, NULL ) ) != 0 ) { DBG ( "SYSLOGS cannot connect to log server: %s\n", strerror ( rc ) ); goto err_open_named_socket; } - DBG ( "SYSLOGS using log server %s\n", server ); + + /* Add TLS filter */ + if ( ( rc = add_tls ( &syslogs, server, NULL, NULL ) ) != 0 ) { + DBG ( "SYSLOGS cannot create TLS filter: %s\n", + strerror ( rc ) ); + goto err_add_tls; + } /* Record log server */ old_server = server; - server = NULL; - /* Success */ - rc = 0; + return 0; - err_open_named_socket: err_add_tls: + err_open_named_socket: + syslogs_close ( &syslogs, rc ); out_no_server: out_no_change: free ( server ); diff --git a/src/net/tls.c b/src/net/tls.c index ea827600f..3c4144450 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -45,6 +45,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/x509.h> #include <ipxe/privkey.h> #include <ipxe/certstore.h> +#include <ipxe/rootcert.h> #include <ipxe/rbg.h> #include <ipxe/validator.h> #include <ipxe/job.h> @@ -349,7 +350,9 @@ static void free_tls_session ( struct refcnt *refcnt ) { /* Remove from list of sessions */ list_del ( &session->list ); - /* Free session ticket */ + /* Free dynamically-allocated resources */ + x509_root_put ( session->root ); + privkey_put ( session->key ); free ( session->ticket ); /* Free session */ @@ -378,8 +381,10 @@ static void free_tls ( struct refcnt *refcnt ) { list_del ( &iobuf->list ); free_iob ( iobuf ); } - x509_put ( tls->cert ); + x509_chain_put ( tls->certs ); x509_chain_put ( tls->chain ); + x509_root_put ( tls->root ); + privkey_put ( tls->key ); /* Drop reference to session */ assert ( list_empty ( &tls->list ) ); @@ -1148,40 +1153,56 @@ static int tls_send_client_hello ( struct tls_connection *tls ) { */ static int tls_send_certificate ( struct tls_connection *tls ) { struct { - uint32_t type_length; tls24_t length; - struct { - tls24_t length; - uint8_t data[ tls->cert->raw.len ]; - } __attribute__ (( packed )) certificates[1]; + uint8_t data[0]; } __attribute__ (( packed )) *certificate; + struct { + uint32_t type_length; + tls24_t length; + typeof ( *certificate ) certificates[0]; + } __attribute__ (( packed )) *certificates; + struct x509_link *link; + struct x509_certificate *cert; + size_t len; int rc; + /* Calculate length of client certificates */ + len = 0; + list_for_each_entry ( link, &tls->certs->links, list ) { + cert = link->cert; + len += ( sizeof ( *certificate ) + cert->raw.len ); + DBGC ( tls, "TLS %p sending client certificate %s\n", + tls, x509_name ( cert ) ); + } + /* Allocate storage for Certificate record (which may be too * large for the stack). */ - certificate = zalloc ( sizeof ( *certificate ) ); - if ( ! certificate ) + certificates = zalloc ( sizeof ( *certificates ) + len ); + if ( ! certificates ) return -ENOMEM_CERTIFICATE; /* Populate record */ - certificate->type_length = + certificates->type_length = ( cpu_to_le32 ( TLS_CERTIFICATE ) | - htonl ( sizeof ( *certificate ) - - sizeof ( certificate->type_length ) ) ); - tls_set_uint24 ( &certificate->length, - sizeof ( certificate->certificates ) ); - tls_set_uint24 ( &certificate->certificates[0].length, - sizeof ( certificate->certificates[0].data ) ); - memcpy ( certificate->certificates[0].data, - tls->cert->raw.data, - sizeof ( certificate->certificates[0].data ) ); + htonl ( sizeof ( *certificates ) + len - + sizeof ( certificates->type_length ) ) ); + tls_set_uint24 ( &certificates->length, len ); + certificate = &certificates->certificates[0]; + list_for_each_entry ( link, &tls->certs->links, list ) { + cert = link->cert; + tls_set_uint24 ( &certificate->length, cert->raw.len ); + memcpy ( certificate->data, cert->raw.data, cert->raw.len ); + certificate = ( ( ( void * ) certificate->data ) + + cert->raw.len ); + } /* Transmit record */ - rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) ); + rc = tls_send_handshake ( tls, certificates, + ( sizeof ( *certificates ) + len ) ); /* Free record */ - free ( certificate ); + free ( certificates ); return rc; } @@ -1238,8 +1259,9 @@ static int tls_send_client_key_exchange ( struct tls_connection *tls ) { */ static int tls_send_certificate_verify ( struct tls_connection *tls ) { struct digest_algorithm *digest = tls->handshake_digest; - struct x509_certificate *cert = tls->cert; + struct x509_certificate *cert = x509_first ( tls->certs ); struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey; + struct asn1_cursor *key = privkey_cursor ( tls->key ); uint8_t digest_out[ digest->digestsize ]; uint8_t ctx[ pubkey->ctxsize ]; struct tls_signature_hash_algorithm *sig_hash = NULL; @@ -1249,8 +1271,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { tls_verify_handshake ( tls, digest_out ); /* Initialise public-key algorithm */ - if ( ( rc = pubkey_init ( pubkey, ctx, private_key.data, - private_key.len ) ) != 0 ) { + if ( ( rc = pubkey_init ( pubkey, ctx, key->data, key->len ) ) != 0 ) { DBGC ( tls, "TLS %p could not initialise %s client private " "key: %s\n", tls, pubkey->name, strerror ( rc ) ); goto err_pubkey_init; @@ -1845,26 +1866,57 @@ static int tls_new_certificate ( struct tls_connection *tls, static int tls_new_certificate_request ( struct tls_connection *tls, const void *data __unused, size_t len __unused ) { + struct x509_certificate *cert; + int rc; /* We can only send a single certificate, so there is no point * in parsing the Certificate Request. */ - /* Free any existing client certificate */ - x509_put ( tls->cert ); + /* Free any existing client certificate chain */ + x509_chain_put ( tls->certs ); + tls->certs = NULL; /* Determine client certificate to be sent */ - tls->cert = certstore_find_key ( &private_key ); - if ( ! tls->cert ) { + cert = certstore_find_key ( tls->key ); + if ( ! cert ) { DBGC ( tls, "TLS %p could not find certificate corresponding " "to private key\n", tls ); - return -EPERM_CLIENT_CERT; + rc = -EPERM_CLIENT_CERT; + goto err_find; + } + x509_get ( cert ); + DBGC ( tls, "TLS %p selected client certificate %s\n", + tls, x509_name ( cert ) ); + + /* Create client certificate chain */ + tls->certs = x509_alloc_chain(); + if ( ! tls->certs ) { + rc = -ENOMEM; + goto err_alloc; } - x509_get ( tls->cert ); - DBGC ( tls, "TLS %p sending client certificate %s\n", - tls, x509_name ( tls->cert ) ); + + /* Append client certificate to chain */ + if ( ( rc = x509_append ( tls->certs, cert ) ) != 0 ) + goto err_append; + + /* Append any relevant issuer certificates */ + if ( ( rc = x509_auto_append ( tls->certs, &certstore ) ) != 0 ) + goto err_auto_append; + + /* Drop local reference to client certificate */ + x509_put ( cert ); return 0; + + err_auto_append: + err_append: + x509_chain_put ( tls->certs ); + tls->certs = NULL; + err_alloc: + x509_put ( cert ); + err_find: + return rc; } /** @@ -1891,7 +1943,8 @@ static int tls_new_server_hello_done ( struct tls_connection *tls, } /* Begin certificate validation */ - if ( ( rc = create_validator ( &tls->validator, tls->chain ) ) != 0 ) { + if ( ( rc = create_validator ( &tls->validator, tls->chain, + tls->root ) ) != 0 ) { DBGC ( tls, "TLS %p could not start certificate validation: " "%s\n", tls, strerror ( rc ) ); return rc; @@ -2880,7 +2933,7 @@ static void tls_validator_done ( struct tls_connection *tls, int rc ) { tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE | TLS_TX_CHANGE_CIPHER | TLS_TX_FINISHED ); - if ( tls->cert ) { + if ( tls->certs ) { tls->tx_pending |= ( TLS_TX_CERTIFICATE | TLS_TX_CERTIFICATE_VERIFY ); } @@ -3048,7 +3101,9 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { /* Find existing matching session, if any */ list_for_each_entry ( session, &tls_sessions, list ) { - if ( strcmp ( name, session->name ) == 0 ) { + if ( ( strcmp ( name, session->name ) == 0 ) && + ( tls->root == session->root ) && + ( tls->key == session->key ) ) { ref_get ( &session->refcnt ); tls->session = session; DBGC ( tls, "TLS %p joining session %s\n", tls, name ); @@ -3067,6 +3122,8 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { name_copy = ( ( ( void * ) session ) + sizeof ( *session ) ); strcpy ( name_copy, name ); session->name = name_copy; + session->root = x509_root_get ( tls->root ); + session->key = privkey_get ( tls->key ); INIT_LIST_HEAD ( &session->conn ); list_add ( &session->list, &tls_sessions ); @@ -3088,8 +3145,17 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { ****************************************************************************** */ +/** + * Add TLS on an interface + * + * @v xfer Data transfer interface + * @v name Host name + * @v root Root of trust (or NULL to use default) + * @v key Private key (or NULL to use default) + * @ret rc Return status code + */ int add_tls ( struct interface *xfer, const char *name, - struct interface **next ) { + struct x509_root *root, struct private_key *key ) { struct tls_connection *tls; int rc; @@ -3107,6 +3173,8 @@ int add_tls ( struct interface *xfer, const char *name, intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt ); process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt ); + tls->key = privkey_get ( key ? key : &private_key ); + tls->root = x509_root_get ( root ? root : &root_certificates ); tls->version = TLS_VERSION_TLS_1_2; tls_clear_cipher ( tls, &tls->tx_cipherspec ); tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); @@ -3133,8 +3201,7 @@ int add_tls ( struct interface *xfer, const char *name, tls_restart ( tls ); /* Attach to parent interface, mortalise self, and return */ - intf_plug_plug ( &tls->plainstream, xfer ); - *next = &tls->cipherstream; + intf_insert ( xfer, &tls->plainstream, &tls->cipherstream ); ref_put ( &tls->refcnt ); return 0; diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index 3a3666c9a..4ebd38bbb 100644 --- a/src/net/udp/dhcp.c +++ b/src/net/udp/dhcp.c @@ -451,17 +451,6 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp, static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) { unsigned long elapsed = ( currticks() - dhcp->start ); - /* If link is blocked, defer DHCP discovery (and reset timeout) */ - if ( netdev_link_blocked ( dhcp->netdev ) && - ( dhcp->count <= DHCP_DISC_MAX_DEFERRALS ) ) { - DBGC ( dhcp, "DHCP %p deferring discovery\n", dhcp ); - dhcp->start = currticks(); - start_timer_fixed ( &dhcp->timer, - ( DHCP_DISC_START_TIMEOUT_SEC * - TICKS_PER_SEC ) ); - return; - } - /* Give up waiting for ProxyDHCP before we reach the failure point */ if ( dhcp->offer.s_addr && ( elapsed > DHCP_DISC_PROXY_TIMEOUT_SEC * TICKS_PER_SEC ) ) { @@ -469,8 +458,18 @@ static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) { return; } - /* Otherwise, retransmit current packet */ + /* Retransmit current packet */ dhcp_tx ( dhcp ); + + /* If link is blocked, defer DHCP discovery timeout */ + if ( netdev_link_blocked ( dhcp->netdev ) && + ( dhcp->count <= DHCP_DISC_MAX_DEFERRALS ) ) { + DBGC ( dhcp, "DHCP %p deferring discovery timeout\n", dhcp ); + dhcp->start = currticks(); + start_timer_fixed ( &dhcp->timer, + ( DHCP_DISC_START_TIMEOUT_SEC * + TICKS_PER_SEC ) ); + } } /** DHCP discovery state operations */ diff --git a/src/net/udp/dns.c b/src/net/udp/dns.c index f23e10dcc..e5579174e 100644 --- a/src/net/udp/dns.c +++ b/src/net/udp/dns.c @@ -1211,7 +1211,7 @@ static int apply_dns_settings ( void ) { /* Fetch DNS server address */ apply_dns_servers(); - if ( DBG_LOG && ( dns_count != 0 ) ) { + if ( DBG_EXTRA && ( dns_count != 0 ) ) { union { struct sockaddr sa; struct sockaddr_in sin; @@ -1219,37 +1219,37 @@ static int apply_dns_settings ( void ) { } u; unsigned int i; - DBGC ( dbgcol, "DNS servers:" ); + DBGC2 ( dbgcol, "DNS servers:" ); for ( i = 0 ; i < dns6.count ; i++ ) { u.sin6.sin6_family = AF_INET6; memcpy ( &u.sin6.sin6_addr, &dns6.in6[i], sizeof ( u.sin6.sin6_addr ) ); - DBGC ( dbgcol, " %s", sock_ntoa ( &u.sa ) ); + DBGC2 ( dbgcol, " %s", sock_ntoa ( &u.sa ) ); } for ( i = 0 ; i < dns4.count ; i++ ) { u.sin.sin_family = AF_INET; u.sin.sin_addr = dns4.in[i]; - DBGC ( dbgcol, " %s", sock_ntoa ( &u.sa ) ); + DBGC2 ( dbgcol, " %s", sock_ntoa ( &u.sa ) ); } - DBGC ( dbgcol, "\n" ); + DBGC2 ( dbgcol, "\n" ); } /* Fetch DNS search list */ apply_dns_search(); - if ( DBG_LOG && ( dns_search.len != 0 ) ) { + if ( DBG_EXTRA && ( dns_search.len != 0 ) ) { struct dns_name name; int offset; - DBGC ( dbgcol, "DNS search list:" ); + DBGC2 ( dbgcol, "DNS search list:" ); memcpy ( &name, &dns_search, sizeof ( name ) ); while ( name.offset != name.len ) { - DBGC ( dbgcol, " %s", dns_name ( &name ) ); + DBGC2 ( dbgcol, " %s", dns_name ( &name ) ); offset = dns_skip_search ( &name ); if ( offset < 0 ) break; name.offset = offset; } - DBGC ( dbgcol, "\n" ); + DBGC2 ( dbgcol, "\n" ); } return 0; diff --git a/src/net/udp/tftp.c b/src/net/udp/tftp.c index a0dac1ec5..3073e682f 100644 --- a/src/net/udp/tftp.c +++ b/src/net/udp/tftp.c @@ -43,6 +43,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/settings.h> #include <ipxe/dhcp.h> #include <ipxe/uri.h> +#include <ipxe/profile.h> #include <ipxe/tftp.h> /** @file @@ -158,6 +159,14 @@ enum { /** Maximum number of MTFTP open requests before falling back to TFTP */ #define MTFTP_MAX_TIMEOUTS 3 +/** Client profiler */ +static struct profiler tftp_client_profiler __profiler = + { .name = "tftp.client" }; + +/** Server profiler */ +static struct profiler tftp_server_profiler __profiler = + { .name = "tftp.server" }; + /** * Free TFTP request * @@ -802,6 +811,10 @@ static int tftp_rx_data ( struct tftp_request *tftp, } block += ( ntohs ( data->block ) - 1 ); + /* Stop profiling server turnaround if applicable */ + if ( block ) + profile_stop ( &tftp_server_profiler ); + /* Extract data */ offset = ( block * tftp->blksize ); iob_pull ( iobuf, sizeof ( *data ) ); @@ -834,6 +847,12 @@ static int tftp_rx_data ( struct tftp_request *tftp, /* Acknowledge block */ tftp_send_packet ( tftp ); + /* Stop profiling client turnaround */ + profile_stop ( &tftp_client_profiler ); + + /* Start profiling server turnaround */ + profile_start ( &tftp_server_profiler ); + /* If all blocks have been received, finish. */ if ( bitmap_full ( &tftp->bitmap ) ) tftp_done ( tftp, 0 ); @@ -906,7 +925,10 @@ static int tftp_rx ( struct tftp_request *tftp, struct tftp_common *common = iobuf->data; size_t len = iob_len ( iobuf ); int rc = -EINVAL; - + + /* Start profiling client turnaround */ + profile_start ( &tftp_client_profiler ); + /* Sanity checks */ if ( len < sizeof ( *common ) ) { DBGC ( tftp, "TFTP %p received underlength packet length " diff --git a/src/net/validator.c b/src/net/validator.c index f6b03ff41..693d4464b 100644 --- a/src/net/validator.c +++ b/src/net/validator.c @@ -73,6 +73,8 @@ struct validator { /** Process */ struct process process; + /** Root of trust (or NULL to use default) */ + struct x509_root *root; /** X.509 certificate chain */ struct x509_chain *chain; /** OCSP check */ @@ -114,6 +116,7 @@ static void validator_free ( struct refcnt *refcnt ) { DBGC2 ( validator, "VALIDATOR %p \"%s\" freed\n", validator, validator_name ( validator ) ); + x509_root_put ( validator->root ); x509_chain_put ( validator->chain ); ocsp_put ( validator->ocsp ); xferbuf_free ( &validator->buffer ); @@ -554,7 +557,7 @@ static void validator_step ( struct validator *validator ) { */ now = time ( NULL ); if ( ( rc = x509_validate_chain ( validator->chain, now, NULL, - NULL ) ) == 0 ) { + validator->root ) ) == 0 ) { DBGC ( validator, "VALIDATOR %p \"%s\" validated\n", validator, validator_name ( validator ) ); validator_finished ( validator, 0 ); @@ -569,7 +572,7 @@ static void validator_step ( struct validator *validator ) { issuer = link->cert; if ( ! cert ) continue; - if ( ! x509_is_valid ( issuer ) ) + if ( ! x509_is_valid ( issuer, validator->root ) ) continue; /* The issuer is valid, but this certificate is not * yet valid. If OCSP is applicable, start it. @@ -621,9 +624,11 @@ static struct process_descriptor validator_process_desc = * * @v job Job control interface * @v chain X.509 certificate chain + * @v root Root of trust, or NULL to use default * @ret rc Return status code */ -int create_validator ( struct interface *job, struct x509_chain *chain ) { +int create_validator ( struct interface *job, struct x509_chain *chain, + struct x509_root *root ) { struct validator *validator; int rc; @@ -646,6 +651,7 @@ int create_validator ( struct interface *job, struct x509_chain *chain ) { &validator->refcnt ); process_init ( &validator->process, &validator_process_desc, &validator->refcnt ); + validator->root = x509_root_get ( root ); validator->chain = x509_chain_get ( chain ); xferbuf_malloc_init ( &validator->buffer ); |
