4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2003 Sun Microsystems, Inc.
24 * All rights reserved. Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This code is conformant to revision 7 of 2292bis. Some of these functions
31 * were provided (named inet6_rthdr_) in a very similar form in RFC 2292.
32 * The RFC 2292 variants are not supported.
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <netinet/ip6.h>
46 #define MAX_RTHDR0_SEGMENTS 127
49 * Return amount of space needed to hold N segments for the specified
50 * routing type. Does NOT include space for cmsghdr.
53 inet6_rth_space(int type
, int segments
)
55 if (type
!= IPV6_RTHDR_TYPE_0
|| segments
< 0 ||
56 segments
> MAX_RTHDR0_SEGMENTS
)
59 return (sizeof (struct ip6_rthdr0
) +
60 segments
* sizeof (struct in6_addr
));
64 * Initializes rthdr structure. Verifies the segments against the length of
66 * Note that a routing header can only hold 127 segments since the length field
67 * in the header is just a byte.
70 inet6_rth_init(void *bp
, socklen_t bp_len
, int type
, int segments
)
72 struct ip6_rthdr0
*rthdr
;
74 if (type
!= IPV6_RTHDR_TYPE_0
|| segments
< 0 ||
75 segments
> MAX_RTHDR0_SEGMENTS
)
78 if (bp_len
< sizeof (struct ip6_rthdr0
) +
79 segments
* sizeof (struct in6_addr
))
82 rthdr
= (struct ip6_rthdr0
*)bp
;
84 rthdr
->ip6r0_len
= (segments
* 2);
85 rthdr
->ip6r0_type
= type
;
86 rthdr
->ip6r0_segleft
= 0; /* Incremented by rthdr_add */
87 *(uint32_t *)&rthdr
->ip6r0_reserved
= 0;
92 * Add one more address to the routing header. Fails when there is no more
96 inet6_rth_add(void *bp
, const struct in6_addr
*addr
)
98 struct ip6_rthdr0
*rthdr
;
99 struct in6_addr
*addrs
;
101 rthdr
= (struct ip6_rthdr0
*)bp
;
102 if ((rthdr
->ip6r0_segleft
+ 1) * 2 > rthdr
->ip6r0_len
) {
103 /* Not room for one more */
106 addrs
= (struct in6_addr
*)((char *)rthdr
+ sizeof (*rthdr
));
107 addrs
[rthdr
->ip6r0_segleft
++] = *addr
;
112 * Reverse a source route. Both arguments can point to the same buffer.
115 inet6_rth_reverse(const void *in
, void *out
)
117 struct ip6_rthdr0
*rtin
, *rtout
;
120 struct in6_addr
*rtout_addrs
;
121 struct in6_addr
*rtin_addrs
;
123 rtin
= (struct ip6_rthdr0
*)in
;
124 rtout
= (struct ip6_rthdr0
*)out
;
126 if (rtout
->ip6r0_type
!= 0 || rtin
->ip6r0_type
!= 0 ||
127 rtout
->ip6r0_len
> MAX_RTHDR0_SEGMENTS
* 2 ||
128 rtin
->ip6r0_len
> MAX_RTHDR0_SEGMENTS
* 2 ||
129 rtout
->ip6r0_len
!= rtin
->ip6r0_len
)
132 segments
= rtin
->ip6r0_len
/ 2;
133 rtout_addrs
= (struct in6_addr
*)((char *)rtout
+ sizeof (*rtout
));
134 rtin_addrs
= (struct in6_addr
*)((char *)rtin
+ sizeof (*rtin
));
135 for (i
= 0; i
< (segments
+ 1)/2; i
++) {
137 rtout_addrs
[i
] = rtin_addrs
[segments
- 1 - i
];
138 rtout_addrs
[segments
- 1 - i
] = tmp
;
140 rtout
->ip6r0_segleft
= segments
;
145 * Return the number of segments in the routing header.
148 inet6_rth_segments(const void *bp
)
150 struct ip6_rthdr0
*rthdr
;
152 rthdr
= (struct ip6_rthdr0
*)bp
;
153 if (rthdr
->ip6r0_type
== 0) {
154 if (rthdr
->ip6r0_len
> MAX_RTHDR0_SEGMENTS
* 2) {
157 return (rthdr
->ip6r0_len
/ 2);
165 * Return a pointer to an element in the source route.
166 * This uses the C convention for index [0, size-1].
169 inet6_rth_getaddr(const void *bp
, int index
)
171 struct ip6_rthdr0
*rthdr
;
174 rthdr
= (struct ip6_rthdr0
*)bp
;
175 if (index
>= rthdr
->ip6r0_len
/2 || index
< 0)
178 rv
= (struct in6_addr
*)((char *)rthdr
+ sizeof (*rthdr
));