From f008b77ba2b7d921a9d765c9931694e9c7d13ee9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 10 Jan 2007 02:25:11 +0000 Subject: [PATCH] Allow an explicit network device to be specified for IP-layer transmissions. --- src/include/gpxe/tcpip.h | 10 ++++++++-- src/net/icmpv6.c | 3 ++- src/net/ipv4.c | 20 ++++++++++++-------- src/net/ipv6.c | 2 +- src/net/tcp.c | 6 ++++-- src/net/tcpip.c | 6 ++++-- src/net/udp.c | 2 +- 7 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/include/gpxe/tcpip.h b/src/include/gpxe/tcpip.h index 23c6ce7f..1fdb8b71 100644 --- a/src/include/gpxe/tcpip.h +++ b/src/include/gpxe/tcpip.h @@ -13,6 +13,7 @@ #include struct pk_buff; +struct net_device; /** Empty checksum value * @@ -84,6 +85,7 @@ struct tcpip_net_protocol { * @v pkb Packet buffer * @v tcpip_protocol Transport-layer protocol * @v st_dest Destination address + * @v netdev Network device (or NULL to route automatically) * @v trans_csum Transport-layer checksum to complete, or NULL * @ret rc Return status code * @@ -91,7 +93,9 @@ struct tcpip_net_protocol { */ int ( * tx ) ( struct pk_buff *pkb, struct tcpip_protocol *tcpip_protocol, - struct sockaddr_tcpip *st_dest, uint16_t *trans_csum ); + struct sockaddr_tcpip *st_dest, + struct net_device *netdev, + uint16_t *trans_csum ); }; /** Declare a TCP/IP transport-layer protocol */ @@ -104,7 +108,9 @@ extern int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ); extern int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip, - struct sockaddr_tcpip *st_dest, uint16_t *trans_csum ); + struct sockaddr_tcpip *st_dest, + struct net_device *netdev, + uint16_t *trans_csum ); extern uint16_t 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/icmpv6.c b/src/net/icmpv6.c index 3f2b06f8..4eed0584 100644 --- a/src/net/icmpv6.c +++ b/src/net/icmpv6.c @@ -60,7 +60,8 @@ int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src __unuse st_dest.sin6.sin6_addr.in6_u.u6_addr8[13] = 0xff; /* Send packet over IP6 */ - return tcpip_tx ( pkb, &icmp6_protocol, &st_dest.st, &nsolicit->csum ); + return tcpip_tx ( pkb, &icmp6_protocol, &st_dest.st, + NULL, &nsolicit->csum ); } /** diff --git a/src/net/ipv4.c b/src/net/ipv4.c index e663ec32..a1a2d360 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -372,6 +372,7 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, * @v pkb Packet buffer * @v tcpip Transport-layer protocol * @v st_dest Destination network-layer address + * @v netdev Network device (or NULL to route automatically) * @v trans_csum Transport-layer checksum to complete, or NULL * @ret rc Status * @@ -379,7 +380,9 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, */ static int ipv4_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip_protocol, - struct sockaddr_tcpip *st_dest, uint16_t *trans_csum ) { + struct sockaddr_tcpip *st_dest, + struct net_device *netdev, + uint16_t *trans_csum ) { struct iphdr *iphdr = pkb_push ( pkb, sizeof ( *iphdr ) ); struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest ); struct ipv4_miniroute *miniroute; @@ -388,28 +391,29 @@ static int ipv4_tx ( struct pk_buff *pkb, int rc; /* Fill up the IP header, except source address */ + memset ( iphdr, 0, sizeof ( *iphdr ) ); iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) ); iphdr->service = IP_TOS; iphdr->len = htons ( pkb_len ( pkb ) ); iphdr->ident = htons ( ++next_ident ); - iphdr->frags = 0; iphdr->ttl = IP_TTL; iphdr->protocol = tcpip_protocol->tcpip_proto; - iphdr->chksum = 0; iphdr->dest = sin_dest->sin_addr; /* Use routing table to identify next hop and transmitting netdev */ next_hop = iphdr->dest; - miniroute = ipv4_route ( &next_hop ); - if ( ! miniroute ) { + if ( ( miniroute = ipv4_route ( &next_hop ) ) ) { + iphdr->src = miniroute->address; + netdev = miniroute->netdev; + } + if ( ! netdev ) { DBG ( "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) ); rc = -EHOSTUNREACH; goto err; } - iphdr->src = miniroute->address; /* Determine link-layer destination address */ - if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, miniroute->netdev, + if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netdev, ll_dest ) ) != 0 ) { DBG ( "IPv4 has no link-layer address for %s\n", inet_ntoa ( iphdr->dest ) ); @@ -428,7 +432,7 @@ static int ipv4_tx ( struct pk_buff *pkb, ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) ); /* Hand off to link layer */ - return net_tx ( pkb, miniroute->netdev, &ipv4_protocol, ll_dest ); + return net_tx ( pkb, netdev, &ipv4_protocol, ll_dest ); err: free_pkb ( pkb ); diff --git a/src/net/ipv6.c b/src/net/ipv6.c index 1801891b..b158254f 100644 --- a/src/net/ipv6.c +++ b/src/net/ipv6.c @@ -202,11 +202,11 @@ void ipv6_dump ( struct ip6_header *ip6hdr ) { static int ipv6_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip, struct sockaddr_tcpip *st_dest, + struct net_device *netdev, uint16_t *trans_csum ) { struct sockaddr_in6 *dest = ( struct sockaddr_in6* ) st_dest; struct in6_addr next_hop; struct ipv6_miniroute *miniroute; - struct net_device *netdev = NULL; uint8_t ll_dest_buf[MAX_LL_ADDR_LEN]; const uint8_t *ll_dest = ll_dest_buf; int rc; diff --git a/src/net/tcp.c b/src/net/tcp.c index b1ed0c09..f50c776a 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -309,7 +309,8 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) { DBGC ( conn, "\n" ); /* Transmit packet */ - return tcpip_tx ( pkb, &tcp_protocol, &conn->peer, &tcphdr->csum ); + return tcpip_tx ( pkb, &tcp_protocol, &conn->peer, + NULL, &tcphdr->csum ); } /** @@ -465,7 +466,8 @@ static int tcp_send_reset ( struct tcp_connection *conn, DBGC ( conn, "\n" ); /* Transmit packet */ - return tcpip_tx ( pkb, &tcp_protocol, &conn->peer, &tcphdr->csum ); + return tcpip_tx ( pkb, &tcp_protocol, &conn->peer, + NULL, &tcphdr->csum ); } /** diff --git a/src/net/tcpip.c b/src/net/tcpip.c index ae22104a..eec9ee94 100644 --- a/src/net/tcpip.c +++ b/src/net/tcpip.c @@ -65,11 +65,13 @@ int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto, * @v pkb Packet buffer * @v tcpip_protocol Transport-layer protocol * @v st_dest Destination address + * @v netdev Network device (or NULL to route automatically) * @v trans_csum Transport-layer checksum to complete, or NULL * @ret rc Return status code */ int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip_protocol, - struct sockaddr_tcpip *st_dest, uint16_t *trans_csum ) { + struct sockaddr_tcpip *st_dest, struct net_device *netdev, + uint16_t *trans_csum ) { struct tcpip_net_protocol *tcpip_net; /* Hand off packet to the appropriate network-layer protocol */ @@ -78,7 +80,7 @@ int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip_protocol, if ( tcpip_net->sa_family == st_dest->st_family ) { DBG ( "TCP/IP sending %s packet\n", tcpip_net->name ); return tcpip_net->tx ( pkb, tcpip_protocol, st_dest, - trans_csum ); + netdev, trans_csum ); } } diff --git a/src/net/udp.c b/src/net/udp.c index 0a9cea8b..32dfaec3 100644 --- a/src/net/udp.c +++ b/src/net/udp.c @@ -162,7 +162,7 @@ int udp_sendto ( struct udp_connection *conn, struct sockaddr_tcpip *peer, ntohs ( udphdr->len ) ); /* Send it to the next layer for processing */ - return tcpip_tx ( pkb, &udp_protocol, peer, &udphdr->chksum ); + return tcpip_tx ( pkb, &udp_protocol, peer, NULL, &udphdr->chksum ); } /**