diff options
Diffstat (limited to 'qemu/roms/ipxe/src/net/ipv4.c')
-rw-r--r-- | qemu/roms/ipxe/src/net/ipv4.c | 130 |
1 files changed, 105 insertions, 25 deletions
diff --git a/qemu/roms/ipxe/src/net/ipv4.c b/qemu/roms/ipxe/src/net/ipv4.c index 9c5cf2eb4..a54784049 100644 --- a/qemu/roms/ipxe/src/net/ipv4.c +++ b/qemu/roms/ipxe/src/net/ipv4.c @@ -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, @@ -569,10 +614,42 @@ static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) { } /** + * 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 ); |