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 
in6_equal(const struct in6_addr * a,const struct in6_addr * b)101 static 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 
in6_equal_net(const struct in6_addr * a,const struct in6_addr * b,int prefix_len)106 static 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 
in6_equal_mach(const struct in6_addr * a,const struct in6_addr * b,int prefix_len)121 static 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 */
in6_compute_ethaddr(struct in6_addr ip,uint8_t eth[ETH_ALEN])160 static 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  */
178 struct 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  */
196 struct 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  */
211 G_STATIC_ASSERT(sizeof(struct ip6) == 40);
212 G_STATIC_ASSERT(sizeof(struct ip6_pseudohdr) == 40);
213 
214 #endif
215