diff options
author | Michael Brown <mcb30@ipxe.org> | 2012-03-02 20:12:10 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2012-03-02 23:46:29 +0000 |
commit | d620606d3e8c913876a671990600c226788b71da (patch) | |
tree | e0dd768a5c50e0a01c9b9197821a0181b2b018c3 /src/net/ipv4.c | |
parent | 6324bd9389521c7e86384591f41eb78a81e9af47 (diff) | |
download | ipxe-d620606d3e8c913876a671990600c226788b71da.zip ipxe-d620606d3e8c913876a671990600c226788b71da.tar.gz ipxe-d620606d3e8c913876a671990600c226788b71da.tar.bz2 |
[arp] Maintain an ARP transmission queue
Allow packet transmission to be deferred pending successful ARP
resolution. This avoids the time spent waiting for a higher-level
protocol (e.g. TCP or TFTP) to attempt retransmission.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net/ipv4.c')
-rw-r--r-- | src/net/ipv4.c | 84 |
1 files changed, 38 insertions, 46 deletions
diff --git a/src/net/ipv4.c b/src/net/ipv4.c index 99c2580..08249d4 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -282,35 +282,6 @@ static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) { } /** - * Determine link-layer address - * - * @v dest IPv4 destination address - * @v src IPv4 source address - * @v netmask IPv4 subnet mask - * @v netdev Network device - * @v ll_dest Link-layer destination address buffer - * @ret rc Return status code - */ -static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, - struct in_addr netmask, struct net_device *netdev, - uint8_t *ll_dest ) { - struct ll_protocol *ll_protocol = netdev->ll_protocol; - - if ( ( ( dest.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0 ) { - /* Broadcast address */ - memcpy ( ll_dest, netdev->ll_broadcast, - ll_protocol->ll_addr_len ); - return 0; - } else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) { - return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest ); - } else { - /* Unicast address: resolve via ARP */ - return arp_resolve ( netdev, &ipv4_protocol, &dest, - &src, ll_dest ); - } -} - -/** * Transmit IP packet * * @v iobuf I/O buffer @@ -335,7 +306,8 @@ static int ipv4_tx ( struct io_buffer *iobuf, struct ipv4_miniroute *miniroute; struct in_addr next_hop; struct in_addr netmask = { .s_addr = 0 }; - uint8_t ll_dest[MAX_LL_ADDR_LEN]; + uint8_t ll_dest_buf[MAX_LL_ADDR_LEN]; + const void *ll_dest; int rc; /* Fill up the IP header, except source address */ @@ -373,16 +345,6 @@ static int ipv4_tx ( struct io_buffer *iobuf, ( ( netdev->rx_stats.bad & 0xf ) << 4 ) | ( ( netdev->rx_stats.good & 0xf ) << 0 ) ); - /* Determine link-layer destination address */ - if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netmask, netdev, - ll_dest ) ) != 0 ) { - DBGC ( sin_dest->sin_addr, "IPv4 has no link-layer address for " - "%s: %s\n", inet_ntoa ( next_hop ), strerror ( rc ) ); - /* Record error for diagnosis */ - netdev_tx_err ( netdev, iob_disown ( iobuf ), rc ); - goto err; - } - /* Fix up checksums */ if ( trans_csum ) *trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum ); @@ -395,12 +357,42 @@ static int ipv4_tx ( struct io_buffer *iobuf, iphdr->protocol, ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) ); - /* Hand off to link layer */ - if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest, - netdev->ll_addr ) ) != 0 ) { - DBGC ( sin_dest->sin_addr, "IPv4 could not transmit packet " - "via %s: %s\n", netdev->name, strerror ( rc ) ); - return rc; + /* Calculate link-layer destination address, if possible */ + if ( ( ( next_hop.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0){ + /* Broadcast address */ + ll_dest = netdev->ll_broadcast; + } else if ( IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) { + /* Multicast address */ + if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET, &next_hop, + ll_dest_buf ) ) !=0){ + DBGC ( sin_dest->sin_addr, "IPv4 could not hash " + "multicast %s: %s\n", + inet_ntoa ( next_hop ), strerror ( rc ) ); + return rc; + } + ll_dest = ll_dest_buf; + } else { + /* Unicast address */ + ll_dest = NULL; + } + + /* Hand off to link layer (via ARP if applicable) */ + if ( ll_dest ) { + if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest, + netdev->ll_addr ) ) != 0 ) { + DBGC ( sin_dest->sin_addr, "IPv4 could not transmit " + "packet via %s: %s\n", + netdev->name, strerror ( rc ) ); + return rc; + } + } else { + if ( ( rc = arp_tx ( iobuf, netdev, &ipv4_protocol, &next_hop, + &iphdr->src, netdev->ll_addr ) ) != 0 ) { + DBGC ( sin_dest->sin_addr, "IPv4 could not transmit " + "packet via %s: %s\n", + netdev->name, strerror ( rc ) ); + return rc; + } } return 0; |