mirror of https://github.com/ipxe/ipxe.git
[ipv6] Separate the concepts of prefix and address creation
Allow for IPv6 routing table entries to be created for an on-link prefix where a local address has not yet been assigned to the network device. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/17/head
parent
3f9a482b88
commit
6b1eee0452
|
@ -160,16 +160,24 @@ struct ipv6_miniroute {
|
||||||
/** Network device */
|
/** Network device */
|
||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
|
|
||||||
/** IPv6 address */
|
/** IPv6 address (or prefix if no address is defined) */
|
||||||
struct in6_addr address;
|
struct in6_addr address;
|
||||||
/** Prefix length */
|
/** Prefix length */
|
||||||
unsigned int prefix_len;
|
unsigned int prefix_len;
|
||||||
/** IPv6 prefix mask (derived from prefix length) */
|
/** IPv6 prefix mask (derived from prefix length) */
|
||||||
struct in6_addr prefix_mask;
|
struct in6_addr prefix_mask;
|
||||||
/** Router address is present */
|
|
||||||
int has_router;
|
|
||||||
/** Router address */
|
/** Router address */
|
||||||
struct in6_addr router;
|
struct in6_addr router;
|
||||||
|
/** Flags */
|
||||||
|
unsigned int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** IPv6 address/routing table entry flags */
|
||||||
|
enum ipv6_miniroute_flags {
|
||||||
|
/** Routing table entry address is valid */
|
||||||
|
IPV6_HAS_ADDRESS = 0x0001,
|
||||||
|
/** Routing table entry router address is valid */
|
||||||
|
IPV6_HAS_ROUTER = 0x0002,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -235,7 +243,9 @@ extern struct list_head ipv6_miniroutes;
|
||||||
extern struct net_protocol ipv6_protocol __net_protocol;
|
extern struct net_protocol ipv6_protocol __net_protocol;
|
||||||
|
|
||||||
extern int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr );
|
extern int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr );
|
||||||
extern int ipv6_slaac ( struct net_device *netdev, struct in6_addr *prefix,
|
extern int ipv6_set_prefix ( struct net_device *netdev, struct in6_addr *prefix,
|
||||||
unsigned int prefix_len, struct in6_addr *router );
|
unsigned int prefix_len, struct in6_addr *router );
|
||||||
|
extern int ipv6_set_address ( struct net_device *netdev,
|
||||||
|
struct in6_addr *address );
|
||||||
|
|
||||||
#endif /* _IPXE_IPV6_H */
|
#endif /* _IPXE_IPV6_H */
|
||||||
|
|
214
src/net/ipv6.c
214
src/net/ipv6.c
|
@ -67,6 +67,24 @@ static uint32_t ipv6col ( struct in6_addr *in ) {
|
||||||
return crc32_le ( 0, in, sizeof ( *in ) );
|
return crc32_le ( 0, in, sizeof ( *in ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump IPv6 routing table entry
|
||||||
|
*
|
||||||
|
* @v miniroute Routing table entry
|
||||||
|
*/
|
||||||
|
static inline __attribute__ (( always_inline )) void
|
||||||
|
ipv6_dump_miniroute ( struct ipv6_miniroute *miniroute ) {
|
||||||
|
struct net_device *netdev = miniroute->netdev;
|
||||||
|
|
||||||
|
DBGC ( netdev, "IPv6 %s has %s %s/%d", netdev->name,
|
||||||
|
( ( miniroute->flags & IPV6_HAS_ADDRESS ) ?
|
||||||
|
"address" : "prefix" ),
|
||||||
|
inet6_ntoa ( &miniroute->address ), miniroute->prefix_len );
|
||||||
|
if ( miniroute->flags & IPV6_HAS_ROUTER )
|
||||||
|
DBGC ( netdev, " router %s", inet6_ntoa ( &miniroute->router ));
|
||||||
|
DBGC ( netdev, "\n" );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if network device has a specific IPv6 address
|
* Check if network device has a specific IPv6 address
|
||||||
*
|
*
|
||||||
|
@ -79,6 +97,7 @@ int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr ) {
|
||||||
|
|
||||||
list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
|
list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
|
||||||
if ( ( miniroute->netdev == netdev ) &&
|
if ( ( miniroute->netdev == netdev ) &&
|
||||||
|
( miniroute->flags & IPV6_HAS_ADDRESS ) &&
|
||||||
( memcmp ( &miniroute->address, addr,
|
( memcmp ( &miniroute->address, addr,
|
||||||
sizeof ( miniroute->address ) ) == 0 ) ) {
|
sizeof ( miniroute->address ) ) == 0 ) ) {
|
||||||
/* Found matching address */
|
/* Found matching address */
|
||||||
|
@ -109,31 +128,45 @@ static int ipv6_is_on_link ( struct ipv6_miniroute *miniroute,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add IPv6 minirouting table entry
|
* Find IPv6 routing table entry for a given address
|
||||||
*
|
*
|
||||||
* @v netdev Network device
|
* @v netdev Network device
|
||||||
* @v address IPv6 address
|
* @v address IPv6 address
|
||||||
|
* @ret miniroute Routing table entry, or NULL if not found
|
||||||
|
*/
|
||||||
|
static struct ipv6_miniroute * ipv6_miniroute ( struct net_device *netdev,
|
||||||
|
struct in6_addr *address ) {
|
||||||
|
struct ipv6_miniroute *miniroute;
|
||||||
|
|
||||||
|
list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
|
||||||
|
if ( ( miniroute->netdev == netdev ) &&
|
||||||
|
ipv6_is_on_link ( miniroute, address ) ) {
|
||||||
|
return miniroute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add IPv6 routing table entry
|
||||||
|
*
|
||||||
|
* @v netdev Network device
|
||||||
|
* @v address IPv6 address (or prefix)
|
||||||
* @v prefix_len Prefix length
|
* @v prefix_len Prefix length
|
||||||
* @v router Router address (or NULL)
|
* @v flags Flags
|
||||||
* @ret miniroute Routing table entry, or NULL on failure
|
* @ret miniroute Routing table entry, or NULL on failure
|
||||||
*/
|
*/
|
||||||
static struct ipv6_miniroute * __malloc
|
static struct ipv6_miniroute * ipv6_add_miniroute ( struct net_device *netdev,
|
||||||
add_ipv6_miniroute ( struct net_device *netdev, struct in6_addr *address,
|
struct in6_addr *address,
|
||||||
unsigned int prefix_len, struct in6_addr *router ) {
|
unsigned int prefix_len,
|
||||||
|
unsigned int flags ) {
|
||||||
struct ipv6_miniroute *miniroute;
|
struct ipv6_miniroute *miniroute;
|
||||||
uint8_t *prefix_mask;
|
uint8_t *prefix_mask;
|
||||||
|
|
||||||
DBGC ( netdev, "IPv6 add %s/%d ", inet6_ntoa ( address ), prefix_len );
|
/* Create routing table entry */
|
||||||
if ( router )
|
|
||||||
DBGC ( netdev, "router %s ", inet6_ntoa ( router ) );
|
|
||||||
DBGC ( netdev, "via %s\n", netdev->name );
|
|
||||||
|
|
||||||
/* Allocate and populate miniroute structure */
|
|
||||||
miniroute = zalloc ( sizeof ( *miniroute ) );
|
miniroute = zalloc ( sizeof ( *miniroute ) );
|
||||||
if ( ! miniroute )
|
if ( ! miniroute )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Record routing information */
|
|
||||||
miniroute->netdev = netdev_get ( netdev );
|
miniroute->netdev = netdev_get ( netdev );
|
||||||
memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
|
memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
|
||||||
miniroute->prefix_len = prefix_len;
|
miniroute->prefix_len = prefix_len;
|
||||||
|
@ -144,41 +177,83 @@ add_ipv6_miniroute ( struct net_device *netdev, struct in6_addr *address,
|
||||||
}
|
}
|
||||||
if ( prefix_len )
|
if ( prefix_len )
|
||||||
*prefix_mask <<= ( 8 - prefix_len );
|
*prefix_mask <<= ( 8 - prefix_len );
|
||||||
if ( router ) {
|
miniroute->flags = flags;
|
||||||
miniroute->has_router = 1;
|
list_add ( &miniroute->list, &ipv6_miniroutes );
|
||||||
memcpy ( &miniroute->router, router,
|
ipv6_dump_miniroute ( miniroute );
|
||||||
sizeof ( miniroute->router ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add to end of list if we have a gateway, otherwise to start
|
|
||||||
* of list.
|
|
||||||
*/
|
|
||||||
if ( router ) {
|
|
||||||
list_add_tail ( &miniroute->list, &ipv6_miniroutes );
|
|
||||||
} else {
|
|
||||||
list_add ( &miniroute->list, &ipv6_miniroutes );
|
|
||||||
}
|
|
||||||
|
|
||||||
return miniroute;
|
return miniroute;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete IPv6 minirouting table entry
|
* Define IPv6 on-link prefix
|
||||||
*
|
*
|
||||||
* @v miniroute Routing table entry
|
* @v netdev Network device
|
||||||
|
* @v prefix IPv6 address prefix
|
||||||
|
* @v prefix_len Prefix length
|
||||||
|
* @v router Router address (or NULL)
|
||||||
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static void del_ipv6_miniroute ( struct ipv6_miniroute *miniroute ) {
|
int ipv6_set_prefix ( struct net_device *netdev, struct in6_addr *prefix,
|
||||||
struct net_device *netdev = miniroute->netdev;
|
unsigned int prefix_len, struct in6_addr *router ) {
|
||||||
|
struct ipv6_miniroute *miniroute;
|
||||||
|
int changed;
|
||||||
|
|
||||||
DBGC ( netdev, "IPv6 del %s/%d ", inet6_ntoa ( &miniroute->address ),
|
/* Find or create routing table entry */
|
||||||
miniroute->prefix_len );
|
miniroute = ipv6_miniroute ( netdev, prefix );
|
||||||
if ( miniroute->has_router )
|
if ( ! miniroute )
|
||||||
DBGC ( netdev, "router %s ", inet6_ntoa ( &miniroute->router ));
|
miniroute = ipv6_add_miniroute ( netdev, prefix, prefix_len, 0);
|
||||||
DBGC ( netdev, "via %s\n", netdev->name );
|
if ( ! miniroute )
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
netdev_put ( miniroute->netdev );
|
/* Record router and add to start or end of list as appropriate */
|
||||||
list_del ( &miniroute->list );
|
list_del ( &miniroute->list );
|
||||||
free ( miniroute );
|
if ( router ) {
|
||||||
|
changed = ( ( ! ( miniroute->flags & IPV6_HAS_ROUTER ) ) ||
|
||||||
|
( memcmp ( &miniroute->router, router,
|
||||||
|
sizeof ( miniroute->router ) ) != 0 ) );
|
||||||
|
miniroute->flags |= IPV6_HAS_ROUTER;
|
||||||
|
memcpy ( &miniroute->router, router,
|
||||||
|
sizeof ( miniroute->router ) );
|
||||||
|
list_add_tail ( &miniroute->list, &ipv6_miniroutes );
|
||||||
|
} else {
|
||||||
|
changed = ( miniroute->flags & IPV6_HAS_ROUTER );
|
||||||
|
miniroute->flags &= ~IPV6_HAS_ROUTER;
|
||||||
|
list_add ( &miniroute->list, &ipv6_miniroutes );
|
||||||
|
}
|
||||||
|
if ( changed )
|
||||||
|
ipv6_dump_miniroute ( miniroute );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add IPv6 on-link address
|
||||||
|
*
|
||||||
|
* @v netdev Network device
|
||||||
|
* @v address IPv6 address
|
||||||
|
* @ret rc Return status code
|
||||||
|
*
|
||||||
|
* An on-link prefix for the address must already exist.
|
||||||
|
*/
|
||||||
|
int ipv6_set_address ( struct net_device *netdev, struct in6_addr *address ) {
|
||||||
|
struct ipv6_miniroute *miniroute;
|
||||||
|
int changed;
|
||||||
|
|
||||||
|
/* Find routing table entry */
|
||||||
|
miniroute = ipv6_miniroute ( netdev, address );
|
||||||
|
if ( ! miniroute )
|
||||||
|
return -EADDRNOTAVAIL;
|
||||||
|
|
||||||
|
/* Record address */
|
||||||
|
changed = ( ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) ) ||
|
||||||
|
( memcmp ( &miniroute->address, address,
|
||||||
|
sizeof ( miniroute->address ) ) != 0 ) );
|
||||||
|
memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
|
||||||
|
miniroute->flags |= IPV6_HAS_ADDRESS;
|
||||||
|
if ( changed )
|
||||||
|
ipv6_dump_miniroute ( miniroute );
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -200,6 +275,10 @@ static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
|
||||||
if ( ! netdev_is_open ( miniroute->netdev ) )
|
if ( ! netdev_is_open ( miniroute->netdev ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Skip routing table entries with no usable source address */
|
||||||
|
if ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
if ( IN6_IS_ADDR_LINKLOCAL ( *dest ) ||
|
if ( IN6_IS_ADDR_LINKLOCAL ( *dest ) ||
|
||||||
IN6_IS_ADDR_MULTICAST ( *dest ) ) {
|
IN6_IS_ADDR_MULTICAST ( *dest ) ) {
|
||||||
|
|
||||||
|
@ -221,7 +300,7 @@ static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
|
||||||
* address, and we have a default gateway,
|
* address, and we have a default gateway,
|
||||||
* then use this route.
|
* then use this route.
|
||||||
*/
|
*/
|
||||||
if ( miniroute->has_router ) {
|
if ( miniroute->flags & IPV6_HAS_ROUTER ) {
|
||||||
*dest = &miniroute->router;
|
*dest = &miniroute->router;
|
||||||
return miniroute;
|
return miniroute;
|
||||||
}
|
}
|
||||||
|
@ -919,53 +998,6 @@ struct setting_type setting_type_ipv6 __setting_type = {
|
||||||
.format = format_ipv6_setting,
|
.format = format_ipv6_setting,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform IPv6 stateless address autoconfiguration (SLAAC)
|
|
||||||
*
|
|
||||||
* @v netdev Network device
|
|
||||||
* @v prefix Prefix
|
|
||||||
* @v prefix_len Prefix length
|
|
||||||
* @v router Router address (or NULL)
|
|
||||||
* @ret rc Return status code
|
|
||||||
*/
|
|
||||||
int ipv6_slaac ( struct net_device *netdev, struct in6_addr *prefix,
|
|
||||||
unsigned int prefix_len, struct in6_addr *router ) {
|
|
||||||
struct ipv6_miniroute *miniroute;
|
|
||||||
struct ipv6_miniroute *tmp;
|
|
||||||
struct in6_addr address;
|
|
||||||
int check_prefix_len;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* Construct local address */
|
|
||||||
memcpy ( &address, prefix, sizeof ( address ) );
|
|
||||||
check_prefix_len = ipv6_eui64 ( &address, netdev );
|
|
||||||
if ( check_prefix_len < 0 ) {
|
|
||||||
rc = check_prefix_len;
|
|
||||||
DBGC ( netdev, "IPv6 %s could not construct SLAAC address: "
|
|
||||||
"%s\n", netdev->name, strerror ( rc ) );
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if ( check_prefix_len != ( int ) prefix_len ) {
|
|
||||||
DBGC ( netdev, "IPv6 %s incorrect SLAAC prefix length %d "
|
|
||||||
"(expected %d)\n", netdev->name, prefix_len,
|
|
||||||
check_prefix_len );
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Delete any existing SLAAC miniroutes for this prefix */
|
|
||||||
list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
|
|
||||||
if ( ipv6_is_on_link ( miniroute, &address ) )
|
|
||||||
del_ipv6_miniroute ( miniroute );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add miniroute */
|
|
||||||
miniroute = add_ipv6_miniroute ( netdev, &address, prefix_len, router );
|
|
||||||
if ( ! miniroute )
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create IPv6 network device
|
* Create IPv6 network device
|
||||||
*
|
*
|
||||||
|
@ -989,7 +1021,8 @@ static int ipv6_probe ( struct net_device *netdev ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create link-local address for this network device */
|
/* Create link-local address for this network device */
|
||||||
miniroute = add_ipv6_miniroute ( netdev, &address, prefix_len, NULL );
|
miniroute = ipv6_add_miniroute ( netdev, &address, prefix_len,
|
||||||
|
IPV6_HAS_ADDRESS );
|
||||||
if ( ! miniroute )
|
if ( ! miniroute )
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -1007,8 +1040,11 @@ static void ipv6_remove ( struct net_device *netdev ) {
|
||||||
|
|
||||||
/* Delete all miniroutes for this network device */
|
/* Delete all miniroutes for this network device */
|
||||||
list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
|
list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
|
||||||
if ( miniroute->netdev == netdev )
|
if ( miniroute->netdev == netdev ) {
|
||||||
del_ipv6_miniroute ( miniroute );
|
netdev_put ( miniroute->netdev );
|
||||||
|
list_del ( &miniroute->list );
|
||||||
|
free ( miniroute );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,8 +88,8 @@ static int ndp_tx_ll_addr ( struct net_device *netdev,
|
||||||
/* Transmit packet */
|
/* Transmit packet */
|
||||||
if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest,
|
if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest,
|
||||||
netdev, &ndp->icmp.chksum ) ) != 0 ) {
|
netdev, &ndp->icmp.chksum ) ) != 0 ) {
|
||||||
DBGC ( netdev, "NDP could not transmit packet: %s\n",
|
DBGC ( netdev, "NDP %s could not transmit packet: %s\n",
|
||||||
strerror ( rc ) );
|
netdev->name, strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,8 +205,9 @@ ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev,
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if ( offsetof ( typeof ( *ll_addr_opt ),
|
if ( offsetof ( typeof ( *ll_addr_opt ),
|
||||||
ll_addr[ll_protocol->ll_addr_len] ) > len ) {
|
ll_addr[ll_protocol->ll_addr_len] ) > len ) {
|
||||||
DBGC ( netdev, "NDP neighbour solicitation link-layer address "
|
DBGC ( netdev, "NDP %s neighbour solicitation link-layer "
|
||||||
"option too short at %zd bytes\n", len );
|
"address option too short at %zd bytes\n",
|
||||||
|
netdev->name, len );
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,8 +215,8 @@ ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev,
|
||||||
if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
|
if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
|
||||||
&sin6_src->sin6_addr,
|
&sin6_src->sin6_addr,
|
||||||
ll_addr_opt->ll_addr ) ) != 0 ) {
|
ll_addr_opt->ll_addr ) ) != 0 ) {
|
||||||
DBGC ( netdev, "NDP could not define %s => %s: %s\n",
|
DBGC ( netdev, "NDP %s could not define %s => %s: %s\n",
|
||||||
inet6_ntoa ( &sin6_src->sin6_addr ),
|
netdev->name, inet6_ntoa ( &sin6_src->sin6_addr ),
|
||||||
ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
|
ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
|
||||||
strerror ( rc ) );
|
strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -260,16 +261,17 @@ ndp_rx_neighbour_advertisement_ll_target ( struct net_device *netdev,
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if ( offsetof ( typeof ( *ll_addr_opt ),
|
if ( offsetof ( typeof ( *ll_addr_opt ),
|
||||||
ll_addr[ll_protocol->ll_addr_len] ) > len ) {
|
ll_addr[ll_protocol->ll_addr_len] ) > len ) {
|
||||||
DBGC ( netdev, "NDP neighbour advertisement link-layer address "
|
DBGC ( netdev, "NDP %s neighbour advertisement link-layer "
|
||||||
"option too short at %zd bytes\n", len );
|
"address option too short at %zd bytes\n",
|
||||||
|
netdev->name, len );
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update neighbour cache entry, if any */
|
/* Update neighbour cache entry, if any */
|
||||||
if ( ( rc = neighbour_update ( netdev, &ipv6_protocol, &neigh->target,
|
if ( ( rc = neighbour_update ( netdev, &ipv6_protocol, &neigh->target,
|
||||||
ll_addr_opt->ll_addr ) ) != 0 ) {
|
ll_addr_opt->ll_addr ) ) != 0 ) {
|
||||||
DBGC ( netdev, "NDP could not update %s => %s: %s\n",
|
DBGC ( netdev, "NDP %s could not update %s => %s: %s\n",
|
||||||
inet6_ntoa ( &neigh->target ),
|
netdev->name, inet6_ntoa ( &neigh->target ),
|
||||||
ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
|
ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
|
||||||
strerror ( rc ) );
|
strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -300,8 +302,8 @@ ndp_rx_router_advertisement_ll_source ( struct net_device *netdev,
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if ( offsetof ( typeof ( *ll_addr_opt ),
|
if ( offsetof ( typeof ( *ll_addr_opt ),
|
||||||
ll_addr[ll_protocol->ll_addr_len] ) > len ) {
|
ll_addr[ll_protocol->ll_addr_len] ) > len ) {
|
||||||
DBGC ( netdev, "NDP router advertisement link-layer address "
|
DBGC ( netdev, "NDP %s router advertisement link-layer address "
|
||||||
"option too short at %zd bytes\n", len );
|
"option too short at %zd bytes\n", netdev->name, len );
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,8 +311,8 @@ ndp_rx_router_advertisement_ll_source ( struct net_device *netdev,
|
||||||
if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
|
if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
|
||||||
&sin6_src->sin6_addr,
|
&sin6_src->sin6_addr,
|
||||||
ll_addr_opt->ll_addr ) ) != 0 ) {
|
ll_addr_opt->ll_addr ) ) != 0 ) {
|
||||||
DBGC ( netdev, "NDP could not define %s => %s: %s\n",
|
DBGC ( netdev, "NDP %s could not define %s => %s: %s\n",
|
||||||
inet6_ntoa ( &sin6_src->sin6_addr ),
|
netdev->name, inet6_ntoa ( &sin6_src->sin6_addr ),
|
||||||
ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
|
ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
|
||||||
strerror ( rc ) );
|
strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -337,16 +339,18 @@ ndp_rx_router_advertisement_prefix ( struct net_device *netdev,
|
||||||
struct ndp_router_advertisement_header *radv = &ndp->radv;
|
struct ndp_router_advertisement_header *radv = &ndp->radv;
|
||||||
struct ndp_prefix_information_option *prefix_opt = &option->prefix;
|
struct ndp_prefix_information_option *prefix_opt = &option->prefix;
|
||||||
struct in6_addr *router = &sin6_src->sin6_addr;
|
struct in6_addr *router = &sin6_src->sin6_addr;
|
||||||
|
struct in6_addr address;
|
||||||
|
int prefix_len;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if ( sizeof ( *prefix_opt ) > len ) {
|
if ( sizeof ( *prefix_opt ) > len ) {
|
||||||
DBGC ( netdev, "NDP router advertisement prefix option too "
|
DBGC ( netdev, "NDP %s router advertisement prefix option too "
|
||||||
"short at %zd bytes\n", len );
|
"short at %zd bytes\n", netdev->name, len );
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
DBGC ( netdev, "NDP found %sdefault router %s ",
|
DBGC ( netdev, "NDP %s found %sdefault router %s ",
|
||||||
( radv->lifetime ? "" : "non-" ),
|
netdev->name, ( radv->lifetime ? "" : "non-" ),
|
||||||
inet6_ntoa ( &sin6_src->sin6_addr ) );
|
inet6_ntoa ( &sin6_src->sin6_addr ) );
|
||||||
DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d\n",
|
DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d\n",
|
||||||
( ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) ? "on" : "off" ),
|
( ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) ? "on" : "off" ),
|
||||||
|
@ -354,17 +358,41 @@ ndp_rx_router_advertisement_prefix ( struct net_device *netdev,
|
||||||
inet6_ntoa ( &prefix_opt->prefix ),
|
inet6_ntoa ( &prefix_opt->prefix ),
|
||||||
prefix_opt->prefix_len );
|
prefix_opt->prefix_len );
|
||||||
|
|
||||||
|
/* Ignore off-link prefixes */
|
||||||
|
if ( ! ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Define prefix */
|
||||||
|
if ( ( rc = ipv6_set_prefix ( netdev, &prefix_opt->prefix,
|
||||||
|
prefix_opt->prefix_len,
|
||||||
|
( radv->lifetime ?
|
||||||
|
router : NULL ) ) ) != 0 ) {
|
||||||
|
DBGC ( netdev, "NDP %s could not define prefix %s/%d: %s\n",
|
||||||
|
netdev->name, inet6_ntoa ( &prefix_opt->prefix ),
|
||||||
|
prefix_opt->prefix_len, strerror ( rc ) );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* Perform stateless address autoconfiguration, if applicable */
|
/* Perform stateless address autoconfiguration, if applicable */
|
||||||
if ( ( prefix_opt->flags &
|
if ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) {
|
||||||
( NDP_PREFIX_ON_LINK | NDP_PREFIX_AUTONOMOUS ) ) ==
|
memcpy ( &address, &prefix_opt->prefix, sizeof ( address ) );
|
||||||
( NDP_PREFIX_ON_LINK | NDP_PREFIX_AUTONOMOUS ) ) {
|
prefix_len = ipv6_eui64 ( &address, netdev );
|
||||||
if ( ( rc = ipv6_slaac ( netdev, &prefix_opt->prefix,
|
if ( prefix_len < 0 ) {
|
||||||
prefix_opt->prefix_len,
|
rc = prefix_len;
|
||||||
( radv->lifetime ?
|
DBGC ( netdev, "NDP %s could not construct SLAAC "
|
||||||
router : NULL ) ) ) != 0 ) {
|
"address: %s\n", netdev->name, strerror ( rc ) );
|
||||||
DBGC ( netdev, "NDP could not autoconfigure prefix %s/"
|
return rc;
|
||||||
"%d: %s\n", inet6_ntoa ( &prefix_opt->prefix ),
|
}
|
||||||
prefix_opt->prefix_len, strerror ( rc ) );
|
if ( prefix_len != prefix_opt->prefix_len ) {
|
||||||
|
DBGC ( netdev, "NDP %s incorrect SLAAC prefix length "
|
||||||
|
"%d (expected %d)\n", netdev->name,
|
||||||
|
prefix_opt->prefix_len, prefix_len );
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if ( ( rc = ipv6_set_address ( netdev, &address ) ) != 0 ) {
|
||||||
|
DBGC ( netdev, "NDP %s could not set address %s: %s\n",
|
||||||
|
netdev->name, inet6_ntoa ( &address ),
|
||||||
|
strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,8 +495,8 @@ static int ndp_rx_options ( struct net_device *netdev,
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if ( len < offset ) {
|
if ( len < offset ) {
|
||||||
DBGC ( netdev, "NDP packet too short at %zd bytes (min %zd "
|
DBGC ( netdev, "NDP %s packet too short at %zd bytes (min %zd "
|
||||||
"bytes)\n", len, offset );
|
"bytes)\n", netdev->name, len, offset );
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,7 +510,8 @@ static int ndp_rx_options ( struct net_device *netdev,
|
||||||
( option->header.blocks == 0 ) ||
|
( option->header.blocks == 0 ) ||
|
||||||
( remaining < ( option->header.blocks *
|
( remaining < ( option->header.blocks *
|
||||||
NDP_OPTION_BLKSZ ) ) ) {
|
NDP_OPTION_BLKSZ ) ) ) {
|
||||||
DBGC ( netdev, "NDP bad option length:\n" );
|
DBGC ( netdev, "NDP %s bad option length:\n",
|
||||||
|
netdev->name );
|
||||||
DBGC_HDA ( netdev, 0, option, remaining );
|
DBGC_HDA ( netdev, 0, option, remaining );
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -715,9 +744,9 @@ static int ipv6conf_rx_router_advertisement ( struct net_device *netdev,
|
||||||
stateful = ( flags & NDP_ROUTER_MANAGED );
|
stateful = ( flags & NDP_ROUTER_MANAGED );
|
||||||
if ( ( rc = start_dhcpv6 ( &ipv6conf->dhcp, netdev,
|
if ( ( rc = start_dhcpv6 ( &ipv6conf->dhcp, netdev,
|
||||||
stateful ) ) != 0 ) {
|
stateful ) ) != 0 ) {
|
||||||
DBGC ( netdev, "NDP could not start state%s DHCPv6: "
|
DBGC ( netdev, "NDP %s could not start state%s DHCPv6: "
|
||||||
"%s\n", ( stateful ? "ful" : "less" ),
|
"%s\n", netdev->name,
|
||||||
strerror ( rc ) );
|
( stateful ? "ful" : "less" ), strerror ( rc ) );
|
||||||
ipv6conf_done ( ipv6conf, rc );
|
ipv6conf_done ( ipv6conf, rc );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,10 @@ static void route_ipv6_print ( struct net_device *netdev ) {
|
||||||
printf ( "%s: %s/%d", netdev->name,
|
printf ( "%s: %s/%d", netdev->name,
|
||||||
inet6_ntoa ( &miniroute->address ),
|
inet6_ntoa ( &miniroute->address ),
|
||||||
miniroute->prefix_len );
|
miniroute->prefix_len );
|
||||||
if ( miniroute->has_router )
|
if ( miniroute->flags & IPV6_HAS_ROUTER )
|
||||||
printf ( " gw %s", inet6_ntoa ( &miniroute->router ) );
|
printf ( " gw %s", inet6_ntoa ( &miniroute->router ) );
|
||||||
|
if ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) )
|
||||||
|
printf ( " (no address)" );
|
||||||
if ( ! netdev_is_open ( miniroute->netdev ) )
|
if ( ! netdev_is_open ( miniroute->netdev ) )
|
||||||
printf ( " (inaccessible)" );
|
printf ( " (inaccessible)" );
|
||||||
printf ( "\n" );
|
printf ( "\n" );
|
||||||
|
|
Loading…
Reference in New Issue