1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * Copyright (c) 2013
4 * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
5 */
6
7#ifndef SLIRP_IP6_H
8#define SLIRP_IP6_H
9
10#include <glib.h>
11#include <string.h>
12
13#define ALLNODES_MULTICAST \
14 { \
15 .s6_addr = { \
16 0xff, \
17 0x02, \
18 0x00, \
19 0x00, \
20 0x00, \
21 0x00, \
22 0x00, \
23 0x00, \
24 0x00, \
25 0x00, \
26 0x00, \
27 0x00, \
28 0x00, \
29 0x00, \
30 0x00, \
31 0x01 \
32 } \
33 }
34
35#define SOLICITED_NODE_PREFIX \
36 { \
37 .s6_addr = { \
38 0xff, \
39 0x02, \
40 0x00, \
41 0x00, \
42 0x00, \
43 0x00, \
44 0x00, \
45 0x00, \
46 0x00, \
47 0x00, \
48 0x00, \
49 0x01, \
50 0xff, \
51 0x00, \
52 0x00, \
53 0x00 \
54 } \
55 }
56
57#define LINKLOCAL_ADDR \
58 { \
59 .s6_addr = { \
60 0xfe, \
61 0x80, \
62 0x00, \
63 0x00, \
64 0x00, \
65 0x00, \
66 0x00, \
67 0x00, \
68 0x00, \
69 0x00, \
70 0x00, \
71 0x00, \
72 0x00, \
73 0x00, \
74 0x00, \
75 0x02 \
76 } \
77 }
78
79#define ZERO_ADDR \
80 { \
81 .s6_addr = { \
82 0x00, \
83 0x00, \
84 0x00, \
85 0x00, \
86 0x00, \
87 0x00, \
88 0x00, \
89 0x00, \
90 0x00, \
91 0x00, \
92 0x00, \
93 0x00, \
94 0x00, \
95 0x00, \
96 0x00, \
97 0x00 \
98 } \
99 }
100
101static inline bool in6_equal(const struct in6_addr *a, const struct in6_addr *b)
102{
103 return memcmp(a, b, sizeof(*a)) == 0;
104}
105
106static inline bool in6_equal_net(const struct in6_addr *a,
107 const struct in6_addr *b, int prefix_len)
108{
109 if (memcmp(a, b, prefix_len / 8) != 0) {
110 return 0;
111 }
112
113 if (prefix_len % 8 == 0) {
114 return 1;
115 }
116
117 return a->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)) ==
118 b->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8));
119}
120
121static inline bool in6_equal_mach(const struct in6_addr *a,
122 const struct in6_addr *b, int prefix_len)
123{
124 if (memcmp(&(a->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
125 &(b->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
126 16 - DIV_ROUND_UP(prefix_len, 8)) != 0) {
127 return 0;
128 }
129
130 if (prefix_len % 8 == 0) {
131 return 1;
132 }
133
134 return (a->s6_addr[prefix_len / 8] &
135 ((1U << (8 - (prefix_len % 8))) - 1)) ==
136 (b->s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1));
137}
138
139
140#define in6_equal_router(a) \
141 ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len) && \
142 in6_equal_mach(a, &slirp->vhost_addr6, slirp->vprefix_len)) || \
143 (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64) && \
144 in6_equal_mach(a, &slirp->vhost_addr6, 64)))
145
146#define in6_equal_dns(a) \
147 ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len) && \
148 in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len)) || \
149 (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64) && \
150 in6_equal_mach(a, &slirp->vnameserver_addr6, 64)))
151
152#define in6_equal_host(a) (in6_equal_router(a) || in6_equal_dns(a))
153
154#define in6_solicitednode_multicast(a) \
155 (in6_equal_net(a, &(struct in6_addr)SOLICITED_NODE_PREFIX, 104))
156
157#define in6_zero(a) (in6_equal(a, &(struct in6_addr)ZERO_ADDR))
158
159/* Compute emulated host MAC address from its ipv6 address */
160static inline void in6_compute_ethaddr(struct in6_addr ip,
161 uint8_t eth[ETH_ALEN])
162{
163 eth[0] = 0x52;
164 eth[1] = 0x56;
165 memcpy(&eth[2], &ip.s6_addr[16 - (ETH_ALEN - 2)], ETH_ALEN - 2);
166}
167
168/*
169 * Definitions for internet protocol version 6.
170 * Per RFC 2460, December 1998.
171 */
172#define IP6VERSION 6
173#define IP6_HOP_LIMIT 255
174
175/*
176 * Structure of an internet header, naked of options.
177 */
178struct ip6 {
179#if G_BYTE_ORDER == G_BIG_ENDIAN
180 uint32_t ip_v : 4, /* version */
181 ip_tc_hi : 4, /* traffic class */
182 ip_tc_lo : 4, ip_fl_hi : 4, /* flow label */
183 ip_fl_lo : 16;
184#else
185 uint32_t ip_tc_hi : 4, ip_v : 4, ip_fl_hi : 4, ip_tc_lo : 4, ip_fl_lo : 16;
186#endif
187 uint16_t ip_pl; /* payload length */
188 uint8_t ip_nh; /* next header */
189 uint8_t ip_hl; /* hop limit */
190 struct in6_addr ip_src, ip_dst; /* source and dest address */
191};
192
193/*
194 * IPv6 pseudo-header used by upper-layer protocols
195 */
196struct ip6_pseudohdr {
197 struct in6_addr ih_src; /* source internet address */
198 struct in6_addr ih_dst; /* destination internet address */
199 uint32_t ih_pl; /* upper-layer packet length */
200 uint16_t ih_zero_hi; /* zero */
201 uint8_t ih_zero_lo; /* zero */
202 uint8_t ih_nh; /* next header */
203};
204
205/*
206 * We don't want to mark these ip6 structs as packed as they are naturally
207 * correctly aligned; instead assert that there is no stray padding.
208 * If we marked the struct as packed then we would be unable to take
209 * the address of any of the fields in it.
210 */
211G_STATIC_ASSERT(sizeof(struct ip6) == 40);
212G_STATIC_ASSERT(sizeof(struct ip6_pseudohdr) == 40);
213
214#endif
215