]>
git.saurik.com Git - apple/libinfo.git/blob - gen.subproj/rthdr.c
1 /* $KAME: rthdr.c,v 1.19 2003/06/06 10:48:51 itojun Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
32 /* __FBSDID("$FreeBSD: src/lib/libc/net/rthdr.c,v 1.9.10.1.4.1 2010/06/14 02:09:06 kensmith Exp $"); */
35 * These routines support RFC 2292.
36 * __APPLE_USE_RFC_2292 selects the appropriate API in <netinet6/in6.h>
38 #define __APPLE_USE_RFC_2292
40 #include <sys/cdefs.h>
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <netinet/ip6.h>
57 inet6_rthdr_space(type
, seg
)
61 case IPV6_RTHDR_TYPE_0
:
62 if (seg
< 1 || seg
> 23)
65 return (CMSG_SPACE(sizeof(struct in6_addr
) * (seg
- 1) +
66 sizeof(struct ip6_rthdr0
)));
68 return (CMSG_SPACE(sizeof(struct in6_addr
) * seg
+
69 sizeof(struct ip6_rthdr0
)));
77 inet6_rthdr_init(bp
, type
)
81 struct cmsghdr
*ch
= (struct cmsghdr
*)bp
;
82 struct ip6_rthdr
*rthdr
;
84 rthdr
= (struct ip6_rthdr
*)CMSG_DATA(ch
);
86 ch
->cmsg_level
= IPPROTO_IPV6
;
87 ch
->cmsg_type
= IPV6_RTHDR
;
90 case IPV6_RTHDR_TYPE_0
:
92 ch
->cmsg_len
= CMSG_LEN(sizeof(struct ip6_rthdr0
) -
93 sizeof(struct in6_addr
));
95 ch
->cmsg_len
= CMSG_LEN(sizeof(struct ip6_rthdr0
));
98 bzero(rthdr
, sizeof(struct ip6_rthdr0
));
99 rthdr
->ip6r_type
= IPV6_RTHDR_TYPE_0
;
108 inet6_rthdr_add(cmsg
, addr
, flags
)
109 struct cmsghdr
*cmsg
;
110 const struct in6_addr
*addr
;
113 struct ip6_rthdr
*rthdr
;
115 rthdr
= (struct ip6_rthdr
*)CMSG_DATA(cmsg
);
117 switch (rthdr
->ip6r_type
) {
118 case IPV6_RTHDR_TYPE_0
:
120 struct ip6_rthdr0
*rt0
= (struct ip6_rthdr0
*)rthdr
;
121 if (flags
!= IPV6_RTHDR_LOOSE
&& flags
!= IPV6_RTHDR_STRICT
)
123 if (rt0
->ip6r0_segleft
== 23)
126 #ifdef COMPAT_RFC1883 /* XXX */
127 if (flags
== IPV6_RTHDR_STRICT
) {
129 c
= rt0
->ip6r0_segleft
/ 8;
130 b
= rt0
->ip6r0_segleft
% 8;
131 rt0
->ip6r0_slmap
[c
] |= (1 << (7 - b
));
134 if (flags
!= IPV6_RTHDR_LOOSE
)
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);
153 inet6_rthdr_lasthop(cmsg
, flags
)
154 struct cmsghdr
*cmsg
;
157 struct ip6_rthdr
*rthdr
;
159 rthdr
= (struct ip6_rthdr
*)CMSG_DATA(cmsg
);
161 switch (rthdr
->ip6r_type
) {
162 case IPV6_RTHDR_TYPE_0
:
164 struct ip6_rthdr0
*rt0
= (struct ip6_rthdr0
*)rthdr
;
165 #ifdef COMPAT_RFC1883 /* XXX */
166 if (flags
!= IPV6_RTHDR_LOOSE
&& flags
!= IPV6_RTHDR_STRICT
)
168 #endif /* COMPAT_RFC1883 */
169 if (rt0
->ip6r0_segleft
> 23)
171 #ifdef COMPAT_RFC1883 /* XXX */
172 if (flags
== IPV6_RTHDR_STRICT
) {
174 c
= rt0
->ip6r0_segleft
/ 8;
175 b
= rt0
->ip6r0_segleft
% 8;
176 rt0
->ip6r0_slmap
[c
] |= (1 << (7 - b
));
179 if (flags
!= IPV6_RTHDR_LOOSE
)
181 #endif /* COMPAT_RFC1883 */
193 inet6_rthdr_reverse(in
, out
)
194 const struct cmsghdr
*in
;
203 inet6_rthdr_segments(cmsg
)
204 const struct cmsghdr
*cmsg
;
206 struct ip6_rthdr
*rthdr
;
208 rthdr
= (struct ip6_rthdr
*)CMSG_DATA(cmsg
);
210 switch (rthdr
->ip6r_type
) {
211 case IPV6_RTHDR_TYPE_0
:
213 struct ip6_rthdr0
*rt0
= (struct ip6_rthdr0
*)rthdr
;
215 if (rt0
->ip6r0_len
% 2 || 46 < rt0
->ip6r0_len
)
218 return (rt0
->ip6r0_len
* 8) / sizeof(struct in6_addr
);
227 inet6_rthdr_getaddr(cmsg
, idx
)
228 struct cmsghdr
*cmsg
;
231 struct ip6_rthdr
*rthdr
;
233 rthdr
= (struct ip6_rthdr
*)CMSG_DATA(cmsg
);
235 switch (rthdr
->ip6r_type
) {
236 case IPV6_RTHDR_TYPE_0
:
238 struct ip6_rthdr0
*rt0
= (struct ip6_rthdr0
*)rthdr
;
241 if (rt0
->ip6r0_len
% 2 || 46 < rt0
->ip6r0_len
)
243 naddr
= (rt0
->ip6r0_len
* 8) / sizeof(struct in6_addr
);
244 if (idx
<= 0 || naddr
< idx
)
246 #ifdef COMPAT_RFC2292
247 return (((struct in6_addr
*)(rt0
+ 1)) + idx
- 1);
249 return (((struct in6_addr
*)(rt0
+ 1)) + idx
);
259 inet6_rthdr_getflags(cmsg
, idx
)
260 const struct cmsghdr
*cmsg
;
263 struct ip6_rthdr
*rthdr
;
265 rthdr
= (struct ip6_rthdr
*)CMSG_DATA(cmsg
);
267 switch (rthdr
->ip6r_type
) {
268 case IPV6_RTHDR_TYPE_0
:
270 struct ip6_rthdr0
*rt0
= (struct ip6_rthdr0
*)rthdr
;
273 if (rt0
->ip6r0_len
% 2 || 46 < rt0
->ip6r0_len
)
275 naddr
= (rt0
->ip6r0_len
* 8) / sizeof(struct in6_addr
);
276 if (idx
< 0 || naddr
< idx
)
278 #ifdef COMPAT_RFC1883 /* XXX */
279 if (rt0
->ip6r0_slmap
[idx
/ 8] & (0x80 >> (idx
% 8)))
280 return IPV6_RTHDR_STRICT
;
282 return IPV6_RTHDR_LOOSE
;
284 return IPV6_RTHDR_LOOSE
;
285 #endif /* COMPAT_RFC1883 */
298 inet6_rth_space(int type
, int segments
)
301 case IPV6_RTHDR_TYPE_0
:
302 if ((segments
>= 0) && (segments
<= 127))
303 return (((segments
* 2) + 1) << 3);
306 return (0); /* type not suppported */
311 inet6_rth_init(void *bp
, socklen_t bp_len
, int type
, int segments
)
313 struct ip6_rthdr
*rth
= (struct ip6_rthdr
*)bp
;
314 struct ip6_rthdr0
*rth0
;
317 case IPV6_RTHDR_TYPE_0
:
318 /* length validation */
319 if (bp_len
< inet6_rth_space(IPV6_RTHDR_TYPE_0
, segments
))
321 /* segment validation */
322 if ((segments
< 0) || (segments
> 127))
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;
333 return (NULL
); /* type not supported */
340 inet6_rth_add(void *bp
, const struct in6_addr
*addr
)
342 struct ip6_rthdr
*rth
= (struct ip6_rthdr
*)bp
;
343 struct ip6_rthdr0
*rth0
;
344 struct in6_addr
*nextaddr
;
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))
352 nextaddr
= (struct in6_addr
*)(rth0
+ 1) + rth0
->ip6r0_segleft
;
354 rth0
->ip6r0_segleft
++;
357 return (-1); /* type not supported */
364 inet6_rth_reverse(const void *in
, void *out
)
366 struct ip6_rthdr
*rth_in
= (struct ip6_rthdr
*)in
;
367 struct ip6_rthdr0
*rth0_in
, *rth0_out
;
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
;
375 /* parameter validation XXX too paranoid? */
376 if (rth0_in
->ip6r0_len
% 2)
378 segments
= rth0_in
->ip6r0_len
/ 2;
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
;
385 /* reverse the addresses */
386 for (i
= 0; i
< segments
/ 2; i
++) {
387 struct in6_addr addr_tmp
, *addr1
, *addr2
;
389 addr1
= (struct in6_addr
*)(rth0_out
+ 1) + i
;
390 addr2
= (struct in6_addr
*)(rth0_out
+ 1) +
399 return (-1); /* type not supported */
406 inet6_rth_segments(const void *bp
)
408 struct ip6_rthdr
*rh
= (struct ip6_rthdr
*)bp
;
409 struct ip6_rthdr0
*rh0
;
412 switch (rh
->ip6r_type
) {
413 case IPV6_RTHDR_TYPE_0
:
414 rh0
= (struct ip6_rthdr0
*)bp
;
417 * Validation for a type-0 routing header.
418 * Is this too strict?
420 if ((rh0
->ip6r0_len
% 2) != 0 ||
421 (addrs
= (rh0
->ip6r0_len
>> 1)) < rh0
->ip6r0_segleft
)
426 return (-1); /* unknown type */
431 inet6_rth_getaddr(const void *bp
, int idx
)
433 struct ip6_rthdr
*rh
= (struct ip6_rthdr
*)bp
;
434 struct ip6_rthdr0
*rh0
;
437 switch (rh
->ip6r_type
) {
438 case IPV6_RTHDR_TYPE_0
:
439 rh0
= (struct ip6_rthdr0
*)bp
;
442 * Validation for a type-0 routing header.
443 * Is this too strict?
445 if ((rh0
->ip6r0_len
% 2) != 0 ||
446 (addrs
= (rh0
->ip6r0_len
>> 1)) < rh0
->ip6r0_segleft
)
449 if (idx
< 0 || addrs
<= idx
)
452 return (((struct in6_addr
*)(rh0
+ 1)) + idx
);
454 return (NULL
); /* unknown type */