david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[ipv6] Add ndp_tx_router_solicitation() to send router solicitations

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2013-10-24 14:06:33 +01:00
parent 10d19bd2ac
commit b15dbc9cc6
5 changed files with 95 additions and 37 deletions

View File

@ -46,6 +46,9 @@ struct icmpv6_handler {
/** ICMPv6 echo reply */ /** ICMPv6 echo reply */
#define ICMPV6_ECHO_REPLY 129 #define ICMPV6_ECHO_REPLY 129
/** ICMPv6 router solicitation */
#define ICMPV6_ROUTER_SOLICITATION 133
/** ICMPv6 router advertisement */ /** ICMPv6 router advertisement */
#define ICMPV6_ROUTER_ADVERTISEMENT 134 #define ICMPV6_ROUTER_ADVERTISEMENT 134

View File

@ -194,14 +194,13 @@ static inline int ipv6_eui64 ( struct in6_addr *addr,
/** /**
* Construct link-local address via EUI-64 * Construct link-local address via EUI-64
* *
* @v addr Address to construct * @v addr Zeroed address to construct
* @v netdev Network device * @v netdev Network device
* @ret prefix_len Prefix length, or negative error * @ret prefix_len Prefix length, or negative error
*/ */
static inline int ipv6_link_local ( struct in6_addr *addr, static inline int ipv6_link_local ( struct in6_addr *addr,
struct net_device *netdev ) { struct net_device *netdev ) {
memset ( addr, 0, sizeof ( *addr ) );
addr->s6_addr16[0] = htons ( 0xfe80 ); addr->s6_addr16[0] = htons ( 0xfe80 );
return ipv6_eui64 ( addr, netdev ); return ipv6_eui64 ( addr, netdev );
} }
@ -209,19 +208,28 @@ static inline int ipv6_link_local ( struct in6_addr *addr,
/** /**
* Construct solicited-node multicast address * Construct solicited-node multicast address
* *
* @v addr Address to construct * @v addr Zeroed address to construct
* @v unicast Unicast address * @v unicast Unicast address
*/ */
static inline void ipv6_solicited_node ( struct in6_addr *addr, static inline void ipv6_solicited_node ( struct in6_addr *addr,
const struct in6_addr *unicast ) { const struct in6_addr *unicast ) {
memset ( addr, 0, sizeof ( *addr ) );
addr->s6_addr16[0] = htons ( 0xff02 ); addr->s6_addr16[0] = htons ( 0xff02 );
addr->s6_addr[11] = 1; addr->s6_addr[11] = 1;
addr->s6_addr[12] = 0xff; addr->s6_addr[12] = 0xff;
memcpy ( &addr->s6_addr[13], &unicast->s6_addr[13], 3 ); memcpy ( &addr->s6_addr[13], &unicast->s6_addr[13], 3 );
} }
/**
* Construct all-routers multicast address
*
* @v addr Zeroed address to construct
*/
static inline void ipv6_all_routers ( struct in6_addr *addr ) {
addr->s6_addr16[0] = htons ( 0xff02 );
addr->s6_addr[15] = 2;
}
extern struct list_head ipv6_miniroutes; extern struct list_head ipv6_miniroutes;
extern struct net_protocol ipv6_protocol __net_protocol; extern struct net_protocol ipv6_protocol __net_protocol;

View File

@ -124,12 +124,24 @@ struct ndp_router_advertisement_header {
/** NDP other configuration */ /** NDP other configuration */
#define NDP_ROUTER_OTHER 0x40 #define NDP_ROUTER_OTHER 0x40
/** An NDP router solicitation header */
struct ndp_router_solicitation_header {
/** ICMPv6 header */
struct icmp_header icmp;
/** Reserved */
uint32_t reserved;
/** Options */
union ndp_option option[0];
} __attribute__ (( packed ));
/** An NDP header */ /** An NDP header */
union ndp_header { union ndp_header {
/** ICMPv6 header */ /** ICMPv6 header */
struct icmp_header icmp; struct icmp_header icmp;
/** Neighbour solicitation or advertisement header */ /** Neighbour solicitation or advertisement header */
struct ndp_neighbour_header neigh; struct ndp_neighbour_header neigh;
/** Router solicitation header */
struct ndp_router_solicitation_header rsol;
/** Router advertisement header */ /** Router advertisement header */
struct ndp_router_advertisement_header radv; struct ndp_router_advertisement_header radv;
} __attribute__ (( packed )); } __attribute__ (( packed ));
@ -154,4 +166,6 @@ static inline int ndp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
&ndp_discovery, net_source, ll_source ); &ndp_discovery, net_source, ll_source );
} }
extern int ndp_tx_router_solicitation ( struct net_device *netdev );
#endif /* _IPXE_NDP_H */ #endif /* _IPXE_NDP_H */

