Skip to content

Commit

Permalink
[ipv4] Allow IPv4 socket addresses to include a scope ID
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mcb30 committed Jul 28, 2015
1 parent 6efcabd commit 2bcf13f
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 15 deletions.
11 changes: 9 additions & 2 deletions src/include/ipxe/in.h
Expand Up @@ -85,6 +85,11 @@ struct sockaddr_in {
uint16_t sin_flags;
/** TCP/IP port (part of struct @c sockaddr_tcpip) */
uint16_t sin_port;
/** Scope ID (part of struct @c sockaddr_tcpip)
*
* For multicast addresses, this is the network device index.
*/
uint16_t sin_scope_id;
/** IPv4 address */
struct in_addr sin_addr;
/** Padding
Expand All @@ -96,6 +101,7 @@ struct sockaddr_in {
( sizeof ( sa_family_t ) /* sin_family */ +
sizeof ( uint16_t ) /* sin_flags */ +
sizeof ( uint16_t ) /* sin_port */ +
sizeof ( uint16_t ) /* sin_scope_id */ +
sizeof ( struct in_addr ) /* sin_addr */ ) ];
} __attribute__ (( packed, may_alias ));

Expand All @@ -112,9 +118,10 @@ struct sockaddr_in6 {
uint16_t sin6_flags;
/** TCP/IP port (part of struct @c sockaddr_tcpip) */
uint16_t sin6_port;
/** Scope ID
/** Scope ID (part of struct @c sockaddr_tcpip)
*
* For link-local addresses, this is the network device index.
* For link-local or multicast addresses, this is the network
* device index.
*/
uint16_t sin6_scope_id;
/** IPv6 address */
Expand Down
9 changes: 8 additions & 1 deletion src/include/ipxe/tcpip.h
Expand Up @@ -48,6 +48,12 @@ struct sockaddr_tcpip {
uint16_t st_flags;
/** TCP/IP port */
uint16_t st_port;
/** Scope ID
*
* For link-local or multicast addresses, this is the network
* device index.
*/
uint16_t st_scope_id;
/** Padding
*
* This ensures that a struct @c sockaddr_tcpip is large
Expand All @@ -57,7 +63,8 @@ struct sockaddr_tcpip {
char pad[ sizeof ( struct sockaddr ) -
( sizeof ( sa_family_t ) /* st_family */ +
sizeof ( uint16_t ) /* st_flags */ +
sizeof ( uint16_t ) /* st_port */ ) ];
sizeof ( uint16_t ) /* st_port */ +
sizeof ( uint16_t ) /* st_scope_id */ ) ];
} __attribute__ (( packed, may_alias ));

/**
Expand Down
45 changes: 33 additions & 12 deletions src/net/ipv4.c
Expand Up @@ -139,29 +139,50 @@ 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
*
* 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;
}
}
}

Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 2bcf13f

Please sign in to comment.