These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / net / ipv4.c
index 9c5cf2e..a547840 100644 (file)
@@ -1,3 +1,27 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ * Copyright (C) 2006 Nikhil Chandru Rao
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
 #include <string.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -24,7 +48,7 @@
  *
  */
 
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 /* Unique IP datagram identification number (high byte) */
 static uint8_t next_ident_high = 0;
@@ -115,6 +139,7 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
 /**
  * Perform IPv4 routing
  *
+ * @v scope_id         Destination address scope ID
  * @v dest             Final destination address
  * @ret dest           Next hop destination address
  * @ret miniroute      Routing table entry to use, or NULL if no route
@@ -122,22 +147,42 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
  * If the route requires use of a gateway, the next hop destination
  * address will be overwritten with the gateway address.
  */
-static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
+static struct ipv4_miniroute * ipv4_route ( unsigned int scope_id,
+                                           struct in_addr *dest ) {
        struct ipv4_miniroute *miniroute;
-       int local;
-       int has_gw;
 
        /* Find first usable route in routing table */
        list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
+
+               /* Skip closed network devices */
                if ( ! netdev_is_open ( miniroute->netdev ) )
                        continue;
-               local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
-                           & miniroute->netmask.s_addr ) == 0 );
-               has_gw = ( miniroute->gateway.s_addr );
-               if ( local || has_gw ) {
-                       if ( ! local )
+
+               if ( IN_IS_MULTICAST ( dest->s_addr ) ) {
+
+                       /* If destination is non-global, and the scope ID
+                        * matches this network device, then use this route.
+                        */
+                       if ( miniroute->netdev->index == scope_id )
+                               return miniroute;
+
+               } else {
+
+                       /* If destination is an on-link global
+                        * address, then use this route.
+                        */
+                       if ( ( ( dest->s_addr ^ miniroute->address.s_addr )
+                              & miniroute->netmask.s_addr ) == 0 )
+                               return miniroute;
+
+                       /* If destination is an off-link global
+                        * address, and we have a default gateway,
+                        * then use this route.
+                        */
+                       if ( miniroute->gateway.s_addr ) {
                                *dest = miniroute->gateway;
-                       return miniroute;
+                               return miniroute;
+                       }
                }
        }
 
@@ -156,7 +201,7 @@ static struct net_device * ipv4_netdev ( struct sockaddr_tcpip *st_dest ) {
        struct ipv4_miniroute *miniroute;
 
        /* Find routing table entry */
-       miniroute = ipv4_route ( &dest );
+       miniroute = ipv4_route ( sin_dest->sin_scope_id, &dest );
        if ( ! miniroute )
                return NULL;
 
@@ -290,8 +335,8 @@ static int ipv4_tx ( struct io_buffer *iobuf,
        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 ) ) {
+            ( ( miniroute = ipv4_route ( sin_dest->sin_scope_id,
+                                         &next_hop ) ) != NULL ) ) {
                iphdr->src = miniroute->address;
                netmask = miniroute->netmask;
                netdev = miniroute->netdev;
@@ -329,7 +374,7 @@ static int ipv4_tx ( struct io_buffer *iobuf,
                /* Broadcast address */
                ipv4_stats.out_bcast_pkts++;
                ll_dest = netdev->ll_broadcast;
-       } else if ( IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) {
+       } else if ( IN_IS_MULTICAST ( next_hop.s_addr ) ) {
                /* Multicast address */
                ipv4_stats.out_mcast_pkts++;
                if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET, &next_hop,
@@ -568,11 +613,43 @@ static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
        return -ENOENT;
 }
 
+/**
+ * Parse IPv4 address
+ *
+ * @v string           IPv4 address string
+ * @ret in             IPv4 address to fill in
+ * @ret ok             IPv4 address is valid
+ *
+ * Note that this function returns nonzero iff the address is valid,
+ * to match the standard BSD API function of the same name.  Unlike
+ * most other iPXE functions, a zero therefore indicates failure.
+ */
+int inet_aton ( const char *string, struct in_addr *in ) {
+       const char *separator = "...";
+       uint8_t *byte = ( ( uint8_t * ) in );
+       char *endp;
+       unsigned long value;
+
+       while ( 1 ) {
+               value = strtoul ( string, &endp, 0 );
+               if ( string == endp )
+                       return 0;
+               if ( value > 0xff )
+                       return 0;
+               *(byte++) = value;
+               if ( *endp != *separator )
+                       return 0;
+               if ( ! *(separator++) )
+                       return 1;
+               string = ( endp + 1 );
+       }
+}
+
 /**
  * Convert IPv4 address to dotted-quad notation
  *
- * @v in       IP address
- * @ret string IP address in dotted-quad notation
+ * @v in               IPv4 address
+ * @ret string         IPv4 address in dotted-quad notation
  */
 char * inet_ntoa ( struct in_addr in ) {
        static char buf[16]; /* "xxx.xxx.xxx.xxx" */
@@ -583,10 +660,10 @@ char * inet_ntoa ( struct in_addr in ) {
 }
 
 /**
- * Transcribe IP address
+ * Transcribe IPv4 address
  *
- * @v net_addr IP address
- * @ret string IP address in dotted-quad notation
+ * @v net_addr         IPv4 address
+ * @ret string         IPv4 address in dotted-quad notation
  *
  */
 static const char * ipv4_ntoa ( const void *net_addr ) {
@@ -760,12 +837,12 @@ static int ipv4_create_routes ( void ) {
                fetch_ipv4_setting ( settings, &netmask_setting, &netmask );
                /* Calculate default netmask, if necessary */
                if ( ! netmask.s_addr ) {
-                       if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) {
-                               netmask.s_addr = htonl ( IN_CLASSA_NET );
-                       } else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) {
-                               netmask.s_addr = htonl ( IN_CLASSB_NET );
-                       } else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) {
-                               netmask.s_addr = htonl ( IN_CLASSC_NET );
+                       if ( IN_IS_CLASSA ( address.s_addr ) ) {
+                               netmask.s_addr = INADDR_NET_CLASSA;
+                       } else if ( IN_IS_CLASSB ( address.s_addr ) ) {
+                               netmask.s_addr = INADDR_NET_CLASSB;
+                       } else if ( IN_IS_CLASSC ( address.s_addr ) ) {
+                               netmask.s_addr = INADDR_NET_CLASSC;
                        }
                }
                /* Get default gateway, if present */
@@ -785,5 +862,8 @@ struct settings_applicator ipv4_settings_applicator __settings_applicator = {
        .apply = ipv4_create_routes,
 };
 
+/* Drag in objects via ipv4_protocol */
+REQUIRING_SYMBOL ( ipv4_protocol );
+
 /* Drag in ICMPv4 */
 REQUIRE_OBJECT ( icmpv4 );