View File

@ -926,6 +926,7 @@ static int ipv6_probe ( struct net_device *netdev ) {
int rc; int rc;
/* Construct link-local address from EUI-64 as per RFC 2464 */ /* Construct link-local address from EUI-64 as per RFC 2464 */
memset ( &address, 0, sizeof ( address ) );
prefix_len = ipv6_link_local ( &address, netdev ); prefix_len = ipv6_link_local ( &address, netdev );
if ( prefix_len < 0 ) { if ( prefix_len < 0 ) {
rc = prefix_len; rc = prefix_len;

View File

@ -37,23 +37,20 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/ */
/** /**
* Transmit NDP neighbour solicitation/advertisement packet * Transmit NDP packet with link-layer address option
* *
* @v netdev Network device * @v netdev Network device
* @v sin6_src Source socket address * @v sin6_src Source socket address
* @v sin6_dest Destination socket address * @v sin6_dest Destination socket address
* @v target Neighbour target address * @v data NDP header
* @v icmp_type ICMPv6 type * @v len Size of NDP header
* @v flags NDP flags
* @v option_type NDP option type * @v option_type NDP option type
* @ret rc Return status code * @ret rc Return status code
*/ */
static int ndp_tx_neighbour ( struct net_device *netdev, static int ndp_tx_ll_addr ( struct net_device *netdev,
struct sockaddr_in6 *sin6_src, struct sockaddr_in6 *sin6_src,
struct sockaddr_in6 *sin6_dest, struct sockaddr_in6 *sin6_dest,
const struct in6_addr *target, const void *data, size_t len,
unsigned int icmp_type,
unsigned int flags,
unsigned int option_type ) { unsigned int option_type ) {
struct sockaddr_tcpip *st_src = struct sockaddr_tcpip *st_src =
( ( struct sockaddr_tcpip * ) sin6_src ); ( ( struct sockaddr_tcpip * ) sin6_src );
@ -61,36 +58,31 @@ static int ndp_tx_neighbour ( struct net_device *netdev,
( ( struct sockaddr_tcpip * ) sin6_dest ); ( ( struct sockaddr_tcpip * ) sin6_dest );
struct ll_protocol *ll_protocol = netdev->ll_protocol; struct ll_protocol *ll_protocol = netdev->ll_protocol;
struct io_buffer *iobuf; struct io_buffer *iobuf;
struct ndp_neighbour_header *neigh;
struct ndp_ll_addr_option *ll_addr_opt; struct ndp_ll_addr_option *ll_addr_opt;
union ndp_header *ndp;
size_t option_len; size_t option_len;
size_t len;
int rc; int rc;
/* Allocate and populate buffer */ /* Allocate and populate buffer */
option_len = ( ( sizeof ( *ll_addr_opt ) + option_len = ( ( sizeof ( *ll_addr_opt ) +
ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) & ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) &
~( NDP_OPTION_BLKSZ - 1 ) ); ~( NDP_OPTION_BLKSZ - 1 ) );
len = ( sizeof ( *neigh ) + option_len ); iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len + option_len );
iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
if ( ! iobuf ) if ( ! iobuf )
return -ENOMEM; return -ENOMEM;
iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN ); iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
neigh = iob_put ( iobuf, len ); memcpy ( iob_put ( iobuf, len ), data, len );
memset ( neigh, 0, len ); ll_addr_opt = iob_put ( iobuf, option_len );
neigh->icmp.type = icmp_type;
neigh->flags = flags;
memcpy ( &neigh->target, target, sizeof ( neigh->target ) );
ll_addr_opt = &neigh->option[0].ll_addr;
ll_addr_opt->header.type = option_type; ll_addr_opt->header.type = option_type;
ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ ); ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ );
memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr, memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr,
ll_protocol->ll_addr_len ); ll_protocol->ll_addr_len );
neigh->icmp.chksum = tcpip_chksum ( neigh, len ); ndp = iobuf->data;
ndp->icmp.chksum = tcpip_chksum ( ndp, ( len + option_len ) );
/* 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, &neigh->icmp.chksum ) ) != 0 ) { netdev, &ndp->icmp.chksum ) ) != 0 ) {
DBGC ( netdev, "NDP could not transmit packet: %s\n", DBGC ( netdev, "NDP could not transmit packet: %s\n",
strerror ( rc ) ); strerror ( rc ) );
return rc; return rc;
@ -113,6 +105,8 @@ static int ndp_tx_request ( struct net_device *netdev,
const void *net_dest, const void *net_source ) { const void *net_dest, const void *net_source ) {
struct sockaddr_in6 sin6_src; struct sockaddr_in6 sin6_src;
struct sockaddr_in6 sin6_dest; struct sockaddr_in6 sin6_dest;
struct ndp_neighbour_header neigh;
int rc;
/* Construct source address */ /* Construct source address */
memset ( &sin6_src, 0, sizeof ( sin6_src ) ); memset ( &sin6_src, 0, sizeof ( sin6_src ) );
@ -127,10 +121,18 @@ static int ndp_tx_request ( struct net_device *netdev,
sin6_dest.sin6_scope_id = netdev->index; sin6_dest.sin6_scope_id = netdev->index;
ipv6_solicited_node ( &sin6_dest.sin6_addr, net_dest ); ipv6_solicited_node ( &sin6_dest.sin6_addr, net_dest );
/* Construct neighbour header */
memset ( &neigh, 0, sizeof ( neigh ) );
neigh.icmp.type = ICMPV6_NEIGHBOUR_SOLICITATION;
memcpy ( &neigh.target, net_dest, sizeof ( neigh.target ) );
/* Transmit neighbour discovery packet */ /* Transmit neighbour discovery packet */
return ndp_tx_neighbour ( netdev, &sin6_src, &sin6_dest, net_dest, if ( ( rc = ndp_tx_ll_addr ( netdev, &sin6_src, &sin6_dest, &neigh,
ICMPV6_NEIGHBOUR_SOLICITATION, 0, sizeof ( neigh ),
NDP_OPT_LL_SOURCE ); NDP_OPT_LL_SOURCE ) ) != 0 )
return rc;
return 0;
} }
/** NDP neighbour discovery protocol */ /** NDP neighbour discovery protocol */
@ -139,6 +141,35 @@ struct neighbour_discovery ndp_discovery = {
.tx_request = ndp_tx_request, .tx_request = ndp_tx_request,
}; };
/**
* Transmit NDP router solicitation
*
* @v netdev Network device
* @ret rc Return status code
*/
int ndp_tx_router_solicitation ( struct net_device *netdev ) {
struct ndp_router_solicitation_header rsol;
struct sockaddr_in6 sin6_dest;
int rc;
/* Construct multicast destination address */
memset ( &sin6_dest, 0, sizeof ( sin6_dest ) );
sin6_dest.sin6_family = AF_INET6;
sin6_dest.sin6_scope_id = netdev->index;
ipv6_all_routers ( &sin6_dest.sin6_addr );
/* Construct router solicitation */
memset ( &rsol, 0, sizeof ( rsol ) );
rsol.icmp.type = ICMPV6_ROUTER_SOLICITATION;
/* Transmit packet */
if ( ( rc = ndp_tx_ll_addr ( netdev, NULL, &sin6_dest, &rsol,
sizeof ( rsol ), NDP_OPT_LL_SOURCE ) ) !=0)
return rc;
return 0;
}
/** /**
* Process NDP neighbour solicitation source link-layer address option * Process NDP neighbour solicitation source link-layer address option
* *
@ -185,14 +216,16 @@ ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev,
return rc; return rc;
} }
/* Convert neighbour header to advertisement */
memset ( neigh, 0, offsetof ( typeof ( *neigh ), target ) );
neigh->icmp.type = ICMPV6_NEIGHBOUR_ADVERTISEMENT;
neigh->flags = ( NDP_NEIGHBOUR_SOLICITED | NDP_NEIGHBOUR_OVERRIDE );
/* Send neighbour advertisement */ /* Send neighbour advertisement */
if ( ( rc = ndp_tx_neighbour ( netdev, NULL, sin6_src, &neigh->target, if ( ( rc = ndp_tx_ll_addr ( netdev, NULL, sin6_src, neigh,
ICMPV6_NEIGHBOUR_ADVERTISEMENT, sizeof ( *neigh ),
( NDP_NEIGHBOUR_SOLICITED | NDP_OPT_LL_TARGET ) ) != 0 )
NDP_NEIGHBOUR_OVERRIDE ),
NDP_OPT_LL_TARGET ) ) != 0 ) {
return rc; return rc;
}
return 0; return 0;
} }
@ -512,7 +545,6 @@ ndp_rx_router_advertisement ( struct io_buffer *iobuf,
offsetof ( typeof ( *radv ), option ) ); offsetof ( typeof ( *radv ), option ) );
} }
/** NDP ICMPv6 handlers */ /** NDP ICMPv6 handlers */
struct icmpv6_handler ndp_handlers[] __icmpv6_handler = { struct icmpv6_handler ndp_handlers[] __icmpv6_handler = {
{ {