From db67de6f31a062dc1995d4561be83cd51609d6c4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 4 Mar 2014 12:54:21 +0000 Subject: [PATCH] [tcpip] Provide tcpip_netdev() to determine the transmitting network device Provide the function tcpip_netdev() to allow external code to determine the transmitting network device for a given socket address. Signed-off-by: Michael Brown --- src/include/ipxe/tcpip.h | 8 ++++++ src/net/ipv4.c | 20 ++++++++++++++ src/net/ipv6.c | 20 ++++++++++++++ src/net/tcpip.c | 56 +++++++++++++++++++++++++++++++++------- 4 files changed, 94 insertions(+), 10 deletions(-) diff --git a/src/include/ipxe/tcpip.h b/src/include/ipxe/tcpip.h index f5ef4f04..d28689a1 100644 --- a/src/include/ipxe/tcpip.h +++ b/src/include/ipxe/tcpip.h @@ -116,6 +116,13 @@ struct tcpip_net_protocol { struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum ); + /** + * Determine transmitting network device + * + * @v st_dest Destination address + * @ret netdev Network device, or NULL + */ + struct net_device * ( * netdev ) ( struct sockaddr_tcpip *dest ); }; /** TCP/IP transport-layer protocol table */ @@ -140,6 +147,7 @@ extern int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip, struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum ); +extern struct net_device * tcpip_netdev ( struct sockaddr_tcpip *st_dest ); extern uint16_t generic_tcpip_continue_chksum ( uint16_t partial, const void *data, size_t len ); extern uint16_t tcpip_chksum ( const void *data, size_t len ); diff --git a/src/net/ipv4.c b/src/net/ipv4.c index d9a54ade..8bda5c86 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -137,6 +137,25 @@ static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) { return NULL; } +/** + * Determine transmitting network device + * + * @v st_dest Destination network-layer address + * @ret netdev Transmitting network device, or NULL + */ +static struct net_device * ipv4_netdev ( struct sockaddr_tcpip *st_dest ) { + struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest ); + struct in_addr dest = sin_dest->sin_addr; + struct ipv4_miniroute *miniroute; + + /* Find routing table entry */ + miniroute = ipv4_route ( &dest ); + if ( ! miniroute ) + return NULL; + + return miniroute->netdev; +} + /** * Check if IPv4 fragment matches fragment reassembly buffer * @@ -603,6 +622,7 @@ struct tcpip_net_protocol ipv4_tcpip_protocol __tcpip_net_protocol = { .name = "IPv4", .sa_family = AF_INET, .tx = ipv4_tx, + .netdev = ipv4_netdev, }; /** IPv4 ARP protocol */ diff --git a/src/net/ipv6.c b/src/net/ipv6.c index 2802aef0..6f2e9477 100644 --- a/src/net/ipv6.c +++ b/src/net/ipv6.c @@ -321,6 +321,25 @@ static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id, return NULL; } +/** + * Determine transmitting network device + * + * @v st_dest Destination network-layer address + * @ret netdev Transmitting network device, or NULL + */ +static struct net_device * ipv6_netdev ( struct sockaddr_tcpip *st_dest ) { + struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest ); + struct in6_addr *dest = &sin6_dest->sin6_addr; + struct ipv6_miniroute *miniroute; + + /* Find routing table entry */ + miniroute = ipv6_route ( sin6_dest->sin6_scope_id, &dest ); + if ( ! miniroute ) + return NULL; + + return miniroute->netdev; +} + /** * Check that received options can be safely ignored * @@ -970,6 +989,7 @@ struct tcpip_net_protocol ipv6_tcpip_protocol __tcpip_net_protocol = { .name = "IPv6", .sa_family = AF_INET6, .tx = ipv6_tx, + .netdev = ipv6_netdev, }; /** IPv6 socket address converter */ diff --git a/src/net/tcpip.c b/src/net/tcpip.c index 0b2adfd9..6fac8c52 100644 --- a/src/net/tcpip.c +++ b/src/net/tcpip.c @@ -18,7 +18,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); -/** Process a received TCP/IP packet +/** + * Process a received TCP/IP packet * * @v iobuf I/O buffer * @v netdev Network device @@ -57,7 +58,27 @@ int tcpip_rx ( struct io_buffer *iobuf, struct net_device *netdev, return -EPROTONOSUPPORT; } -/** Transmit a TCP/IP packet +/** + * Find TCP/IP network-layer protocol + * + * @v st_dest Destination address + * @ret tcpip_net TCP/IP network-layer protocol, or NULL if not found + */ +static struct tcpip_net_protocol * +tcpip_net_protocol ( struct sockaddr_tcpip *st_dest ) { + struct tcpip_net_protocol *tcpip_net; + + for_each_table_entry ( tcpip_net, TCPIP_NET_PROTOCOLS ) { + if ( tcpip_net->sa_family == st_dest->st_family ) + return tcpip_net; + } + + DBG ( "Unrecognised TCP/IP address family %d\n", st_dest->st_family ); + return NULL; +} + +/** + * Transmit a TCP/IP packet * * @v iobuf I/O buffer * @v tcpip_protocol Transport-layer protocol @@ -73,19 +94,34 @@ int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol, struct tcpip_net_protocol *tcpip_net; /* Hand off packet to the appropriate network-layer protocol */ - for_each_table_entry ( tcpip_net, TCPIP_NET_PROTOCOLS ) { - if ( tcpip_net->sa_family == st_dest->st_family ) { - DBG ( "TCP/IP sending %s packet\n", tcpip_net->name ); - return tcpip_net->tx ( iobuf, tcpip_protocol, st_src, - st_dest, netdev, trans_csum ); - } + tcpip_net = tcpip_net_protocol ( st_dest ); + if ( tcpip_net ) { + DBG ( "TCP/IP sending %s packet\n", tcpip_net->name ); + return tcpip_net->tx ( iobuf, tcpip_protocol, st_src, st_dest, + netdev, trans_csum ); } - - DBG ( "Unrecognised TCP/IP address family %d\n", st_dest->st_family ); + free_iob ( iobuf ); return -EAFNOSUPPORT; } +/** + * Determine transmitting network device + * + * @v st_dest Destination address + * @ret netdev Network device, or NULL + */ +struct net_device * tcpip_netdev ( struct sockaddr_tcpip *st_dest ) { + struct tcpip_net_protocol *tcpip_net; + + /* Hand off to the appropriate network-layer protocol */ + tcpip_net = tcpip_net_protocol ( st_dest ); + if ( tcpip_net ) + return tcpip_net->netdev ( st_dest ); + + return NULL; +} + /** * Calculate continued TCP/IP checkum *