mirror of
https://github.com/ipxe/ipxe
synced 2025-12-21 04:20:17 +03:00
[ipv6] Automatically choose source for link-local and multicast destinations
When transmitting to a link-local or multicast destination address, use the network device's link-local address as the source address if no explicit source address has been specified. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -93,10 +93,10 @@ int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr ) {
|
|||||||
*
|
*
|
||||||
* @v miniroute Routing table entry
|
* @v miniroute Routing table entry
|
||||||
* @v address IPv6 address
|
* @v address IPv6 address
|
||||||
* @ret is_local Address is within this entry's local network
|
* @ret is_on_link Address is within this entry's local network
|
||||||
*/
|
*/
|
||||||
static int ipv6_is_local ( struct ipv6_miniroute *miniroute,
|
static int ipv6_is_on_link ( struct ipv6_miniroute *miniroute,
|
||||||
struct in6_addr *address ) {
|
struct in6_addr *address ) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
|
for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
|
||||||
@@ -192,7 +192,6 @@ static void del_ipv6_miniroute ( struct ipv6_miniroute *miniroute ) {
|
|||||||
static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
|
static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
|
||||||
struct in6_addr **dest ) {
|
struct in6_addr **dest ) {
|
||||||
struct ipv6_miniroute *miniroute;
|
struct ipv6_miniroute *miniroute;
|
||||||
int local;
|
|
||||||
|
|
||||||
/* Find first usable route in routing table */
|
/* Find first usable route in routing table */
|
||||||
list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
|
list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
|
||||||
@@ -201,25 +200,32 @@ static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
|
|||||||
if ( ! netdev_is_open ( miniroute->netdev ) )
|
if ( ! netdev_is_open ( miniroute->netdev ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* For link-local addresses, skip devices that are not
|
if ( IN6_IS_ADDR_LINKLOCAL ( *dest ) ||
|
||||||
* the specified network device.
|
IN6_IS_ADDR_MULTICAST ( *dest ) ) {
|
||||||
*/
|
|
||||||
if ( IN6_IS_ADDR_LINKLOCAL ( *dest ) &&
|
|
||||||
( miniroute->netdev->index != scope_id ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Skip non-gateway devices for which the prefix does
|
/* If destination is non-global, and the scope ID
|
||||||
* not match.
|
* matches this network device, then use this route.
|
||||||
*/
|
*/
|
||||||
local = ipv6_is_local ( miniroute, *dest );
|
if ( miniroute->netdev->index == scope_id )
|
||||||
if ( ! ( local || miniroute->has_router ) )
|
return miniroute;
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Update next hop if applicable */
|
} else {
|
||||||
if ( ! local )
|
|
||||||
*dest = &miniroute->router;
|
|
||||||
|
|
||||||
return miniroute;
|
/* If destination is an on-link global
|
||||||
|
* address, then use this route.
|
||||||
|
*/
|
||||||
|
if ( ipv6_is_on_link ( miniroute, *dest ) )
|
||||||
|
return miniroute;
|
||||||
|
|
||||||
|
/* If destination is an off-link global
|
||||||
|
* address, and we have a default gateway,
|
||||||
|
* then use this route.
|
||||||
|
*/
|
||||||
|
if ( miniroute->has_router ) {
|
||||||
|
*dest = &miniroute->router;
|
||||||
|
return miniroute;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -363,6 +369,7 @@ static int ipv6_tx ( struct io_buffer *iobuf,
|
|||||||
struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest );
|
struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest );
|
||||||
struct ipv6_miniroute *miniroute;
|
struct ipv6_miniroute *miniroute;
|
||||||
struct ipv6_header *iphdr;
|
struct ipv6_header *iphdr;
|
||||||
|
struct in6_addr *src = NULL;
|
||||||
struct in6_addr *next_hop;
|
struct in6_addr *next_hop;
|
||||||
uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
|
uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
|
||||||
const void *ll_dest;
|
const void *ll_dest;
|
||||||
@@ -381,15 +388,9 @@ static int ipv6_tx ( struct io_buffer *iobuf,
|
|||||||
|
|
||||||
/* Use routing table to identify next hop and transmitting netdev */
|
/* Use routing table to identify next hop and transmitting netdev */
|
||||||
next_hop = &iphdr->dest;
|
next_hop = &iphdr->dest;
|
||||||
if ( sin6_src ) {
|
if ( ( miniroute = ipv6_route ( sin6_dest->sin6_scope_id,
|
||||||
memcpy ( &iphdr->src, &sin6_src->sin6_addr,
|
&next_hop ) ) != NULL ) {
|
||||||
sizeof ( iphdr->src ) );
|
src = &miniroute->address;
|
||||||
}
|
|
||||||
if ( ( ! IN6_IS_ADDR_MULTICAST ( next_hop ) ) &&
|
|
||||||
( ( miniroute = ipv6_route ( sin6_dest->sin6_scope_id,
|
|
||||||
&next_hop ) ) != NULL ) ) {
|
|
||||||
memcpy ( &iphdr->src, &miniroute->address,
|
|
||||||
sizeof ( iphdr->src ) );
|
|
||||||
netdev = miniroute->netdev;
|
netdev = miniroute->netdev;
|
||||||
}
|
}
|
||||||
if ( ! netdev ) {
|
if ( ! netdev ) {
|
||||||
@@ -398,6 +399,9 @@ static int ipv6_tx ( struct io_buffer *iobuf,
|
|||||||
rc = -ENETUNREACH;
|
rc = -ENETUNREACH;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
if ( sin6_src )
|
||||||
|
src = &sin6_src->sin6_addr;
|
||||||
|
memcpy ( &iphdr->src, src, sizeof ( iphdr->src ) );
|
||||||
|
|
||||||
/* Fix up checksums */
|
/* Fix up checksums */
|
||||||
if ( trans_csum ) {
|
if ( trans_csum ) {
|
||||||
@@ -897,7 +901,7 @@ int ipv6_slaac ( struct net_device *netdev, struct in6_addr *prefix,
|
|||||||
|
|
||||||
/* Delete any existing SLAAC miniroutes for this prefix */
|
/* Delete any existing SLAAC miniroutes for this prefix */
|
||||||
list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
|
list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
|
||||||
if ( ipv6_is_local ( miniroute, &address ) )
|
if ( ipv6_is_on_link ( miniroute, &address ) )
|
||||||
del_ipv6_miniroute ( miniroute );
|
del_ipv6_miniroute ( miniroute );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user