Allow an explicit network device to be specified for IP-layer
authorMichael Brown <mcb30@etherboot.org>
Wed, 10 Jan 2007 02:25:11 +0000 (02:25 +0000)
committerMichael Brown <mcb30@etherboot.org>
Wed, 10 Jan 2007 02:25:11 +0000 (02:25 +0000)
transmissions.

src/include/gpxe/tcpip.h
src/net/icmpv6.c
src/net/ipv4.c
src/net/ipv6.c
src/net/tcp.c
src/net/tcpip.c
src/net/udp.c

index 23c6ce7..1fdb8b7 100644 (file)
@@ -13,6 +13,7 @@
 #include <gpxe/tables.h>
 
 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 );
index 3f2b06f..4eed058 100644 (file)
@@ -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 );
 }
 
 /**
index e663ec3..a1a2d36 100644 (file)
@@ -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 );
index 1801891..b158254 100644 (file)
@@ -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;
index b1ed0c0..f50c776 100644 (file)
@@ -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 );
 }
 
 /**
index ae22104..eec9ee9 100644 (file)
@@ -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 );
                }
        }
        
index 0a9cea8..32dfaec 100644 (file)
@@ -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 );
 }
 
 /**