mirror of
https://github.com/ipxe/ipxe
synced 2025-12-28 02:28:57 +03:00
[ipv6] Replace IPv6 stack
Replace the existing partially-implemented IPv6 stack with a fresh implementation. This implementation is not yet complete. The IPv6 transmit and receive datapaths are functional (including fragment reassembly and parsing of arbitrary extension headers). NDP neighbour solicitations and advertisements are supported. ICMPv6 echo is supported. At present, only link-local addresses may be used, and there is no way to specify an IPv6 address as part of a URI (either directly or via a DNS lookup). Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -1,59 +0,0 @@
|
||||
#ifndef _IPXE_ICMP6_H
|
||||
#define _IPXE_ICMP6_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ICMP6 protocol
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/ip6.h>
|
||||
#include <ipxe/ndp.h>
|
||||
|
||||
#define ICMP6_NSOLICIT 135
|
||||
#define ICMP6_NADVERT 136
|
||||
|
||||
extern struct tcpip_protocol icmp6_protocol __tcpip_protocol;
|
||||
|
||||
struct icmp6_header {
|
||||
uint8_t type;
|
||||
uint8_t code;
|
||||
uint16_t csum;
|
||||
/* Message body */
|
||||
};
|
||||
|
||||
struct neighbour_solicit {
|
||||
uint8_t type;
|
||||
uint8_t code;
|
||||
uint16_t csum;
|
||||
uint32_t reserved;
|
||||
struct in6_addr target;
|
||||
/* "Compulsory" options */
|
||||
uint8_t opt_type;
|
||||
uint8_t opt_len;
|
||||
/* FIXME: hack alert */
|
||||
uint8_t opt_ll_addr[6];
|
||||
};
|
||||
|
||||
struct neighbour_advert {
|
||||
uint8_t type;
|
||||
uint8_t code;
|
||||
uint16_t csum;
|
||||
uint8_t flags;
|
||||
uint8_t reserved;
|
||||
struct in6_addr target;
|
||||
uint8_t opt_type;
|
||||
uint8_t opt_len;
|
||||
/* FIXME: hack alert */
|
||||
uint8_t opt_ll_addr[6];
|
||||
};
|
||||
|
||||
#define ICMP6_FLAGS_ROUTER 0x80
|
||||
#define ICMP6_FLAGS_SOLICITED 0x40
|
||||
#define ICMP6_FLAGS_OVERRIDE 0x20
|
||||
|
||||
int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src, struct in6_addr *dest );
|
||||
|
||||
#endif /* _IPXE_ICMP6_H */
|
||||
78
src/include/ipxe/icmpv6.h
Normal file
78
src/include/ipxe/icmpv6.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#ifndef _IPXE_ICMP6_H
|
||||
#define _IPXE_ICMP6_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ICMPv6 protocol
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/tables.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
|
||||
/** An ICMPv6 header */
|
||||
struct icmpv6_header {
|
||||
/** Type */
|
||||
uint8_t type;
|
||||
/** Code */
|
||||
uint8_t code;
|
||||
/** Checksum */
|
||||
uint16_t chksum;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An ICMPv6 echo request/reply */
|
||||
struct icmpv6_echo {
|
||||
/** ICMPv6 header */
|
||||
struct icmpv6_header icmp;
|
||||
/** Identifier */
|
||||
uint16_t ident;
|
||||
/** Sequence number */
|
||||
uint16_t sequence;
|
||||
/** Data */
|
||||
uint8_t data[0];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An ICMPv6 handler */
|
||||
struct icmpv6_handler {
|
||||
/** Type */
|
||||
unsigned int type;
|
||||
/** Process received packet
|
||||
*
|
||||
* @v iobuf I/O buffer
|
||||
* @v netdev Network device
|
||||
* @v sin6_src Source socket address
|
||||
* @v sin6_dest Destination socket address
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This function takes ownership of the I/O buffer.
|
||||
*/
|
||||
int ( * rx ) ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
struct sockaddr_in6 *sin6_src,
|
||||
struct sockaddr_in6 *sin6_dest );
|
||||
};
|
||||
|
||||
/** ICMPv6 handler table */
|
||||
#define ICMPV6_HANDLERS __table ( struct icmpv6_handler, "icmpv6_handlers" )
|
||||
|
||||
/** Declare an ICMPv6 handler */
|
||||
#define __icmpv6_handler __table_entry ( ICMPV6_HANDLERS, 01 )
|
||||
|
||||
/** ICMPv6 echo request */
|
||||
#define ICMPV6_ECHO_REQUEST 128
|
||||
|
||||
/** ICMPv6 echo reply */
|
||||
#define ICMPV6_ECHO_REPLY 129
|
||||
|
||||
/** ICMPv6 neighbour solicitation */
|
||||
#define ICMPV6_NDP_NEIGHBOUR_SOLICITATION 135
|
||||
|
||||
/** ICMPv6 neighbour advertisement */
|
||||
#define ICMPV6_NDP_NEIGHBOUR_ADVERTISEMENT 136
|
||||
|
||||
extern struct tcpip_protocol icmpv6_protocol __tcpip_protocol;
|
||||
|
||||
#endif /* _IPXE_ICMP6_H */
|
||||
@@ -50,6 +50,13 @@ struct in6_addr {
|
||||
#define s6_addr32 in6_u.u6_addr32
|
||||
};
|
||||
|
||||
#define IN6_IS_ADDR_MULTICAST( addr ) \
|
||||
( *( ( const uint8_t * ) (addr) ) == 0xff )
|
||||
|
||||
#define IN6_IS_ADDR_LINKLOCAL( addr ) \
|
||||
( ( *( ( const uint16_t * ) (addr) ) & htons ( 0xffc0 ) ) == \
|
||||
htonl ( 0xfe80 ) )
|
||||
|
||||
/**
|
||||
* IPv4 socket address
|
||||
*/
|
||||
@@ -90,9 +97,13 @@ struct sockaddr_in6 {
|
||||
uint16_t sin6_flags;
|
||||
/** TCP/IP port (part of struct @c sockaddr_tcpip) */
|
||||
uint16_t sin6_port;
|
||||
uint32_t sin6_flowinfo; /* Flow number */
|
||||
struct in6_addr sin6_addr; /* 128-bit destination address */
|
||||
uint32_t sin6_scope_id; /* Scope ID */
|
||||
/** Scope ID
|
||||
*
|
||||
* For link-local addresses, this is the network device index.
|
||||
*/
|
||||
uint16_t sin6_scope_id;
|
||||
/** IPv6 address */
|
||||
struct in6_addr sin6_addr;
|
||||
/** Padding
|
||||
*
|
||||
* This ensures that a struct @c sockaddr_in6 is large
|
||||
@@ -103,20 +114,12 @@ struct sockaddr_in6 {
|
||||
( sizeof ( sa_family_t ) /* sin6_family */ +
|
||||
sizeof ( uint16_t ) /* sin6_flags */ +
|
||||
sizeof ( uint16_t ) /* sin6_port */ +
|
||||
sizeof ( uint32_t ) /* sin6_flowinfo */ +
|
||||
sizeof ( struct in6_addr ) /* sin6_addr */ +
|
||||
sizeof ( uint32_t ) /* sin6_scope_id */ ) ];
|
||||
sizeof ( uint16_t ) /* sin6_scope_id */ +
|
||||
sizeof ( struct in6_addr ) /* sin6_addr */ ) ];
|
||||
} __attribute__ (( may_alias ));
|
||||
|
||||
extern int inet_aton ( const char *cp, struct in_addr *inp );
|
||||
extern char * inet_ntoa ( struct in_addr in );
|
||||
|
||||
/* Adding the following for IP6 support
|
||||
*
|
||||
|
||||
extern int inet6_aton ( const char *cp, struct in6_addr *inp );
|
||||
extern char * inet6_ntoa ( struct in_addr in );
|
||||
|
||||
*/
|
||||
extern char * inet6_ntoa ( const struct in6_addr *in6 );
|
||||
|
||||
#endif /* _IPXE_IN_H */
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
#ifndef _IPXE_IP6_H
|
||||
#define _IPXE_IP6_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* IP6 protocol
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/in.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/tcpip.h>
|
||||
|
||||
/* IP6 constants */
|
||||
|
||||
#define IP6_VERSION 0x6
|
||||
#define IP6_HOP_LIMIT 255
|
||||
|
||||
/**
|
||||
* I/O buffer contents
|
||||
* This is duplicated in tcp.h and here. Ideally it should go into iobuf.h
|
||||
*/
|
||||
#define MAX_HDR_LEN 100
|
||||
#define MAX_IOB_LEN 1500
|
||||
#define MIN_IOB_LEN MAX_HDR_LEN + 100 /* To account for padding by LL */
|
||||
|
||||
#define IP6_EQUAL( in6_addr1, in6_addr2 ) \
|
||||
( memcmp ( ( char* ) &( in6_addr1 ), ( char* ) &( in6_addr2 ),\
|
||||
sizeof ( struct in6_addr ) ) == 0 )
|
||||
|
||||
#define IS_UNSPECIFIED( addr ) \
|
||||
( ( (addr).in6_u.u6_addr32[0] == 0x00000000 ) && \
|
||||
( (addr).in6_u.u6_addr32[1] == 0x00000000 ) && \
|
||||
( (addr).in6_u.u6_addr32[2] == 0x00000000 ) && \
|
||||
( (addr).in6_u.u6_addr32[3] == 0x00000000 ) )
|
||||
/* IP6 header */
|
||||
struct ip6_header {
|
||||
uint32_t ver_traffic_class_flow_label;
|
||||
uint16_t payload_len;
|
||||
uint8_t nxt_hdr;
|
||||
uint8_t hop_limit;
|
||||
struct in6_addr src;
|
||||
struct in6_addr dest;
|
||||
};
|
||||
|
||||
/* IP6 pseudo header */
|
||||
struct ipv6_pseudo_header {
|
||||
struct in6_addr src;
|
||||
struct in6_addr dest;
|
||||
uint8_t zero_padding;
|
||||
uint8_t nxt_hdr;
|
||||
uint16_t len;
|
||||
};
|
||||
|
||||
/* Next header numbers */
|
||||
#define IP6_HOPBYHOP 0x00
|
||||
#define IP6_ROUTING 0x43
|
||||
#define IP6_FRAGMENT 0x44
|
||||
#define IP6_AUTHENTICATION 0x51
|
||||
#define IP6_DEST_OPTS 0x60
|
||||
#define IP6_ESP 0x50
|
||||
#define IP6_ICMP6 0x58
|
||||
#define IP6_NO_HEADER 0x59
|
||||
|
||||
struct io_buffer;
|
||||
|
||||
extern struct net_protocol ipv6_protocol __net_protocol;
|
||||
extern struct tcpip_net_protocol ipv6_tcpip_protocol __tcpip_net_protocol;
|
||||
extern char * inet6_ntoa ( struct in6_addr in6 );
|
||||
|
||||
extern int add_ipv6_address ( struct net_device *netdev,
|
||||
struct in6_addr prefix, int prefix_len,
|
||||
struct in6_addr address,
|
||||
struct in6_addr gateway );
|
||||
extern void del_ipv6_address ( struct net_device *netdev );
|
||||
|
||||
#endif /* _IPXE_IP6_H */
|
||||
218
src/include/ipxe/ipv6.h
Normal file
218
src/include/ipxe/ipv6.h
Normal file
@@ -0,0 +1,218 @@
|
||||
#ifndef _IPXE_IPV6_H
|
||||
#define _IPXE_IPV6_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* IPv6 protocol
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/in.h>
|
||||
#include <ipxe/list.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
|
||||
/** IPv6 version */
|
||||
#define IPV6_VER 0x60000000UL
|
||||
|
||||
/** IPv6 version mask */
|
||||
#define IPV6_MASK_VER 0xf0000000UL
|
||||
|
||||
/** IPv6 maximum hop limit */
|
||||
#define IPV6_HOP_LIMIT 0xff
|
||||
|
||||
/** IPv6 header */
|
||||
struct ipv6_header {
|
||||
/** Version (4 bits), Traffic class (8 bits), Flow label (20 bits) */
|
||||
uint32_t ver_tc_label;
|
||||
/** Payload length, including any extension headers */
|
||||
uint16_t len;
|
||||
/** Next header type */
|
||||
uint8_t next_header;
|
||||
/** Hop limit */
|
||||
uint8_t hop_limit;
|
||||
/** Source address */
|
||||
struct in6_addr src;
|
||||
/** Destination address */
|
||||
struct in6_addr dest;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** IPv6 extension header common fields */
|
||||
struct ipv6_extension_header_common {
|
||||
/** Next header type */
|
||||
uint8_t next_header;
|
||||
/** Header extension length (excluding first 8 bytes) */
|
||||
uint8_t len;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** IPv6 type-length-value options */
|
||||
struct ipv6_option {
|
||||
/** Type */
|
||||
uint8_t type;
|
||||
/** Length */
|
||||
uint8_t len;
|
||||
/** Value */
|
||||
uint8_t value[0];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** IPv6 option types */
|
||||
enum ipv6_option_type {
|
||||
/** Pad1 */
|
||||
IPV6_OPT_PAD1 = 0x00,
|
||||
/** PadN */
|
||||
IPV6_OPT_PADN = 0x01,
|
||||
};
|
||||
|
||||
/** Test if IPv6 option can be safely ignored */
|
||||
#define IPV6_CAN_IGNORE_OPT( type ) ( ( (type) & 0xc0 ) == 0x00 )
|
||||
|
||||
/** IPv6 option-based extension header */
|
||||
struct ipv6_options_header {
|
||||
/** Extension header common fields */
|
||||
struct ipv6_extension_header_common common;
|
||||
/** Options */
|
||||
struct ipv6_option options[0];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** IPv6 routing header */
|
||||
struct ipv6_routing_header {
|
||||
/** Extension header common fields */
|
||||
struct ipv6_extension_header_common common;
|
||||
/** Routing type */
|
||||
uint8_t type;
|
||||
/** Segments left */
|
||||
uint8_t remaining;
|
||||
/** Type-specific data */
|
||||
uint8_t data[0];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** IPv6 fragment header */
|
||||
struct ipv6_fragment_header {
|
||||
/** Extension header common fields */
|
||||
struct ipv6_extension_header_common common;
|
||||
/** Fragment offset (13 bits), reserved, more fragments (1 bit) */
|
||||
uint16_t offset_more;
|
||||
/** Identification */
|
||||
uint32_t ident;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Fragment offset mask */
|
||||
#define IPV6_MASK_OFFSET 0xfff8
|
||||
|
||||
/** More fragments */
|
||||
#define IPV6_MASK_MOREFRAGS 0x0001
|
||||
|
||||
/** IPv6 extension header */
|
||||
union ipv6_extension_header {
|
||||
/** Extension header common fields */
|
||||
struct ipv6_extension_header_common common;
|
||||
/** Minimum size padding */
|
||||
uint8_t pad[8];
|
||||
/** Generic options header */
|
||||
struct ipv6_options_header options;
|
||||
/** Hop-by-hop options header */
|
||||
struct ipv6_options_header hopbyhop;
|
||||
/** Routing header */
|
||||
struct ipv6_routing_header routing;
|
||||
/** Fragment header */
|
||||
struct ipv6_fragment_header fragment;
|
||||
/** Destination options header */
|
||||
struct ipv6_options_header destination;
|
||||
};
|
||||
|
||||
/** IPv6 header types */
|
||||
enum ipv6_header_type {
|
||||
/** IPv6 hop-by-hop options header type */
|
||||
IPV6_HOPBYHOP = 0,
|
||||
/** IPv6 routing header type */
|
||||
IPV6_ROUTING = 43,
|
||||
/** IPv6 fragment header type */
|
||||
IPV6_FRAGMENT = 44,
|
||||
/** IPv6 no next header type */
|
||||
IPV6_NO_HEADER = 59,
|
||||
/** IPv6 destination options header type */
|
||||
IPV6_DESTINATION = 60,
|
||||
};
|
||||
|
||||
/** IPv6 pseudo-header */
|
||||
struct ipv6_pseudo_header {
|
||||
/** Source address */
|
||||
struct in6_addr src;
|
||||
/** Destination address */
|
||||
struct in6_addr dest;
|
||||
/** Upper-layer packet length */
|
||||
uint32_t len;
|
||||
/** Zero padding */
|
||||
uint8_t zero[3];
|
||||
/** Next header */
|
||||
uint8_t next_header;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An IPv6 address/routing table entry */
|
||||
struct ipv6_miniroute {
|
||||
/** List of miniroutes */
|
||||
struct list_head list;
|
||||
|
||||
/** Network device */
|
||||
struct net_device *netdev;
|
||||
|
||||
/** IPv6 address */
|
||||
struct in6_addr address;
|
||||
/** Prefix length */
|
||||
unsigned int prefix_len;
|
||||
/** IPv6 prefix mask (derived from prefix length) */
|
||||
struct in6_addr prefix_mask;
|
||||
/** Router address is present */
|
||||
int has_router;
|
||||
/** Router address */
|
||||
struct in6_addr router;
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct link-local address (via EUI-64)
|
||||
*
|
||||
* @v addr Address to construct
|
||||
* @v netdev Network device
|
||||
* @ret prefix_len Prefix length, or negative error
|
||||
*/
|
||||
static inline int ipv6_link_local ( struct in6_addr *addr,
|
||||
struct net_device *netdev ) {
|
||||
struct ll_protocol *ll_protocol = netdev->ll_protocol;
|
||||
const void *ll_addr = netdev->ll_addr;
|
||||
int rc;
|
||||
|
||||
memset ( addr, 0, sizeof ( *addr ) );
|
||||
addr->s6_addr16[0] = htons ( 0xfe80 );
|
||||
if ( ( rc = ll_protocol->eui64 ( ll_addr, &addr->s6_addr[8] ) ) != 0 )
|
||||
return rc;
|
||||
addr->s6_addr[8] ^= 0x02;
|
||||
return 64;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct solicited-node multicast address
|
||||
*
|
||||
* @v addr Address to construct
|
||||
* @v unicast Unicast address
|
||||
*/
|
||||
static inline void ipv6_solicited_node ( struct in6_addr *addr,
|
||||
const struct in6_addr *unicast ) {
|
||||
|
||||
memset ( addr, 0, sizeof ( *addr ) );
|
||||
addr->s6_addr16[0] = htons ( 0xff02 );
|
||||
addr->s6_addr[11] = 1;
|
||||
addr->s6_addr[12] = 0xff;
|
||||
memcpy ( &addr->s6_addr[13], &unicast->s6_addr[13], 3 );
|
||||
}
|
||||
|
||||
extern struct list_head ipv6_miniroutes;
|
||||
|
||||
extern struct net_protocol ipv6_protocol __net_protocol;
|
||||
|
||||
extern int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr );
|
||||
|
||||
#endif /* _IPXE_IPV6_H */
|
||||
@@ -1,21 +1,80 @@
|
||||
#ifndef _IPXE_NDP_H
|
||||
#define _IPXE_NDP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Neighbour discovery protocol
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <byteswap.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/icmp6.h>
|
||||
#include <ipxe/ip6.h>
|
||||
#include <ipxe/in.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/tcpip.h>
|
||||
#include <ipxe/ipv6.h>
|
||||
#include <ipxe/icmpv6.h>
|
||||
#include <ipxe/neighbour.h>
|
||||
|
||||
#define NDP_STATE_INVALID 0
|
||||
#define NDP_STATE_INCOMPLETE 1
|
||||
#define NDP_STATE_REACHABLE 2
|
||||
#define NDP_STATE_DELAY 3
|
||||
#define NDP_STATE_PROBE 4
|
||||
#define NDP_STATE_STALE 5
|
||||
/** An NDP option */
|
||||
struct ndp_option {
|
||||
/** Type */
|
||||
uint8_t type;
|
||||
/** Length (in blocks of 8 bytes) */
|
||||
uint8_t blocks;
|
||||
/** Value */
|
||||
uint8_t value[0];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
int ndp_resolve ( struct net_device *netdev, struct in6_addr *src,
|
||||
struct in6_addr *dest, void *dest_ll_addr );
|
||||
int ndp_process_advert ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
|
||||
struct sockaddr_tcpip *st_dest );
|
||||
/** NDP option block size */
|
||||
#define NDP_OPTION_BLKSZ 8
|
||||
|
||||
/** An NDP header */
|
||||
struct ndp_header {
|
||||
/** ICMPv6 header */
|
||||
struct icmpv6_header icmp;
|
||||
/** Flags */
|
||||
uint8_t flags;
|
||||
/** Reserved */
|
||||
uint8_t reserved[3];
|
||||
/** Target address */
|
||||
struct in6_addr target;
|
||||
/** Options */
|
||||
struct ndp_option option[0];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** NDP router flag */
|
||||
#define NDP_ROUTER 0x80
|
||||
|
||||
/** NDP solicited flag */
|
||||
#define NDP_SOLICITED 0x40
|
||||
|
||||
/** NDP override flag */
|
||||
#define NDP_OVERRIDE 0x20
|
||||
|
||||
/** NDP source link-layer address option */
|
||||
#define NDP_OPT_LL_SOURCE 1
|
||||
|
||||
/** NDP target link-layer address option */
|
||||
#define NDP_OPT_LL_TARGET 2
|
||||
|
||||
extern struct neighbour_discovery ndp_discovery;
|
||||
|
||||
/**
|
||||
* Transmit packet, determining link-layer address via NDP
|
||||
*
|
||||
* @v iobuf I/O buffer
|
||||
* @v netdev Network device
|
||||
* @v net_dest Destination network-layer address
|
||||
* @v net_source Source network-layer address
|
||||
* @v ll_source Source link-layer address
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static inline int ndp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
const void *net_dest, const void *net_source,
|
||||
const void *ll_source ) {
|
||||
|
||||
return neighbour_tx ( iobuf, netdev, &ipv6_protocol, net_dest,
|
||||
&ndp_discovery, net_source, ll_source );
|
||||
}
|
||||
|
||||
#endif /* _IPXE_NDP_H */
|
||||
|
||||
Reference in New Issue
Block a user