summaryrefslogtreecommitdiff
path: root/gpxe/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/net')
-rw-r--r--gpxe/src/net/aoe.c15
-rw-r--r--gpxe/src/net/ethernet.c60
-rw-r--r--gpxe/src/net/infiniband.c316
-rw-r--r--gpxe/src/net/ipv4.c15
-rw-r--r--gpxe/src/net/netdevice.c62
-rw-r--r--gpxe/src/net/retry.c12
-rw-r--r--gpxe/src/net/tcp/ftp.c61
-rw-r--r--gpxe/src/net/tls.c37
-rw-r--r--gpxe/src/net/udp/dhcp.c2
-rw-r--r--gpxe/src/net/udp/tftp.c23
10 files changed, 394 insertions, 209 deletions
diff --git a/gpxe/src/net/aoe.c b/gpxe/src/net/aoe.c
index e3f84e5a..ec3814bf 100644
--- a/gpxe/src/net/aoe.c
+++ b/gpxe/src/net/aoe.c
@@ -94,6 +94,13 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
return -ENETUNREACH;
}
+ /* If we are transmitting anything that requires a response,
+ * start the retransmission timer. Do this before attempting
+ * to allocate the I/O buffer, in case allocation itself
+ * fails.
+ */
+ start_timer ( &aoe->timer );
+
/* Calculate count and data_out_len for this subcommand */
count = command->cb.count.native;
if ( count > AOE_MAX_COUNT )
@@ -101,8 +108,8 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
data_out_len = ( command->data_out ? ( count * ATA_SECTOR_SIZE ) : 0 );
/* Create outgoing I/O buffer */
- iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) +
- data_out_len );
+ iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) +
+ sizeof ( *aoecmd ) + data_out_len );
if ( ! iobuf )
return -ENOMEM;
iob_reserve ( iobuf, ETH_HLEN );
@@ -133,7 +140,6 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
aoe->command_offset, data_out_len );
/* Send packet */
- start_timer ( &aoe->timer );
return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target );
}
@@ -231,7 +237,8 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
* @ret rc Return status code
*
*/
-static int aoe_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused,
+static int aoe_rx ( struct io_buffer *iobuf,
+ struct net_device *netdev __unused,
const void *ll_source ) {
struct aoehdr *aoehdr = iobuf->data;
unsigned int len = iob_len ( iobuf );
diff --git a/gpxe/src/net/ethernet.c b/gpxe/src/net/ethernet.c
index 7b1c496f..3b289705 100644
--- a/gpxe/src/net/ethernet.c
+++ b/gpxe/src/net/ethernet.c
@@ -24,6 +24,7 @@
#include <assert.h>
#include <gpxe/if_arp.h>
#include <gpxe/if_ether.h>
+#include <gpxe/in.h>
#include <gpxe/netdevice.h>
#include <gpxe/iobuf.h>
#include <gpxe/ethernet.h>
@@ -41,19 +42,19 @@ static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
* Add Ethernet link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_protocol Network-layer protocol
* @v ll_dest Link-layer destination address
+ * @v ll_source Source link-layer address
+ * @v net_proto Network-layer protocol, in network-byte order
+ * @ret rc Return status code
*/
-static int eth_push ( struct io_buffer *iobuf, struct net_device *netdev,
- struct net_protocol *net_protocol,
- const void *ll_dest ) {
+static int eth_push ( struct io_buffer *iobuf, const void *ll_dest,
+ const void *ll_source, uint16_t net_proto ) {
struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) );
/* Build Ethernet header */
memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN );
- memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
- ethhdr->h_protocol = net_protocol->net_proto;
+ memcpy ( ethhdr->h_source, ll_source, ETH_ALEN );
+ ethhdr->h_protocol = net_proto;
return 0;
}
@@ -62,14 +63,13 @@ static int eth_push ( struct io_buffer *iobuf, struct net_device *netdev,
* Remove Ethernet link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_proto Network-layer protocol, in network-byte order
- * @v ll_source Source link-layer address
+ * @ret ll_dest Link-layer destination address
+ * @ret ll_source Source link-layer address
+ * @ret net_proto Network-layer protocol, in network-byte order
* @ret rc Return status code
*/
-static int eth_pull ( struct io_buffer *iobuf,
- struct net_device *netdev __unused,
- uint16_t *net_proto, const void **ll_source ) {
+static int eth_pull ( struct io_buffer *iobuf, const void **ll_dest,
+ const void **ll_source, uint16_t *net_proto ) {
struct ethhdr *ethhdr = iobuf->data;
/* Sanity check */
@@ -83,8 +83,9 @@ static int eth_pull ( struct io_buffer *iobuf,
iob_pull ( iobuf, sizeof ( *ethhdr ) );
/* Fill in required fields */
- *net_proto = ethhdr->h_protocol;
+ *ll_dest = ethhdr->h_dest;
*ll_source = ethhdr->h_source;
+ *net_proto = ethhdr->h_protocol;
return 0;
}
@@ -92,8 +93,8 @@ static int eth_pull ( struct io_buffer *iobuf,
/**
* Transcribe Ethernet address
*
- * @v ll_addr Link-layer address
- * @ret string Link-layer address in human-readable format
+ * @v ll_addr Link-layer address
+ * @ret string Link-layer address in human-readable format
*/
const char * eth_ntoa ( const void *ll_addr ) {
static char buf[18]; /* "00:00:00:00:00:00" */
@@ -105,6 +106,32 @@ const char * eth_ntoa ( const void *ll_addr ) {
return buf;
}
+/**
+ * Hash multicast address
+ *
+ * @v af Address family
+ * @v net_addr Network-layer address
+ * @v ll_addr Link-layer address to fill in
+ * @ret rc Return status code
+ */
+static int eth_mc_hash ( unsigned int af, const void *net_addr,
+ void *ll_addr ) {
+ const uint8_t *net_addr_bytes = net_addr;
+ uint8_t *ll_addr_bytes = ll_addr;
+
+ switch ( af ) {
+ case AF_INET:
+ ll_addr_bytes[0] = 0x01;
+ ll_addr_bytes[1] = 0x00;
+ ll_addr_bytes[2] = 0x5e;
+ ll_addr_bytes[3] = net_addr_bytes[1] & 0x7f;
+ ll_addr_bytes[4] = net_addr_bytes[2];
+ ll_addr_bytes[5] = net_addr_bytes[3];
+ default:
+ return -ENOTSUP;
+ }
+}
+
/** Ethernet protocol */
struct ll_protocol ethernet_protocol __ll_protocol = {
.name = "Ethernet",
@@ -115,4 +142,5 @@ struct ll_protocol ethernet_protocol __ll_protocol = {
.push = eth_push,
.pull = eth_pull,
.ntoa = eth_ntoa,
+ .mc_hash = eth_mc_hash,
};
diff --git a/gpxe/src/net/infiniband.c b/gpxe/src/net/infiniband.c
index ab76742e..fb6fca7d 100644
--- a/gpxe/src/net/infiniband.c
+++ b/gpxe/src/net/infiniband.c
@@ -46,10 +46,12 @@ struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
*
* @v ibdev Infiniband device
* @v num_cqes Number of completion queue entries
+ * @v op Completion queue operations
* @ret cq New completion queue
*/
-struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
- unsigned int num_cqes ) {
+struct ib_completion_queue *
+ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
+ struct ib_completion_queue_operations *op ) {
struct ib_completion_queue *cq;
int rc;
@@ -58,22 +60,28 @@ struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
/* Allocate and initialise data structure */
cq = zalloc ( sizeof ( *cq ) );
if ( ! cq )
- return NULL;
+ goto err_alloc_cq;
cq->num_cqes = num_cqes;
INIT_LIST_HEAD ( &cq->work_queues );
+ cq->op = op;
/* Perform device-specific initialisation and get CQN */
if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
DBGC ( ibdev, "IBDEV %p could not initialise completion "
"queue: %s\n", ibdev, strerror ( rc ) );
- free ( cq );
- return NULL;
+ goto err_dev_create_cq;
}
DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
"with CQN %#lx\n", ibdev, num_cqes, cq,
ib_cq_get_drvdata ( cq ), cq->cqn );
return cq;
+
+ ibdev->op->destroy_cq ( ibdev, cq );
+ err_dev_create_cq:
+ free ( cq );
+ err_alloc_cq:
+ return NULL;
}
/**
@@ -120,7 +128,9 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
qp = zalloc ( total_size );
if ( ! qp )
- return NULL;
+ goto err_alloc_qp;
+ qp->ibdev = ibdev;
+ list_add ( &qp->list, &ibdev->qps );
qp->qkey = qkey;
qp->send.qp = qp;
qp->send.is_send = 1;
@@ -134,15 +144,13 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
qp->recv.num_wqes = num_recv_wqes;
qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
+ INIT_LIST_HEAD ( &qp->mgids );
/* Perform device-specific initialisation and get QPN */
if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
"%s\n", ibdev, strerror ( rc ) );
- list_del ( &qp->send.list );
- list_del ( &qp->recv.list );
- free ( qp );
- return NULL;
+ goto err_dev_create_qp;
}
DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
@@ -154,6 +162,15 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
( ( ( void * ) qp ) + total_size ) );
return qp;
+
+ ibdev->op->destroy_qp ( ibdev, qp );
+ err_dev_create_qp:
+ list_del ( &qp->send.list );
+ list_del ( &qp->recv.list );
+ list_del ( &qp->list );
+ free ( qp );
+ err_alloc_qp:
+ return NULL;
}
/**
@@ -190,15 +207,80 @@ int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp,
* @v qp Queue pair
*/
void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
+ struct io_buffer *iobuf;
+ unsigned int i;
+
DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
ibdev, qp->qpn );
+
+ assert ( list_empty ( &qp->mgids ) );
+
+ /* Perform device-specific destruction */
ibdev->op->destroy_qp ( ibdev, qp );
+
+ /* Complete any remaining I/O buffers with errors */
+ for ( i = 0 ; i < qp->send.num_wqes ; i++ ) {
+ if ( ( iobuf = qp->send.iobufs[i] ) != NULL )
+ ib_complete_send ( ibdev, qp, iobuf, -ECANCELED );
+ }
+ for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
+ if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) {
+ ib_complete_recv ( ibdev, qp, NULL, iobuf,
+ -ECANCELED );
+ }
+ }
+
+ /* Remove work queues from completion queue */
list_del ( &qp->send.list );
list_del ( &qp->recv.list );
+
+ /* Free QP */
+ list_del ( &qp->list );
free ( qp );
}
/**
+ * Find queue pair by QPN
+ *
+ * @v ibdev Infiniband device
+ * @v qpn Queue pair number
+ * @ret qp Queue pair, or NULL
+ */
+struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
+ unsigned long qpn ) {
+ struct ib_queue_pair *qp;
+
+ list_for_each_entry ( qp, &ibdev->qps, list ) {
+ if ( qp->qpn == qpn )
+ return qp;
+ }
+ return NULL;
+}
+
+/**
+ * Find queue pair by multicast GID
+ *
+ * @v ibdev Infiniband device
+ * @v gid Multicast GID
+ * @ret qp Queue pair, or NULL
+ */
+struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
+ struct ib_gid *gid ) {
+ struct ib_queue_pair *qp;
+ struct ib_multicast_gid *mgid;
+
+ list_for_each_entry ( qp, &ibdev->qps, list ) {
+ list_for_each_entry ( mgid, &qp->mgids, list ) {
+ if ( memcmp ( &mgid->gid, gid,
+ sizeof ( mgid->gid ) ) == 0 ) {
+ return qp;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
* Find work queue belonging to completion queue
*
* @v cq Completion queue
@@ -217,142 +299,158 @@ struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
return NULL;
}
-/***************************************************************************
- *
- * Management datagram operations
- *
- ***************************************************************************
- */
-
/**
- * Get port information
+ * Post send work queue entry
*
* @v ibdev Infiniband device
- * @v port_info Port information datagram to fill in
+ * @v qp Queue pair
+ * @v av Address vector
+ * @v iobuf I/O buffer
* @ret rc Return status code
*/
-static int ib_get_port_info ( struct ib_device *ibdev,
- struct ib_mad_port_info *port_info ) {
- struct ib_mad_hdr *hdr = &port_info->mad_hdr;
+int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf ) {
int rc;
- /* Construct MAD */
- memset ( port_info, 0, sizeof ( *port_info ) );
- hdr->base_version = IB_MGMT_BASE_VERSION;
- hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
- hdr->class_version = 1;
- hdr->method = IB_MGMT_METHOD_GET;
- hdr->attr_id = htons ( IB_SMP_ATTR_PORT_INFO );
- hdr->attr_mod = htonl ( ibdev->port );
-
- if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *port_info ) ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not get port info: %s\n",
- ibdev, strerror ( rc ) );
+ /* Check queue fill level */
+ if ( qp->send.fill >= qp->send.num_wqes ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n",
+ ibdev, qp->qpn );
+ return -ENOBUFS;
+ }
+
+ /* Post to hardware */
+ if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: "
+ "%s\n", ibdev, qp->qpn, strerror ( rc ) );
return rc;
}
+
+ qp->send.fill++;
return 0;
}
/**
- * Get GUID information
+ * Post receive work queue entry
*
* @v ibdev Infiniband device
- * @v guid_info GUID information datagram to fill in
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
* @ret rc Return status code
*/
-static int ib_get_guid_info ( struct ib_device *ibdev,
- struct ib_mad_guid_info *guid_info ) {
- struct ib_mad_hdr *hdr = &guid_info->mad_hdr;
+int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct io_buffer *iobuf ) {
int rc;
- /* Construct MAD */
- memset ( guid_info, 0, sizeof ( *guid_info ) );
- hdr->base_version = IB_MGMT_BASE_VERSION;
- hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
- hdr->class_version = 1;
- hdr->method = IB_MGMT_METHOD_GET;
- hdr->attr_id = htons ( IB_SMP_ATTR_GUID_INFO );
+ /* Check queue fill level */
+ if ( qp->recv.fill >= qp->recv.num_wqes ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n",
+ ibdev, qp->qpn );
+ return -ENOBUFS;
+ }
- if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *guid_info ) ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n",
- ibdev, strerror ( rc ) );
+ /* Post to hardware */
+ if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: "
+ "%s\n", ibdev, qp->qpn, strerror ( rc ) );
return rc;
}
+
+ qp->recv.fill++;
return 0;
}
/**
- * Get partition key table
+ * Complete send work queue entry
*
* @v ibdev Infiniband device
- * @v guid_info Partition key table datagram to fill in
- * @ret rc Return status code
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
*/
-static int ib_get_pkey_table ( struct ib_device *ibdev,
- struct ib_mad_pkey_table *pkey_table ) {
- struct ib_mad_hdr *hdr = &pkey_table->mad_hdr;
- int rc;
-
- /* Construct MAD */
- memset ( pkey_table, 0, sizeof ( *pkey_table ) );
- hdr->base_version = IB_MGMT_BASE_VERSION;
- hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
- hdr->class_version = 1;
- hdr->method = IB_MGMT_METHOD_GET;
- hdr->attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE );
+void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct io_buffer *iobuf, int rc ) {
+ qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc );
+ qp->send.fill--;
+}
- if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *pkey_table ) ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n",
- ibdev, strerror ( rc ) );
- return rc;
- }
- return 0;
+/**
+ * Complete receive work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v av Address vector
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc ) {
+ qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc );
+ qp->recv.fill--;
}
/**
- * Get MAD parameters
+ * Attach to multicast group
*
* @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v gid Multicast GID
* @ret rc Return status code
*/
-static int ib_get_mad_params ( struct ib_device *ibdev ) {
- union {
- /* This union exists just to save stack space */
- struct ib_mad_port_info port_info;
- struct ib_mad_guid_info guid_info;
- struct ib_mad_pkey_table pkey_table;
- } u;
+int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_gid *gid ) {
+ struct ib_multicast_gid *mgid;
int rc;
- /* Port info gives us the link state, the first half of the
- * port GID and the SM LID.
- */
- if ( ( rc = ib_get_port_info ( ibdev, &u.port_info ) ) != 0 )
- return rc;
- ibdev->link_up = ( ( u.port_info.port_state__link_speed_supported
- & 0xf ) == 4 );
- memcpy ( &ibdev->port_gid.u.bytes[0], u.port_info.gid_prefix, 8 );
- ibdev->sm_lid = ntohs ( u.port_info.mastersm_lid );
+ /* Add to software multicast GID list */
+ mgid = zalloc ( sizeof ( *mgid ) );
+ if ( ! mgid ) {
+ rc = -ENOMEM;
+ goto err_alloc_mgid;
+ }
+ memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) );
+ list_add ( &mgid->list, &qp->mgids );
- /* GUID info gives us the second half of the port GID */
- if ( ( rc = ib_get_guid_info ( ibdev, &u.guid_info ) ) != 0 )
- return rc;
- memcpy ( &ibdev->port_gid.u.bytes[8], u.guid_info.gid_local, 8 );
+ /* Add to hardware multicast GID list */
+ if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 )
+ goto err_dev_mcast_attach;
- /* Get partition key */
- if ( ( rc = ib_get_pkey_table ( ibdev, &u.pkey_table ) ) != 0 )
- return rc;
- ibdev->pkey = ntohs ( u.pkey_table.pkey[0][0] );
+ return 0;
- DBGC ( ibdev, "IBDEV %p port GID is %08lx:%08lx:%08lx:%08lx\n",
- ibdev, htonl ( ibdev->port_gid.u.dwords[0] ),
- htonl ( ibdev->port_gid.u.dwords[1] ),
- htonl ( ibdev->port_gid.u.dwords[2] ),
- htonl ( ibdev->port_gid.u.dwords[3] ) );
+ err_dev_mcast_attach:
+ list_del ( &mgid->list );
+ free ( mgid );
+ err_alloc_mgid:
+ return rc;
+}
- return 0;
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v gid Multicast GID
+ */
+void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_gid *gid ) {
+ struct ib_multicast_gid *mgid;
+
+ /* Remove from hardware multicast GID list */
+ ibdev->op->mcast_detach ( ibdev, qp, gid );
+
+ /* Remove from software multicast GID list */
+ list_for_each_entry ( mgid, &qp->mgids, list ) {
+ if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) {
+ list_del ( &mgid->list );
+ free ( mgid );
+ break;
+ }
+ }
}
+
/***************************************************************************
*
* Event queues
@@ -366,14 +464,6 @@ static int ib_get_mad_params ( struct ib_device *ibdev ) {
* @v ibdev Infiniband device
*/
void ib_link_state_changed ( struct ib_device *ibdev ) {
- int rc;
-
- /* Update MAD parameters */
- if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not update MAD parameters: %s\n",
- ibdev, strerror ( rc ) );
- return;
- }
/* Notify IPoIB of link state change */
ipoib_link_state_changed ( ibdev );
@@ -420,6 +510,9 @@ struct ib_device * alloc_ibdev ( size_t priv_size ) {
if ( ibdev ) {
drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
ib_set_drvdata ( ibdev, drv_priv );
+ INIT_LIST_HEAD ( &ibdev->qps );
+ ibdev->lid = IB_LID_NONE;
+ ibdev->pkey = IB_PKEY_NONE;
}
return ibdev;
}
@@ -441,10 +534,6 @@ int register_ibdev ( struct ib_device *ibdev ) {
if ( ( rc = ib_open ( ibdev ) ) != 0 )
goto err_open;
- /* Get MAD parameters */
- if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 )
- goto err_get_mad_params;
-
/* Add IPoIB device */
if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) {
DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n",
@@ -457,7 +546,6 @@ int register_ibdev ( struct ib_device *ibdev ) {
return 0;
err_ipoib_probe:
- err_get_mad_params:
ib_close ( ibdev );
err_open:
list_del ( &ibdev->list );
diff --git a/gpxe/src/net/ipv4.c b/gpxe/src/net/ipv4.c
index 82a13c33..63dcca28 100644
--- a/gpxe/src/net/ipv4.c
+++ b/gpxe/src/net/ipv4.c
@@ -188,7 +188,7 @@ static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
free_iob ( iobuf );
/** Check if the fragment series is over */
- if ( !iphdr->frags & IP_MASK_MOREFRAGS ) {
+ if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) {
iobuf = fragbuf->frag_iob;
free_fragbuf ( fragbuf );
return iobuf;
@@ -266,7 +266,6 @@ static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
struct net_device *netdev, uint8_t *ll_dest ) {
struct ll_protocol *ll_protocol = netdev->ll_protocol;
- uint8_t *dest_bytes = ( ( uint8_t * ) &dest );
if ( dest.s_addr == INADDR_BROADCAST ) {
/* Broadcast address */
@@ -274,17 +273,7 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
ll_protocol->ll_addr_len );
return 0;
} else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) {
- /* Special case: IPv4 multicast over Ethernet. This
- * code may need to be generalised once we find out
- * what happens for other link layers.
- */
- ll_dest[0] = 0x01;
- ll_dest[1] = 0x00;
- ll_dest[2] = 0x5e;
- ll_dest[3] = dest_bytes[1] & 0x7f;
- ll_dest[4] = dest_bytes[2];
- ll_dest[5] = dest_bytes[3];
- return 0;
+ return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest );
} else {
/* Unicast address: resolve via ARP */
return arp_resolve ( netdev, &ipv4_protocol, &dest,
diff --git a/gpxe/src/net/netdevice.c b/gpxe/src/net/netdevice.c
index 3721b334..e8587a9d 100644
--- a/gpxe/src/net/netdevice.c
+++ b/gpxe/src/net/netdevice.c
@@ -46,6 +46,45 @@ static struct net_protocol net_protocols_end[0]
struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
/**
+ * Record network device statistic
+ *
+ * @v stats Network device statistics
+ * @v rc Status code
+ */
+static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
+ struct net_device_error *error;
+ struct net_device_error *least_common_error;
+ unsigned int i;
+
+ /* If this is not an error, just update the good counter */
+ if ( rc == 0 ) {
+ stats->good++;
+ return;
+ }
+
+ /* Update the bad counter */
+ stats->bad++;
+
+ /* Locate the appropriate error record */
+ least_common_error = &stats->errors[0];
+ for ( i = 0 ; i < ( sizeof ( stats->errors ) /
+ sizeof ( stats->errors[0] ) ) ; i++ ) {
+ error = &stats->errors[i];
+ /* Update matching record, if found */
+ if ( error->rc == rc ) {
+ error->count++;
+ return;
+ }
+ if ( error->count < least_common_error->count )
+ least_common_error = error;
+ }
+
+ /* Overwrite the least common error record */
+ least_common_error->rc = rc;
+ least_common_error->count = 1;
+}
+
+/**
* Transmit raw packet via network device
*
* @v netdev Network device
@@ -91,12 +130,11 @@ void netdev_tx_complete_err ( struct net_device *netdev,
struct io_buffer *iobuf, int rc ) {
/* Update statistics counter */
+ netdev_record_stat ( &netdev->tx_stats, rc );
if ( rc == 0 ) {
- netdev->stats.tx_ok++;
DBGC ( netdev, "NETDEV %p transmission %p complete\n",
netdev, iobuf );
} else {
- netdev->stats.tx_err++;
DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
netdev, iobuf, strerror ( rc ) );
}
@@ -158,7 +196,7 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
list_add_tail ( &iobuf->list, &netdev->rx_queue );
/* Update statistics counter */
- netdev->stats.rx_ok++;
+ netdev_record_stat ( &netdev->rx_stats, 0 );
}
/**
@@ -183,7 +221,7 @@ void netdev_rx_err ( struct net_device *netdev,
free_iob ( iobuf );
/* Update statistics counter */
- netdev->stats.rx_err++;
+ netdev_record_stat ( &netdev->rx_stats, rc );
}
/**
@@ -268,7 +306,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
INIT_LIST_HEAD ( &netdev->rx_queue );
settings_init ( netdev_settings ( netdev ),
&netdev_settings_operations, &netdev->refcnt,
- netdev->name );
+ netdev->name, 0 );
netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
}
return netdev;
@@ -439,6 +477,7 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type,
*/
int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
struct net_protocol *net_protocol, const void *ll_dest ) {
+ struct ll_protocol *ll_protocol = netdev->ll_protocol;
int rc;
/* Force a poll on the netdevice to (potentially) clear any
@@ -449,8 +488,8 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
netdev_poll ( netdev );
/* Add link-layer header */
- if ( ( rc = netdev->ll_protocol->push ( iobuf, netdev, net_protocol,
- ll_dest ) ) != 0 ) {
+ if ( ( rc = ll_protocol->push ( iobuf, ll_dest, netdev->ll_addr,
+ net_protocol->net_proto ) ) != 0 ) {
free_iob ( iobuf );
return rc;
}
@@ -495,8 +534,9 @@ static void net_step ( struct process *process __unused ) {
struct net_device *netdev;
struct io_buffer *iobuf;
struct ll_protocol *ll_protocol;
- uint16_t net_proto;
+ const void *ll_dest;
const void *ll_source;
+ uint16_t net_proto;
int rc;
/* Poll and process each network device */
@@ -519,9 +559,9 @@ static void net_step ( struct process *process __unused ) {
/* Remove link-layer header */
ll_protocol = netdev->ll_protocol;
- if ( ( rc = ll_protocol->pull ( iobuf, netdev,
- &net_proto,
- &ll_source ) ) != 0 ) {
+ if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest,
+ &ll_source,
+ &net_proto ) ) != 0 ) {
free_iob ( iobuf );
continue;
}
diff --git a/gpxe/src/net/retry.c b/gpxe/src/net/retry.c
index 2a645c97..cd793a7f 100644
--- a/gpxe/src/net/retry.c
+++ b/gpxe/src/net/retry.c
@@ -55,9 +55,10 @@ static LIST_HEAD ( timers );
* be stopped and the timer's callback function will be called.
*/
void start_timer ( struct retry_timer *timer ) {
- if ( ! timer_running ( timer ) )
+ if ( ! timer->running )
list_add ( &timer->list, &timers );
timer->start = currticks();
+ timer->running = 1;
/* 0 means "use default timeout" */
if ( timer->min_timeout == 0 )
@@ -82,6 +83,8 @@ void start_timer ( struct retry_timer *timer ) {
void start_timer_fixed ( struct retry_timer *timer, unsigned long timeout ) {
start_timer ( timer );
timer->timeout = timeout;
+ DBG2 ( "Timer %p expiry time changed to %ld\n",
+ timer, ( timer->start + timer->timeout ) );
}
/**
@@ -97,12 +100,12 @@ void stop_timer ( struct retry_timer *timer ) {
unsigned long runtime;
/* If timer was already stopped, do nothing */
- if ( ! timer_running ( timer ) )
+ if ( ! timer->running )
return;
list_del ( &timer->list );
runtime = ( now - timer->start );
- timer->start = 0;
+ timer->running = 0;
DBG2 ( "Timer %p stopped at time %ld (ran for %ld)\n",
timer, now, runtime );
@@ -144,8 +147,9 @@ static void timer_expired ( struct retry_timer *timer ) {
/* Stop timer without performing RTT calculations */
DBG2 ( "Timer %p stopped at time %ld on expiry\n",
timer, currticks() );
+ assert ( timer->running );
list_del ( &timer->list );
- timer->start = 0;
+ timer->running = 0;
timer->count++;
/* Back off the timeout value */
diff --git a/gpxe/src/net/tcp/ftp.c b/gpxe/src/net/tcp/ftp.c
index 3b88f7b6..82dc19ca 100644
--- a/gpxe/src/net/tcp/ftp.c
+++ b/gpxe/src/net/tcp/ftp.c
@@ -109,23 +109,39 @@ static void ftp_done ( struct ftp_request *ftp, int rc ) {
*
*/
+/** An FTP control channel string */
+struct ftp_control_string {
+ /** Literal portion */
+ const char *literal;
+ /** Variable portion
+ *
+ * @v ftp FTP request
+ * @ret string Variable portion of string
+ */
+ const char * ( *variable ) ( struct ftp_request *ftp );
+};
+
/**
- * FTP control channel strings
+ * Retrieve FTP pathname
*
- * These are used as printf() format strings. Since only one of them
- * (RETR) takes an argument, we always supply that argument to the
- * snprintf() call.
+ * @v ftp FTP request
+ * @ret path FTP pathname
*/
-static const char * ftp_strings[] = {
- [FTP_CONNECT] = NULL,
- [FTP_USER] = "USER anonymous\r\n",
- [FTP_PASS] = "PASS etherboot@etherboot.org\r\n",
- [FTP_TYPE] = "TYPE I\r\n",
- [FTP_PASV] = "PASV\r\n",
- [FTP_RETR] = "RETR %s\r\n",
- [FTP_WAIT] = NULL,
- [FTP_QUIT] = "QUIT\r\n",
- [FTP_DONE] = NULL,
+static const char * ftp_uri_path ( struct ftp_request *ftp ) {
+ return ftp->uri->path;
+}
+
+/** FTP control channel strings */
+static struct ftp_control_string ftp_strings[] = {
+ [FTP_CONNECT] = { NULL, NULL },
+ [FTP_USER] = { "USER anonymous", NULL },
+ [FTP_PASS] = { "PASS etherboot@etherboot.org", NULL },
+ [FTP_TYPE] = { "TYPE I", NULL },
+ [FTP_PASV] = { "PASV", NULL },
+ [FTP_RETR] = { "RETR ", ftp_uri_path },
+ [FTP_WAIT] = { NULL, NULL },
+ [FTP_QUIT] = { "QUIT", NULL },
+ [FTP_DONE] = { NULL, NULL },
};
/**
@@ -178,18 +194,23 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) {
*
*/
static void ftp_next_state ( struct ftp_request *ftp ) {
+ struct ftp_control_string *ftp_string;
+ const char *literal;
+ const char *variable;
/* Move to next state */
if ( ftp->state < FTP_DONE )
ftp->state++;
/* Send control string if needed */
- if ( ftp_strings[ftp->state] != NULL ) {
- DBGC ( ftp, "FTP %p sending ", ftp );
- DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path );
- xfer_printf ( &ftp->control, ftp_strings[ftp->state],
- ftp->uri->path );
- }
+ ftp_string = &ftp_strings[ftp->state];
+ literal = ftp_string->literal;
+ variable = ( ftp_string->variable ?
+ ftp_string->variable ( ftp ) : "" );
+ if ( literal ) {
+ DBGC ( ftp, "FTP %p sending %s%s\n", ftp, literal, variable );
+ xfer_printf ( &ftp->control, "%s%s\r\n", literal, variable );
+ }
}
/**
diff --git a/gpxe/src/net/tls.c b/gpxe/src/net/tls.c
index 834686fb..fa4b58d4 100644
--- a/gpxe/src/net/tls.c
+++ b/gpxe/src/net/tls.c
@@ -270,16 +270,16 @@ static void tls_generate_master_secret ( struct tls_session *tls ) {
DBGC_HD ( tls, &tls->pre_master_secret,
sizeof ( tls->pre_master_secret ) );
DBGC ( tls, "TLS %p client random bytes:\n", tls );
- DBGC_HD ( tls, &tls->client_random, sizeof ( tls->server_random ) );
+ DBGC_HD ( tls, &tls->client_random, sizeof ( tls->client_random ) );
DBGC ( tls, "TLS %p server random bytes:\n", tls );
DBGC_HD ( tls, &tls->server_random, sizeof ( tls->server_random ) );
- tls_prf_label ( tls, tls->pre_master_secret,
+ tls_prf_label ( tls, &tls->pre_master_secret,
sizeof ( tls->pre_master_secret ),
- tls->master_secret, sizeof ( tls->master_secret ),
+ &tls->master_secret, sizeof ( tls->master_secret ),
"master secret",
- tls->client_random, sizeof ( tls->client_random ),
- tls->server_random, sizeof ( tls->server_random ) );
+ &tls->client_random, sizeof ( tls->client_random ),
+ &tls->server_random, sizeof ( tls->server_random ) );
DBGC ( tls, "TLS %p generated master secret:\n", tls );
DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) );
@@ -304,10 +304,10 @@ static int tls_generate_keys ( struct tls_session *tls ) {
int rc;
/* Generate key block */
- tls_prf_label ( tls, tls->master_secret, sizeof ( tls->master_secret ),
+ tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
key_block, sizeof ( key_block ), "key expansion",
- tls->server_random, sizeof ( tls->server_random ),
- tls->client_random, sizeof ( tls->client_random ) );
+ &tls->server_random, sizeof ( tls->server_random ),
+ &tls->client_random, sizeof ( tls->client_random ) );
/* Split key block into portions */
key = key_block;
@@ -604,7 +604,7 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
htonl ( sizeof ( hello ) -
sizeof ( hello.type_length ) ) );
hello.version = htons ( TLS_VERSION_TLS_1_0 );
- memcpy ( &hello.random, tls->client_random, sizeof ( hello.random ) );
+ memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) );
hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) );
hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA );
hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA );
@@ -643,7 +643,7 @@ static int tls_send_client_key_exchange ( struct tls_session *tls ) {
sizeof ( tls->pre_master_secret ) );
DBGC_HD ( tls, tls->rsa_mod, tls->rsa_mod_len );
DBGC_HD ( tls, tls->rsa_pub_exp, tls->rsa_pub_exp_len );
- RSA_encrypt ( rsa_ctx, tls->pre_master_secret,
+ RSA_encrypt ( rsa_ctx, ( const uint8_t * ) &tls->pre_master_secret,
sizeof ( tls->pre_master_secret ),
key_xchg.encrypted_pre_master_secret, 0 );
DBGC ( tls, "RSA encrypt done. Ciphertext:\n" );
@@ -685,7 +685,7 @@ static int tls_send_finished ( struct tls_session *tls ) {
htonl ( sizeof ( finished ) -
sizeof ( finished.type_length ) ) );
tls_verify_handshake ( tls, digest );
- tls_prf_label ( tls, tls->master_secret, sizeof ( tls->master_secret ),
+ tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
finished.verify_data, sizeof ( finished.verify_data ),
"client finished", digest, sizeof ( digest ) );
@@ -802,7 +802,7 @@ static int tls_new_server_hello ( struct tls_session *tls,
}
/* Copy out server random bytes */
- memcpy ( tls->server_random, hello_a->random,
+ memcpy ( &tls->server_random, &hello_a->random,
sizeof ( tls->server_random ) );
/* Select cipher suite */
@@ -1710,13 +1710,12 @@ int add_tls ( struct xfer_interface *xfer, struct xfer_interface **next ) {
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
tls_clear_cipher ( tls, &tls->rx_cipherspec );
tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
- *( ( uint32_t * ) tls->client_random ) = 0; /* GMT Unix time */
- tls_generate_random ( ( tls->client_random + 4 ),
- ( sizeof ( tls->client_random ) - 4 ) );
- *( ( uint16_t * ) tls->pre_master_secret )
- = htons ( TLS_VERSION_TLS_1_0 );
- tls_generate_random ( ( tls->pre_master_secret + 2 ),
- ( sizeof ( tls->pre_master_secret ) - 2 ) );
+ tls->client_random.gmt_unix_time = 0;
+ tls_generate_random ( &tls->client_random.random,
+ ( sizeof ( tls->client_random.random ) ) );
+ tls->pre_master_secret.version = htons ( TLS_VERSION_TLS_1_0 );
+ tls_generate_random ( &tls->pre_master_secret.random,
+ ( sizeof ( tls->pre_master_secret.random ) ) );
digest_init ( &md5_algorithm, tls->handshake_md5_ctx );
digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx );
tls->tx_state = TLS_TX_CLIENT_HELLO;
diff --git a/gpxe/src/net/udp/dhcp.c b/gpxe/src/net/udp/dhcp.c
index ab751cd5..21347832 100644
--- a/gpxe/src/net/udp/dhcp.c
+++ b/gpxe/src/net/udp/dhcp.c
@@ -256,7 +256,7 @@ static struct dhcp_settings * dhcpset_create ( const struct dhcphdr *dhcphdr,
dhcppkt_init ( &dhcpset->dhcppkt, data, len );
settings_init ( &dhcpset->settings,
&dhcpset_settings_operations, &dhcpset->refcnt,
- DHCP_SETTINGS_NAME );
+ DHCP_SETTINGS_NAME, 0 );
}
return dhcpset;
}
diff --git a/gpxe/src/net/udp/tftp.c b/gpxe/src/net/udp/tftp.c
index 8fdb3714..b262b108 100644
--- a/gpxe/src/net/udp/tftp.c
+++ b/gpxe/src/net/udp/tftp.c
@@ -45,6 +45,15 @@
FEATURE ( FEATURE_PROTOCOL, "TFTP", DHCP_EB_FEATURE_TFTP, 1 );
+/* TFTP-specific error codes */
+#define ETFTP_INVALID_BLKSIZE EUNIQ_01
+#define ETFTP_INVALID_TSIZE EUNIQ_02
+#define ETFTP_MC_NO_PORT EUNIQ_03
+#define ETFTP_MC_NO_MC EUNIQ_04
+#define ETFTP_MC_INVALID_MC EUNIQ_05
+#define ETFTP_MC_INVALID_IP EUNIQ_06
+#define ETFTP_MC_INVALID_PORT EUNIQ_07
+
/**
* A TFTP request
*
@@ -504,7 +513,7 @@ static int tftp_process_blksize ( struct tftp_request *tftp,
if ( *end ) {
DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
tftp, value );
- return -EINVAL;
+ return -( EINVAL | ETFTP_INVALID_BLKSIZE );
}
DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
@@ -526,7 +535,7 @@ static int tftp_process_tsize ( struct tftp_request *tftp,
if ( *end ) {
DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
tftp, value );
- return -EINVAL;
+ return -( EINVAL | ETFTP_INVALID_TSIZE );
}
DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
@@ -560,13 +569,13 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
port = strchr ( addr, ',' );
if ( ! port ) {
DBGC ( tftp, "TFTP %p multicast missing port,mc\n", tftp );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_NO_PORT );
}
*(port++) = '\0';
mc = strchr ( port, ',' );
if ( ! mc ) {
DBGC ( tftp, "TFTP %p multicast missing mc\n", tftp );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_NO_MC );
}
*(mc++) = '\0';
@@ -575,7 +584,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
tftp->flags &= ~TFTP_FL_SEND_ACK;
if ( *mc_end ) {
DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_INVALID_MC );
}
DBGC ( tftp, "TFTP %p is%s the master client\n",
tftp, ( ( tftp->flags & TFTP_FL_SEND_ACK ) ? "" : " not" ) );
@@ -584,7 +593,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
if ( inet_aton ( addr, &socket.sin.sin_addr ) == 0 ) {
DBGC ( tftp, "TFTP %p multicast invalid IP address "
"%s\n", tftp, addr );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_INVALID_IP );
}
DBGC ( tftp, "TFTP %p multicast IP address %s\n",
tftp, inet_ntoa ( socket.sin.sin_addr ) );
@@ -592,7 +601,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
if ( *port_end ) {
DBGC ( tftp, "TFTP %p multicast invalid port %s\n",
tftp, port );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_INVALID_PORT );
}
DBGC ( tftp, "TFTP %p multicast port %d\n",
tftp, ntohs ( socket.sin.sin_port ) );