Libinfo-517.200.9.tar.gz
[apple/libinfo.git] / gen.subproj / rthdr.c
1 /*
2 * Copyright (c) 2018 Apple Inc. All rights reserved.
3 */
4 /* $KAME: rthdr.c,v 1.19 2003/06/06 10:48:51 itojun Exp $ */
5
6 /*
7 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the project nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /* __FBSDID("$FreeBSD: src/lib/libc/net/rthdr.c,v 1.9.10.1.4.1 2010/06/14 02:09:06 kensmith Exp $"); */
36
37 #include "libinfo_common.h"
38
39 /*
40 * These routines support RFC 2292.
41 * __APPLE_USE_RFC_2292 selects the appropriate API in <netinet6/in6.h>
42 */
43 #define __APPLE_USE_RFC_2292
44
45 #include <sys/cdefs.h>
46
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <sys/socket.h>
50
51 #include <netinet/in.h>
52 #include <netinet/ip6.h>
53
54 #include <string.h>
55 #include <stdio.h>
56
57 /*
58 * RFC2292 API
59 */
60
61 LIBINFO_EXPORT
62 size_t
63 inet6_rthdr_space(type, seg)
64 int type, seg;
65 {
66 switch (type) {
67 case IPV6_RTHDR_TYPE_0:
68 if (seg < 1 || seg > 23)
69 return (0);
70 #ifdef COMPAT_RFC2292
71 return (CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) +
72 sizeof(struct ip6_rthdr0)));
73 #else
74 return (CMSG_SPACE(sizeof(struct in6_addr) * seg +
75 sizeof(struct ip6_rthdr0)));
76 #endif
77 default:
78 return (0);
79 }
80 }
81
82 LIBINFO_EXPORT
83 struct cmsghdr *
84 inet6_rthdr_init(bp, type)
85 void *bp;
86 int type;
87 {
88 struct cmsghdr *ch = (struct cmsghdr *)bp;
89 struct ip6_rthdr *rthdr;
90
91 rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
92
93 ch->cmsg_level = IPPROTO_IPV6;
94 ch->cmsg_type = IPV6_RTHDR;
95
96 switch (type) {
97 case IPV6_RTHDR_TYPE_0:
98 #ifdef COMPAT_RFC2292
99 ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) -
100 sizeof(struct in6_addr));
101 #else
102 ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0));
103 #endif
104
105 bzero(rthdr, sizeof(struct ip6_rthdr0));
106 rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
107 return (ch);
108 default:
109 return (NULL);
110 }
111 }
112
113 /* ARGSUSED */
114 LIBINFO_EXPORT
115 int
116 inet6_rthdr_add(cmsg, addr, flags)
117 struct cmsghdr *cmsg;
118 const struct in6_addr *addr;
119 u_int flags;
120 {
121 struct ip6_rthdr *rthdr;
122
123 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
124
125 switch (rthdr->ip6r_type) {
126 case IPV6_RTHDR_TYPE_0:
127 {
128 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
129 if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
130 return (-1);
131 if (rt0->ip6r0_segleft == 23)
132 return (-1);
133
134 #ifdef COMPAT_RFC1883 /* XXX */
135 if (flags == IPV6_RTHDR_STRICT) {
136 int c, b;
137 c = rt0->ip6r0_segleft / 8;
138 b = rt0->ip6r0_segleft % 8;
139 rt0->ip6r0_slmap[c] |= (1 << (7 - b));
140 }
141 #else
142 if (flags != IPV6_RTHDR_LOOSE)
143 return (-1);
144 #endif
145 rt0->ip6r0_segleft++;
146 bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3),
147 sizeof(struct in6_addr));
148 rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
149 cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
150 break;
151 }
152 default:
153 return (-1);
154 }
155
156 return (0);
157 }
158
159 /* ARGSUSED */
160 LIBINFO_EXPORT
161 int
162 inet6_rthdr_lasthop(cmsg, flags)
163 struct cmsghdr *cmsg;
164 unsigned int flags;
165 {
166 struct ip6_rthdr *rthdr;
167
168 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
169
170 switch (rthdr->ip6r_type) {
171 case IPV6_RTHDR_TYPE_0:
172 {
173 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
174 #ifdef COMPAT_RFC1883 /* XXX */
175 if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
176 return (-1);
177 #endif /* COMPAT_RFC1883 */
178 if (rt0->ip6r0_segleft > 23)
179 return (-1);
180 #ifdef COMPAT_RFC1883 /* XXX */
181 if (flags == IPV6_RTHDR_STRICT) {
182 int c, b;
183 c = rt0->ip6r0_segleft / 8;
184 b = rt0->ip6r0_segleft % 8;
185 rt0->ip6r0_slmap[c] |= (1 << (7 - b));
186 }
187 #else
188 if (flags != IPV6_RTHDR_LOOSE)
189 return (-1);
190 #endif /* COMPAT_RFC1883 */
191 break;
192 }
193 default:
194 return (-1);
195 }
196
197 return (0);
198 }
199
200 #if 0
201 int
202 inet6_rthdr_reverse(in, out)
203 const struct cmsghdr *in;
204 struct cmsghdr *out;
205 {
206
207 return (-1);
208 }
209 #endif
210
211 LIBINFO_EXPORT
212 int
213 inet6_rthdr_segments(cmsg)
214 const struct cmsghdr *cmsg;
215 {
216 struct ip6_rthdr *rthdr;
217
218 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
219
220 switch (rthdr->ip6r_type) {
221 case IPV6_RTHDR_TYPE_0:
222 {
223 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
224
225 if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
226 return (-1);
227
228 return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
229 }
230
231 default:
232 return (-1);
233 }
234 }
235
236 LIBINFO_EXPORT
237 struct in6_addr *
238 inet6_rthdr_getaddr(cmsg, idx)
239 struct cmsghdr *cmsg;
240 int idx;
241 {
242 struct ip6_rthdr *rthdr;
243
244 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
245
246 switch (rthdr->ip6r_type) {
247 case IPV6_RTHDR_TYPE_0:
248 {
249 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
250 int naddr;
251
252 if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
253 return NULL;
254 naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
255 if (idx <= 0 || naddr < idx)
256 return NULL;
257 #ifdef COMPAT_RFC2292
258 return (((struct in6_addr *)(rt0 + 1)) + idx - 1);
259 #else
260 return (((struct in6_addr *)(rt0 + 1)) + idx);
261 #endif
262 }
263
264 default:
265 return NULL;
266 }
267 }
268
269 LIBINFO_EXPORT
270 int
271 inet6_rthdr_getflags(cmsg, idx)
272 const struct cmsghdr *cmsg;
273 int idx;
274 {
275 struct ip6_rthdr *rthdr;
276
277 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
278
279 switch (rthdr->ip6r_type) {
280 case IPV6_RTHDR_TYPE_0:
281 {
282 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
283 int naddr;
284
285 if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
286 return (-1);
287 naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
288 if (idx < 0 || naddr < idx)
289 return (-1);
290 #ifdef COMPAT_RFC1883 /* XXX */
291 if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8)))
292 return IPV6_RTHDR_STRICT;
293 else
294 return IPV6_RTHDR_LOOSE;
295 #else
296 return IPV6_RTHDR_LOOSE;
297 #endif /* COMPAT_RFC1883 */
298 }
299
300 default:
301 return (-1);
302 }
303 }
304
305 /*
306 * RFC3542 API
307 */
308
309 LIBINFO_EXPORT
310 socklen_t
311 inet6_rth_space(int type, int segments)
312 {
313 switch (type) {
314 case IPV6_RTHDR_TYPE_0:
315 if ((segments >= 0) && (segments <= 127))
316 return (((segments * 2) + 1) << 3);
317 /* FALLTHROUGH */
318 default:
319 return (0); /* type not suppported */
320 }
321 }
322
323 LIBINFO_EXPORT
324 void *
325 inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
326 {
327 struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
328 struct ip6_rthdr0 *rth0;
329
330 switch (type) {
331 case IPV6_RTHDR_TYPE_0:
332 /* length validation */
333 if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments))
334 return (NULL);
335 /* segment validation */
336 if ((segments < 0) || (segments > 127))
337 return (NULL);
338
339 memset(bp, 0, bp_len);
340 rth0 = (struct ip6_rthdr0 *)rth;
341 rth0->ip6r0_len = segments * 2;
342 rth0->ip6r0_type = IPV6_RTHDR_TYPE_0;
343 rth0->ip6r0_segleft = 0;
344 rth0->ip6r0_reserved = 0;
345 break;
346 default:
347 return (NULL); /* type not supported */
348 }
349
350 return (bp);
351 }
352
353 LIBINFO_EXPORT
354 int
355 inet6_rth_add(void *bp, const struct in6_addr *addr)
356 {
357 struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
358 struct ip6_rthdr0 *rth0;
359 struct in6_addr *nextaddr;
360
361 switch (rth->ip6r_type) {
362 case IPV6_RTHDR_TYPE_0:
363 rth0 = (struct ip6_rthdr0 *)rth;
364 /* Don't exceed the number of stated segments */
365 if (rth0->ip6r0_segleft == (rth0->ip6r0_len / 2))
366 return (-1);
367 nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft;
368 *nextaddr = *addr;
369 rth0->ip6r0_segleft++;
370 break;
371 default:
372 return (-1); /* type not supported */
373 }
374
375 return (0);
376 }
377
378 LIBINFO_EXPORT
379 int
380 inet6_rth_reverse(const void *in, void *out)
381 {
382 struct ip6_rthdr *rth_in = (struct ip6_rthdr *)in;
383 struct ip6_rthdr0 *rth0_in, *rth0_out;
384 int i, segments;
385
386 switch (rth_in->ip6r_type) {
387 case IPV6_RTHDR_TYPE_0:
388 rth0_in = (struct ip6_rthdr0 *)in;
389 rth0_out = (struct ip6_rthdr0 *)out;
390
391 /* parameter validation XXX too paranoid? */
392 if (rth0_in->ip6r0_len % 2)
393 return (-1);
394 segments = rth0_in->ip6r0_len / 2;
395
396 /* we can't use memcpy here, since in and out may overlap */
397 memmove((void *)rth0_out, (void *)rth0_in,
398 ((rth0_in->ip6r0_len) + 1) << 3);
399 rth0_out->ip6r0_segleft = segments;
400
401 /* reverse the addresses */
402 for (i = 0; i < segments / 2; i++) {
403 struct in6_addr addr_tmp, *addr1, *addr2;
404
405 addr1 = (struct in6_addr *)(rth0_out + 1) + i;
406 addr2 = (struct in6_addr *)(rth0_out + 1) +
407 (segments - i - 1);
408 addr_tmp = *addr1;
409 *addr1 = *addr2;
410 *addr2 = addr_tmp;
411 }
412
413 break;
414 default:
415 return (-1); /* type not supported */
416 }
417
418 return (0);
419 }
420
421 LIBINFO_EXPORT
422 int
423 inet6_rth_segments(const void *bp)
424 {
425 struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
426 struct ip6_rthdr0 *rh0;
427 int addrs;
428
429 switch (rh->ip6r_type) {
430 case IPV6_RTHDR_TYPE_0:
431 rh0 = (struct ip6_rthdr0 *)bp;
432
433 /*
434 * Validation for a type-0 routing header.
435 * Is this too strict?
436 */
437 if ((rh0->ip6r0_len % 2) != 0 ||
438 (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
439 return (-1);
440
441 return (addrs);
442 default:
443 return (-1); /* unknown type */
444 }
445 }
446
447 LIBINFO_EXPORT
448 struct in6_addr *
449 inet6_rth_getaddr(const void *bp, int idx)
450 {
451 struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
452 struct ip6_rthdr0 *rh0;
453 int addrs;
454
455 switch (rh->ip6r_type) {
456 case IPV6_RTHDR_TYPE_0:
457 rh0 = (struct ip6_rthdr0 *)bp;
458
459 /*
460 * Validation for a type-0 routing header.
461 * Is this too strict?
462 */
463 if ((rh0->ip6r0_len % 2) != 0 ||
464 (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
465 return (NULL);
466
467 if (idx < 0 || addrs <= idx)
468 return (NULL);
469
470 return (((struct in6_addr *)(rh0 + 1)) + idx);
471 default:
472 return (NULL); /* unknown type */
473 break;
474 }
475 }