mirror of https://github.com/ipxe/ipxe.git
313 lines
7.7 KiB
C
313 lines
7.7 KiB
C
#ifndef _IPXE_IPV6_H
|
|
#define _IPXE_IPV6_H
|
|
|
|
/** @file
|
|
*
|
|
* IPv6 protocol
|
|
*
|
|
*/
|
|
|
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|
|
|
#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 default prefix length */
|
|
#define IPV6_DEFAULT_PREFIX_LEN 64
|
|
|
|
/** IPv6 maximum prefix length */
|
|
#define IPV6_MAX_PREFIX_LEN 128
|
|
|
|
/** 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 ));
|
|
|
|
/** IPv6 address scopes */
|
|
enum ipv6_address_scope {
|
|
/** Interface-local address scope */
|
|
IPV6_SCOPE_INTERFACE_LOCAL = 0x1,
|
|
/** Link-local address scope */
|
|
IPV6_SCOPE_LINK_LOCAL = 0x2,
|
|
/** Admin-local address scope */
|
|
INV6_SCOPE_ADMIN_LOCAL = 0x4,
|
|
/** Site-local address scope */
|
|
IPV6_SCOPE_SITE_LOCAL = 0x5,
|
|
/** Organisation-local address scope */
|
|
IPV6_SCOPE_ORGANISATION_LOCAL = 0x8,
|
|
/** Global address scope */
|
|
IPV6_SCOPE_GLOBAL = 0xe,
|
|
/** Maximum scope */
|
|
IPV6_SCOPE_MAX = 0xf,
|
|
};
|
|
|
|
/** An IPv6 address/routing table entry */
|
|
struct ipv6_miniroute {
|
|
/** List of miniroutes */
|
|
struct list_head list;
|
|
|
|
/** Network device */
|
|
struct net_device *netdev;
|
|
|
|
/** IPv6 address (or prefix if no address is defined) */
|
|
struct in6_addr address;
|
|
/** Prefix length */
|
|
unsigned int prefix_len;
|
|
/** IPv6 prefix mask (derived from prefix length) */
|
|
struct in6_addr prefix_mask;
|
|
/** Router address */
|
|
struct in6_addr router;
|
|
/** Scope */
|
|
unsigned int scope;
|
|
/** 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,
|
|
};
|
|
|
|
/**
|
|
* Construct local IPv6 address via EUI-64
|
|
*
|
|
* @v addr Prefix to be completed
|
|
* @v netdev Network device
|
|
* @ret prefix_len Prefix length, or negative error
|
|
*/
|
|
static inline int ipv6_eui64 ( 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;
|
|
|
|
if ( ( rc = ll_protocol->eui64 ( ll_addr, &addr->s6_addr[8] ) ) != 0 )
|
|
return rc;
|
|
addr->s6_addr[8] ^= 0x02;
|
|
return 64;
|
|
}
|
|
|
|
/**
|
|
* Construct link-local address via EUI-64
|
|
*
|
|
* @v addr Zeroed 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 ) {
|
|
|
|
addr->s6_addr16[0] = htons ( 0xfe80 );
|
|
return ipv6_eui64 ( addr, netdev );
|
|
}
|
|
|
|
/**
|
|
* Construct solicited-node multicast address
|
|
*
|
|
* @v addr Zeroed address to construct
|
|
* @v unicast Unicast address
|
|
*/
|
|
static inline void ipv6_solicited_node ( struct in6_addr *addr,
|
|
const struct in6_addr *unicast ) {
|
|
|
|
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 );
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* Get multicast address scope
|
|
*
|
|
* @v addr Multicast address
|
|
* @ret scope Address scope
|
|
*/
|
|
static inline unsigned int
|
|
ipv6_multicast_scope ( const struct in6_addr *addr ) {
|
|
|
|
return ( addr->s6_addr[1] & 0x0f );
|
|
}
|
|
|
|
/** IPv6 settings sibling order */
|
|
enum ipv6_settings_order {
|
|
/** No address */
|
|
IPV6_ORDER_PREFIX_ONLY = -4,
|
|
/** Link-local address */
|
|
IPV6_ORDER_LINK_LOCAL = -3,
|
|
/** Address assigned via SLAAC */
|
|
IPV6_ORDER_SLAAC = -2,
|
|
/** Address assigned via DHCPv6 */
|
|
IPV6_ORDER_DHCPV6 = -1,
|
|
};
|
|
|
|
/** IPv6 link-local address settings block name */
|
|
#define IPV6_SETTINGS_NAME "link"
|
|
|
|
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 );
|
|
extern int ipv6_add_miniroute ( struct net_device *netdev,
|
|
struct in6_addr *address,
|
|
unsigned int prefix_len,
|
|
struct in6_addr *router );
|
|
extern void ipv6_del_miniroute ( struct ipv6_miniroute *miniroute );
|
|
extern struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
|
|
struct in6_addr **dest );
|
|
extern int parse_ipv6_setting ( const struct setting_type *type,
|
|
const char *value, void *buf, size_t len );
|
|
extern int format_ipv6_setting ( const struct setting_type *type,
|
|
const void *raw, size_t raw_len, char *buf,
|
|
size_t len );
|
|
|
|
#endif /* _IPXE_IPV6_H */
|