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