]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[tcpip] Allow for transmission to multicast IPv4 addresses
authorMichael Brown <mcb30@etherboot.org>
Wed, 21 Jan 2009 03:40:39 +0000 (03:40 +0000)
committerMichael Brown <mcb30@etherboot.org>
Wed, 21 Jan 2009 03:40:39 +0000 (03:40 +0000)
When sending to a multicast address, it may be necessary to specify
the source address explicitly, since the multicast destination address
does not provide enough information to deduce the source address via
the miniroute table.

Allow the source address specified via the data-xfer metadata to be
passed down through the TCP/IP stack to the IPv4 layer, which can use
it as a default source address.

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 9bc3cc4a7c7524cf1927019edb297a681bb758b2..da89530e68cf814b69f02ca6fa9642b69ce113fb 100644 (file)
@@ -82,6 +82,7 @@ struct tcpip_net_protocol {
         *
         * @v iobuf             I/O buffer
         * @v tcpip_protocol    Transport-layer protocol
+        * @v st_src            Source address, or NULL to use default
         * @v st_dest           Destination address
         * @v netdev            Network device (or NULL to route automatically)
         * @v trans_csum        Transport-layer checksum to complete, or NULL
@@ -91,6 +92,7 @@ struct tcpip_net_protocol {
         */
        int ( * tx ) ( struct io_buffer *iobuf,
                       struct tcpip_protocol *tcpip_protocol,
+                      struct sockaddr_tcpip *st_src,
                       struct sockaddr_tcpip *st_dest,
                       struct net_device *netdev,
                       uint16_t *trans_csum );
@@ -107,7 +109,8 @@ struct tcpip_net_protocol {
 extern int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto,
                      struct sockaddr_tcpip *st_src,
                      struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum );
-extern int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip, 
+extern int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip,
+                     struct sockaddr_tcpip *st_src,
                      struct sockaddr_tcpip *st_dest,
                      struct net_device *netdev,
                      uint16_t *trans_csum );
index 7b7146c28a07ee93bc17d7d2e63d03603c8b1004..237fc4a63de4424c8b246f45de76040471ccda83 100644 (file)
@@ -60,7 +60,7 @@ 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 ( iobuf, &icmp6_protocol, &st_dest.st,
+       return tcpip_tx ( iobuf, &icmp6_protocol, NULL, &st_dest.st,
                          NULL, &nsolicit->csum );
 }
 
index 63dcca280aae6228df0f1488b41263754225980b..335048c816d43cbd65cfa07a6a5fe63e8414f533 100644 (file)
@@ -286,6 +286,7 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
  *
  * @v iobuf            I/O buffer
  * @v tcpip            Transport-layer protocol
+ * @v st_src           Source network-layer address
  * @v st_dest          Destination network-layer address
  * @v netdev           Network device to use if no route found, or NULL
  * @v trans_csum       Transport-layer checksum to complete, or NULL
@@ -295,10 +296,12 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
  */
 static int ipv4_tx ( struct io_buffer *iobuf,
                     struct tcpip_protocol *tcpip_protocol,
+                    struct sockaddr_tcpip *st_src,
                     struct sockaddr_tcpip *st_dest,
                     struct net_device *netdev,
                     uint16_t *trans_csum ) {
        struct iphdr *iphdr = iob_push ( iobuf, sizeof ( *iphdr ) );
+       struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
        struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
        struct ipv4_miniroute *miniroute;
        struct in_addr next_hop;
@@ -317,7 +320,11 @@ static int ipv4_tx ( struct io_buffer *iobuf,
 
        /* Use routing table to identify next hop and transmitting netdev */
        next_hop = iphdr->dest;
-       if ( ( miniroute = ipv4_route ( &next_hop ) ) ) {
+       if ( sin_src )
+               iphdr->src = sin_src->sin_addr;
+       if ( ( next_hop.s_addr != INADDR_BROADCAST ) &&
+            ( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) &&
+            ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
                iphdr->src = miniroute->address;
                netdev = miniroute->netdev;
        }
index 3407d538ca93d2155170d940f5ca50e9e4887d52..f7308bb431270f9840118e66e9b343149f6632a5 100644 (file)
@@ -176,6 +176,7 @@ void ipv6_dump ( struct ip6_header *ip6hdr ) {
  */
 static int ipv6_tx ( struct io_buffer *iobuf,
                     struct tcpip_protocol *tcpip,
+                    struct sockaddr_tcpip *st_src __unused,
                     struct sockaddr_tcpip *st_dest,
                     struct net_device *netdev,
                     uint16_t *trans_csum ) {
index 4e0db464ccade70028a85d894b12d85c949a97ce..0f91bcf9d6c917942e7b6555f8508063c1e31a58 100644 (file)
@@ -491,7 +491,7 @@ static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) {
        DBGC ( tcp, "\n" );
 
        /* Transmit packet */
-       return tcpip_tx ( iobuf, &tcp_protocol, &tcp->peer, NULL,
+       return tcpip_tx ( iobuf, &tcp_protocol, NULL, &tcp->peer, NULL,
                          &tcphdr->csum );
 }
 
@@ -572,7 +572,7 @@ static int tcp_xmit_reset ( struct tcp_connection *tcp,
        DBGC ( tcp, "\n" );
 
        /* Transmit packet */
-       return tcpip_tx ( iobuf, &tcp_protocol, st_dest,
+       return tcpip_tx ( iobuf, &tcp_protocol, NULL, st_dest,
                          NULL, &tcphdr->csum );
 }
 
index 1bc8d1a30b697d5223bde5cba3ee39818132492d..d4542b05ba8305dfbd22b9a3a9fb8559940e82ac 100644 (file)
@@ -64,14 +64,15 @@ int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto,
  *
  * @v iobuf            I/O buffer
  * @v tcpip_protocol   Transport-layer protocol
+ * @v st_src           Source address, or NULL to use route default
  * @v st_dest          Destination address
  * @v netdev           Network device to use if no route found, or NULL
  * @v trans_csum       Transport-layer checksum to complete, or NULL
  * @ret rc             Return status code
  */
 int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol,
-              struct sockaddr_tcpip *st_dest, struct net_device *netdev,
-              uint16_t *trans_csum ) {
+              struct sockaddr_tcpip *st_src, 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 */
@@ -79,8 +80,8 @@ int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol,
              tcpip_net < tcpip_net_protocols_end ; tcpip_net++ ) {
                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_dest,
-                                              netdev, trans_csum );
+                       return tcpip_net->tx ( iobuf, tcpip_protocol, st_src,
+                                              st_dest, netdev, trans_csum );
                }
        }
        
index fddf81df9cb5c8225fa70a89f940866f904788fd..63c2d9ee3c491d28e3d21387745797938745f897 100644 (file)
@@ -182,13 +182,13 @@ static void udp_close ( struct udp_connection *udp, int rc ) {
  *
  * @v udp              UDP connection
  * @v iobuf            I/O buffer
- * @v src_port         Source port, or 0 to use default
+ * @v src              Source address, or NULL to use default
  * @v dest             Destination address, or NULL to use default
  * @v netdev           Network device, or NULL to use default
  * @ret rc             Return status code
  */
 static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
-                   unsigned int src_port, struct sockaddr_tcpip *dest,
+                   struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest,
                    struct net_device *netdev ) {
                struct udp_header *udphdr;
        size_t len;
@@ -201,8 +201,8 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
        }
 
        /* Fill in default values if not explicitly provided */
-       if ( ! src_port )
-               src_port = udp->local.st_port;
+       if ( ! src )
+               src = &udp->local;
        if ( ! dest )
                dest = &udp->peer;
 
@@ -210,7 +210,7 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
        udphdr = iob_push ( iobuf, sizeof ( *udphdr ) );
        len = iob_len ( iobuf );
        udphdr->dest = dest->st_port;
-       udphdr->src = src_port;
+       udphdr->src = src->st_port;
        udphdr->len = htons ( len );
        udphdr->chksum = 0;
        udphdr->chksum = tcpip_chksum ( udphdr, len );
@@ -221,7 +221,7 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
               ntohs ( udphdr->len ) );
 
        /* Send it to the next layer for processing */
-       if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, dest, netdev,
+       if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev,
                               &udphdr->chksum ) ) != 0 ) {
                DBGC ( udp, "UDP %p could not transmit packet: %s\n",
                       udp, strerror ( rc ) );
@@ -399,22 +399,19 @@ static int udp_xfer_deliver_iob ( struct xfer_interface *xfer,
                                  struct xfer_metadata *meta ) {
        struct udp_connection *udp =
                container_of ( xfer, struct udp_connection, xfer );
-       struct sockaddr_tcpip *src;
+       struct sockaddr_tcpip *src = NULL;
        struct sockaddr_tcpip *dest = NULL;
        struct net_device *netdev = NULL;
-       unsigned int src_port = 0;
 
        /* Apply xfer metadata */
        if ( meta ) {
                src = ( struct sockaddr_tcpip * ) meta->src;
-               if ( src )
-                       src_port = src->st_port;
                dest = ( struct sockaddr_tcpip * ) meta->dest;
                netdev = meta->netdev;
        }
 
        /* Transmit data, if possible */
-       udp_tx ( udp, iobuf, src_port, dest, netdev );
+       udp_tx ( udp, iobuf, src, dest, netdev );
 
        return 0;
 }