1 #ifndef _IPXE_IPV6_H
2 #define _IPXE_IPV6_H
3 
4 /** @file
5  *
6  * IPv6 protocol
7  *
8  */
9 
10 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11 
12 #include <stdint.h>
13 #include <string.h>
14 #include <byteswap.h>
15 #include <ipxe/in.h>
16 #include <ipxe/list.h>
17 #include <ipxe/netdevice.h>
18 
19 /** IPv6 version */
20 #define IPV6_VER 0x60000000UL
21 
22 /** IPv6 version mask */
23 #define IPV6_MASK_VER 0xf0000000UL
24 
25 /** IPv6 maximum hop limit */
26 #define IPV6_HOP_LIMIT 0xff
27 
28 /** IPv6 default prefix length */
29 #define IPV6_DEFAULT_PREFIX_LEN 64
30 
31 /** IPv6 maximum prefix length */
32 #define IPV6_MAX_PREFIX_LEN 128
33 
34 /** IPv6 header */
35 struct ipv6_header {
36 	/** Version (4 bits), Traffic class (8 bits), Flow label (20 bits) */
37 	uint32_t ver_tc_label;
38 	/** Payload length, including any extension headers */
39 	uint16_t len;
40 	/** Next header type */
41 	uint8_t next_header;
42 	/** Hop limit */
43 	uint8_t hop_limit;
44 	/** Source address */
45 	struct in6_addr src;
46 	/** Destination address */
47 	struct in6_addr dest;
48 } __attribute__ (( packed ));
49 
50 /** IPv6 extension header common fields */
51 struct ipv6_extension_header_common {
52 	/** Next header type */
53 	uint8_t next_header;
54 	/** Header extension length (excluding first 8 bytes) */
55 	uint8_t len;
56 } __attribute__ (( packed ));
57 
58 /** IPv6 type-length-value options */
59 struct ipv6_option {
60 	/** Type */
61 	uint8_t type;
62 	/** Length */
63 	uint8_t len;
64 	/** Value */
65 	uint8_t value[0];
66 } __attribute__ (( packed ));
67 
68 /** IPv6 option types */
69 enum ipv6_option_type {
70 	/** Pad1 */
71 	IPV6_OPT_PAD1 = 0x00,
72 	/** PadN */
73 	IPV6_OPT_PADN = 0x01,
74 };
75 
76 /** Test if IPv6 option can be safely ignored */
77 #define IPV6_CAN_IGNORE_OPT( type ) ( ( (type) & 0xc0 ) == 0x00 )
78 
79 /** IPv6 option-based extension header */
80 struct ipv6_options_header {
81 	/** Extension header common fields */
82 	struct ipv6_extension_header_common common;
83 	/** Options */
84 	struct ipv6_option options[0];
85 } __attribute__ (( packed ));
86 
87 /** IPv6 routing header */
88 struct ipv6_routing_header {
89 	/** Extension header common fields */
90 	struct ipv6_extension_header_common common;
91 	/** Routing type */
92 	uint8_t type;
93 	/** Segments left */
94 	uint8_t remaining;
95 	/** Type-specific data */
96 	uint8_t data[0];
97 } __attribute__ (( packed ));
98 
99 /** IPv6 fragment header */
100 struct ipv6_fragment_header {
101 	/** Extension header common fields */
102 	struct ipv6_extension_header_common common;
103 	/** Fragment offset (13 bits), reserved, more fragments (1 bit) */
104 	uint16_t offset_more;
105 	/** Identification */
106 	uint32_t ident;
107 } __attribute__ (( packed ));
108 
109 /** Fragment offset mask */
110 #define IPV6_MASK_OFFSET 0xfff8
111 
112 /** More fragments */
113 #define IPV6_MASK_MOREFRAGS 0x0001
114 
115 /** IPv6 extension header */
116 union ipv6_extension_header {
117 	/** Extension header common fields */
118 	struct ipv6_extension_header_common common;
119 	/** Minimum size padding */
120 	uint8_t pad[8];
121 	/** Generic options header */
122 	struct ipv6_options_header options;
123 	/** Hop-by-hop options header */
124 	struct ipv6_options_header hopbyhop;
125 	/** Routing header */
126 	struct ipv6_routing_header routing;
127 	/** Fragment header */
128 	struct ipv6_fragment_header fragment;
129 	/** Destination options header */
130 	struct ipv6_options_header destination;
131 };
132 
133 /** IPv6 header types */
134 enum ipv6_header_type {
135 	/** IPv6 hop-by-hop options header type */
136 	IPV6_HOPBYHOP = 0,
137 	/** IPv6 routing header type */
138 	IPV6_ROUTING = 43,
139 	/** IPv6 fragment header type */
140 	IPV6_FRAGMENT = 44,
141 	/** IPv6 no next header type */
142 	IPV6_NO_HEADER = 59,
143 	/** IPv6 destination options header type */
144 	IPV6_DESTINATION = 60,
145 };
146 
147 /** IPv6 pseudo-header */
148 struct ipv6_pseudo_header {
149 	/** Source address */
150 	struct in6_addr src;
151 	/** Destination address */
152 	struct in6_addr dest;
153 	/** Upper-layer packet length */
154 	uint32_t len;
155 	/** Zero padding */
156 	uint8_t zero[3];
157 	/** Next header */
158 	uint8_t next_header;
159 } __attribute__ (( packed ));
160 
161 /** IPv6 address scopes */
162 enum ipv6_address_scope {
163 	/** Interface-local address scope */
164 	IPV6_SCOPE_INTERFACE_LOCAL = 0x1,
165 	/** Link-local address scope */
166 	IPV6_SCOPE_LINK_LOCAL = 0x2,
167 	/** Admin-local address scope */
168 	INV6_SCOPE_ADMIN_LOCAL = 0x4,
169 	/** Site-local address scope */
170 	IPV6_SCOPE_SITE_LOCAL = 0x5,
171 	/** Organisation-local address scope */
172 	IPV6_SCOPE_ORGANISATION_LOCAL = 0x8,
173 	/** Global address scope */
174 	IPV6_SCOPE_GLOBAL = 0xe,
175 	/** Maximum scope */
176 	IPV6_SCOPE_MAX = 0xf,
177 };
178 
179 /** An IPv6 address/routing table entry */
180 struct ipv6_miniroute {
181 	/** List of miniroutes */
182 	struct list_head list;
183 
184 	/** Network device */
185 	struct net_device *netdev;
186 
187 	/** IPv6 address (or prefix if no address is defined) */
188 	struct in6_addr address;
189 	/** Prefix length */
190 	unsigned int prefix_len;
191 	/** IPv6 prefix mask (derived from prefix length) */
192 	struct in6_addr prefix_mask;
193 	/** Router address */
194 	struct in6_addr router;
195 	/** Scope */
196 	unsigned int scope;
197 	/** Flags */
198 	unsigned int flags;
199 };
200 
201 /** IPv6 address/routing table entry flags */
202 enum ipv6_miniroute_flags {
203 	/** Routing table entry address is valid */
204 	IPV6_HAS_ADDRESS = 0x0001,
205 	/** Routing table entry router address is valid */
206 	IPV6_HAS_ROUTER = 0x0002,
207 };
208 
209 /**
210  * Construct local IPv6 address via EUI-64
211  *
212  * @v addr		Prefix to be completed
213  * @v netdev		Network device
214  * @ret prefix_len	Prefix length, or negative error
215  */
ipv6_eui64(struct in6_addr * addr,struct net_device * netdev)216 static inline int ipv6_eui64 ( struct in6_addr *addr,
217 			       struct net_device *netdev ) {
218 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
219 	const void *ll_addr = netdev->ll_addr;
220 	int rc;
221 
222 	if ( ( rc = ll_protocol->eui64 ( ll_addr, &addr->s6_addr[8] ) ) != 0 )
223 		return rc;
224 	addr->s6_addr[8] ^= 0x02;
225 	return 64;
226 }
227 
228 /**
229  * Construct link-local address via EUI-64
230  *
231  * @v addr		Zeroed address to construct
232  * @v netdev		Network device
233  * @ret prefix_len	Prefix length, or negative error
234  */
ipv6_link_local(struct in6_addr * addr,struct net_device * netdev)235 static inline int ipv6_link_local ( struct in6_addr *addr,
236 				    struct net_device *netdev ) {
237 
238 	addr->s6_addr16[0] = htons ( 0xfe80 );
239 	return ipv6_eui64 ( addr, netdev );
240 }
241 
242 /**
243  * Construct solicited-node multicast address
244  *
245  * @v addr		Zeroed address to construct
246  * @v unicast		Unicast address
247  */
ipv6_solicited_node(struct in6_addr * addr,const struct in6_addr * unicast)248 static inline void ipv6_solicited_node ( struct in6_addr *addr,
249 					 const struct in6_addr *unicast ) {
250 
251 	addr->s6_addr16[0] = htons ( 0xff02 );
252 	addr->s6_addr[11] = 1;
253 	addr->s6_addr[12] = 0xff;
254 	memcpy ( &addr->s6_addr[13], &unicast->s6_addr[13], 3 );
255 }
256 
257 /**
258  * Construct all-routers multicast address
259  *
260  * @v addr		Zeroed address to construct
261  */
ipv6_all_routers(struct in6_addr * addr)262 static inline void ipv6_all_routers ( struct in6_addr *addr ) {
263 	addr->s6_addr16[0] = htons ( 0xff02 );
264 	addr->s6_addr[15] = 2;
265 }
266 
267 /**
268  * Get multicast address scope
269  *
270  * @v addr		Multicast address
271  * @ret scope		Address scope
272  */
273 static inline unsigned int
ipv6_multicast_scope(const struct in6_addr * addr)274 ipv6_multicast_scope ( const struct in6_addr *addr ) {
275 
276 	return ( addr->s6_addr[1] & 0x0f );
277 }
278 
279 /** IPv6 settings sibling order */
280 enum ipv6_settings_order {
281 	/** No address */
282 	IPV6_ORDER_PREFIX_ONLY = -4,
283 	/** Link-local address */
284 	IPV6_ORDER_LINK_LOCAL = -3,
285 	/** Address assigned via SLAAC */
286 	IPV6_ORDER_SLAAC = -2,
287 	/** Address assigned via DHCPv6 */
288 	IPV6_ORDER_DHCPV6 = -1,
289 };
290 
291 /** IPv6 link-local address settings block name */
292 #define IPV6_SETTINGS_NAME "link"
293 
294 extern struct list_head ipv6_miniroutes;
295 
296 extern struct net_protocol ipv6_protocol __net_protocol;
297 
298 extern int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr );
299 extern int ipv6_add_miniroute ( struct net_device *netdev,
300 				struct in6_addr *address,
301 				unsigned int prefix_len,
302 				struct in6_addr *router );
303 extern void ipv6_del_miniroute ( struct ipv6_miniroute *miniroute );
304 extern struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
305 					    struct in6_addr **dest );
306 extern int parse_ipv6_setting ( const struct setting_type *type,
307 				const char *value, void *buf, size_t len );
308 extern int format_ipv6_setting ( const struct setting_type *type,
309 				 const void *raw, size_t raw_len, char *buf,
310 				 size_t len );
311 
312 #endif /* _IPXE_IPV6_H */
313