diff options
Diffstat (limited to 'gpxe/src/net')
-rw-r--r-- | gpxe/src/net/aoe.c | 15 | ||||
-rw-r--r-- | gpxe/src/net/ethernet.c | 60 | ||||
-rw-r--r-- | gpxe/src/net/infiniband.c | 316 | ||||
-rw-r--r-- | gpxe/src/net/ipv4.c | 15 | ||||
-rw-r--r-- | gpxe/src/net/netdevice.c | 62 | ||||
-rw-r--r-- | gpxe/src/net/retry.c | 12 | ||||
-rw-r--r-- | gpxe/src/net/tcp/ftp.c | 61 | ||||
-rw-r--r-- | gpxe/src/net/tls.c | 37 | ||||
-rw-r--r-- | gpxe/src/net/udp/dhcp.c | 2 | ||||
-rw-r--r-- | gpxe/src/net/udp/tftp.c | 23 |
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 ) ); |