summaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/net')
-rw-r--r--src/net/80211/wpa.c25
-rw-r--r--src/net/aoe.c31
-rw-r--r--src/net/eap.c142
-rw-r--r--src/net/eapol.c139
-rw-r--r--src/net/eth_slow.c11
-rw-r--r--src/net/fcp.c28
-rw-r--r--src/net/infiniband.c20
-rw-r--r--src/net/infiniband/ib_sma.c2
-rw-r--r--src/net/infiniband/ib_srp.c35
-rw-r--r--src/net/ndp.c29
-rw-r--r--src/net/netdevice.c34
-rw-r--r--src/net/tcp/httpconn.c13
-rw-r--r--src/net/tcp/httpcore.c15
-rw-r--r--src/net/tcp/https.c14
-rw-r--r--src/net/tcp/iscsi.c2
-rw-r--r--src/net/tcp/syslogs.c29
-rw-r--r--src/net/tls.c143
-rw-r--r--src/net/udp/dhcp.c23
-rw-r--r--src/net/udp/dns.c18
-rw-r--r--src/net/udp/tftp.c24
-rw-r--r--src/net/validator.c12
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 );