summaryrefslogtreecommitdiffstats
path: root/src/net/ipv4.c
diff options
context:
space:
mode:
authorMichael Brown2015-07-21 15:54:11 +0200
committerMichael Brown2015-07-28 14:48:29 +0200
commit2bcf13f13aff503c47041caaab7cb42bb7ed1484 (patch)
tree0df326f4fb82e26babc7ce5d55a2e8b84ac996e1 /src/net/ipv4.c
parent[ipv4] Redefine IP address constants to avoid unnecessary byte swapping (diff)
downloadipxe-2bcf13f13aff503c47041caaab7cb42bb7ed1484.tar.gz
ipxe-2bcf13f13aff503c47041caaab7cb42bb7ed1484.tar.xz
ipxe-2bcf13f13aff503c47041caaab7cb42bb7ed1484.zip
[ipv4] Allow IPv4 socket addresses to include a scope ID
Extend the IPv6 concept of "scope ID" (indicating the network device index) to IPv4 socket addresses, so that IPv4 multicast transmissions may specify the transmitting network device. The scope ID is not (currently) exposed via the string representation of the socket address, since IPv4 does not use the IPv6 concept of link-local addresses (which could legitimately be specified in a URI). Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net/ipv4.c')
-rw-r--r--src/net/ipv4.c45
1 files changed, 33 insertions, 12 deletions
diff --git a/src/net/ipv4.c b/src/net/ipv4.c
index 3552cc49..a5478404 100644
--- a/src/net/ipv4.c
+++ b/src/net/ipv4.c
@@ -139,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
@@ -146,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;
+ }
}
}
@@ -180,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;
@@ -314,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_IS_MULTICAST ( 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;