rthdr.c revision 1.13 1 1.13 itojun /* $NetBSD: rthdr.c,v 1.13 2003/06/06 06:43:18 itojun Exp $ */
2 1.2 itojun
3 1.1 itojun /*
4 1.1 itojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 1.1 itojun * All rights reserved.
6 1.1 itojun *
7 1.1 itojun * Redistribution and use in source and binary forms, with or without
8 1.1 itojun * modification, are permitted provided that the following conditions
9 1.1 itojun * are met:
10 1.1 itojun * 1. Redistributions of source code must retain the above copyright
11 1.1 itojun * notice, this list of conditions and the following disclaimer.
12 1.1 itojun * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 itojun * notice, this list of conditions and the following disclaimer in the
14 1.1 itojun * documentation and/or other materials provided with the distribution.
15 1.1 itojun * 3. Neither the name of the project nor the names of its contributors
16 1.1 itojun * may be used to endorse or promote products derived from this software
17 1.1 itojun * without specific prior written permission.
18 1.1 itojun *
19 1.1 itojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 1.1 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.1 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.1 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 1.1 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.1 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.1 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.1 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.1 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.1 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.1 itojun * SUCH DAMAGE.
30 1.1 itojun */
31 1.9 itojun
32 1.9 itojun #include <sys/cdefs.h>
33 1.9 itojun #if defined(LIBC_SCCS) && !defined(lint)
34 1.13 itojun __RCSID("$NetBSD: rthdr.c,v 1.13 2003/06/06 06:43:18 itojun Exp $");
35 1.9 itojun #endif /* LIBC_SCCS and not lint */
36 1.1 itojun
37 1.8 itojun #include "namespace.h"
38 1.1 itojun #include <sys/param.h>
39 1.1 itojun #include <sys/types.h>
40 1.1 itojun #include <sys/socket.h>
41 1.1 itojun
42 1.1 itojun #include <netinet/in.h>
43 1.1 itojun #include <netinet/ip6.h>
44 1.1 itojun
45 1.3 lukem #include <assert.h>
46 1.1 itojun #include <string.h>
47 1.1 itojun #include <stdio.h>
48 1.8 itojun
49 1.8 itojun #ifdef __weak_alias
50 1.8 itojun __weak_alias(inet6_rthdr_add,_inet6_rthdr_add)
51 1.8 itojun __weak_alias(inet6_rthdr_getaddr,_inet6_rthdr_getaddr)
52 1.8 itojun __weak_alias(inet6_rthdr_getflags,_inet6_rthdr_getflags)
53 1.8 itojun __weak_alias(inet6_rthdr_init,_inet6_rthdr_init)
54 1.8 itojun __weak_alias(inet6_rthdr_lasthop,_inet6_rthdr_lasthop)
55 1.8 itojun __weak_alias(inet6_rthdr_segments,_inet6_rthdr_segments)
56 1.8 itojun __weak_alias(inet6_rthdr_space,_inet6_rthdr_space)
57 1.8 itojun #endif
58 1.1 itojun
59 1.1 itojun size_t
60 1.1 itojun inet6_rthdr_space(type, seg)
61 1.13 itojun int type, seg;
62 1.1 itojun {
63 1.13 itojun switch (type) {
64 1.13 itojun case IPV6_RTHDR_TYPE_0:
65 1.13 itojun if (seg < 1 || seg > 23)
66 1.13 itojun return (0);
67 1.13 itojun return (CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) +
68 1.13 itojun sizeof(struct ip6_rthdr0)));
69 1.13 itojun default:
70 1.13 itojun return (0);
71 1.13 itojun }
72 1.1 itojun }
73 1.1 itojun
74 1.1 itojun struct cmsghdr *
75 1.1 itojun inet6_rthdr_init(bp, type)
76 1.13 itojun void *bp;
77 1.13 itojun int type;
78 1.1 itojun {
79 1.13 itojun struct cmsghdr *ch;
80 1.13 itojun struct ip6_rthdr *rthdr;
81 1.3 lukem
82 1.13 itojun _DIAGASSERT(bp != NULL);
83 1.3 lukem
84 1.13 itojun ch = (struct cmsghdr *)bp;
85 1.13 itojun rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(ch);
86 1.1 itojun
87 1.13 itojun ch->cmsg_level = IPPROTO_IPV6;
88 1.13 itojun ch->cmsg_type = IPV6_RTHDR;
89 1.13 itojun
90 1.13 itojun switch (type) {
91 1.13 itojun case IPV6_RTHDR_TYPE_0:
92 1.13 itojun ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) -
93 1.13 itojun sizeof(struct in6_addr));
94 1.13 itojun (void)memset(rthdr, 0, sizeof(struct ip6_rthdr0));
95 1.13 itojun rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
96 1.13 itojun return (ch);
97 1.13 itojun default:
98 1.13 itojun return (NULL);
99 1.13 itojun }
100 1.1 itojun }
101 1.1 itojun
102 1.1 itojun int
103 1.1 itojun inet6_rthdr_add(cmsg, addr, flags)
104 1.13 itojun struct cmsghdr *cmsg;
105 1.13 itojun const struct in6_addr *addr;
106 1.13 itojun u_int flags;
107 1.1 itojun {
108 1.13 itojun struct ip6_rthdr *rthdr;
109 1.3 lukem
110 1.13 itojun _DIAGASSERT(cmsg != NULL);
111 1.13 itojun _DIAGASSERT(addr != NULL);
112 1.3 lukem
113 1.13 itojun rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
114 1.1 itojun
115 1.13 itojun switch (rthdr->ip6r_type) {
116 1.13 itojun case IPV6_RTHDR_TYPE_0:
117 1.13 itojun {
118 1.13 itojun struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
119 1.13 itojun if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
120 1.13 itojun return (-1);
121 1.13 itojun if (rt0->ip6r0_segleft == 23)
122 1.13 itojun return (-1);
123 1.13 itojun if (flags == IPV6_RTHDR_STRICT) {
124 1.13 itojun int c, b;
125 1.13 itojun c = rt0->ip6r0_segleft / 8;
126 1.13 itojun b = rt0->ip6r0_segleft % 8;
127 1.13 itojun rt0->ip6r0_slmap[c] |= (1 << (7 - b));
128 1.13 itojun }
129 1.13 itojun rt0->ip6r0_segleft++;
130 1.13 itojun (void)memcpy(((caddr_t)(void *)rt0) +
131 1.13 itojun ((rt0->ip6r0_len + 1) << 3), addr, sizeof(struct in6_addr));
132 1.13 itojun rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
133 1.13 itojun cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
134 1.13 itojun break;
135 1.13 itojun }
136 1.13 itojun default:
137 1.13 itojun return (-1);
138 1.13 itojun }
139 1.1 itojun
140 1.13 itojun return (0);
141 1.1 itojun }
142 1.1 itojun
143 1.1 itojun int
144 1.1 itojun inet6_rthdr_lasthop(cmsg, flags)
145 1.13 itojun struct cmsghdr *cmsg;
146 1.13 itojun unsigned int flags;
147 1.1 itojun {
148 1.13 itojun struct ip6_rthdr *rthdr;
149 1.3 lukem
150 1.13 itojun _DIAGASSERT(cmsg != NULL);
151 1.3 lukem
152 1.13 itojun rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
153 1.1 itojun
154 1.13 itojun switch (rthdr->ip6r_type) {
155 1.13 itojun case IPV6_RTHDR_TYPE_0:
156 1.13 itojun {
157 1.13 itojun struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
158 1.13 itojun if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
159 1.13 itojun return (-1);
160 1.13 itojun if (rt0->ip6r0_segleft > 23)
161 1.13 itojun return (-1);
162 1.13 itojun if (flags == IPV6_RTHDR_STRICT) {
163 1.13 itojun int c, b;
164 1.13 itojun c = rt0->ip6r0_segleft / 8;
165 1.13 itojun b = rt0->ip6r0_segleft % 8;
166 1.13 itojun rt0->ip6r0_slmap[c] |= (1 << (7 - b));
167 1.13 itojun }
168 1.13 itojun break;
169 1.13 itojun }
170 1.13 itojun default:
171 1.13 itojun return (-1);
172 1.13 itojun }
173 1.1 itojun
174 1.13 itojun return (0);
175 1.1 itojun }
176 1.1 itojun
177 1.1 itojun #if 0
178 1.1 itojun int
179 1.1 itojun inet6_rthdr_reverse(in, out)
180 1.13 itojun const struct cmsghdr *in;
181 1.13 itojun struct cmsghdr *out;
182 1.1 itojun {
183 1.13 itojun
184 1.13 itojun return (-1);
185 1.1 itojun }
186 1.1 itojun #endif
187 1.1 itojun
188 1.1 itojun int
189 1.1 itojun inet6_rthdr_segments(cmsg)
190 1.13 itojun const struct cmsghdr *cmsg;
191 1.1 itojun {
192 1.13 itojun const struct ip6_rthdr *rthdr;
193 1.13 itojun
194 1.13 itojun _DIAGASSERT(cmsg != NULL);
195 1.13 itojun
196 1.13 itojun /*LINTED const castaway*/
197 1.13 itojun rthdr = (const struct ip6_rthdr *)(const void *)CMSG_DATA(cmsg);
198 1.3 lukem
199 1.13 itojun switch (rthdr->ip6r_type) {
200 1.13 itojun case IPV6_RTHDR_TYPE_0:
201 1.13 itojun {
202 1.13 itojun const struct ip6_rthdr0 *rt0 =
203 1.13 itojun (const struct ip6_rthdr0 *)(const void *)rthdr;
204 1.3 lukem
205 1.13 itojun if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
206 1.13 itojun return (-1);
207 1.1 itojun
208 1.13 itojun return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
209 1.13 itojun }
210 1.13 itojun
211 1.13 itojun default:
212 1.13 itojun return (-1);
213 1.13 itojun }
214 1.1 itojun }
215 1.1 itojun
216 1.1 itojun struct in6_addr *
217 1.11 lukem inet6_rthdr_getaddr(cmsg, idx)
218 1.13 itojun struct cmsghdr *cmsg;
219 1.13 itojun int idx;
220 1.1 itojun {
221 1.13 itojun struct ip6_rthdr *rthdr;
222 1.3 lukem
223 1.13 itojun _DIAGASSERT(cmsg != NULL);
224 1.3 lukem
225 1.13 itojun rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
226 1.13 itojun
227 1.13 itojun switch (rthdr->ip6r_type) {
228 1.13 itojun case IPV6_RTHDR_TYPE_0:
229 1.13 itojun {
230 1.13 itojun struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
231 1.13 itojun int naddr;
232 1.13 itojun
233 1.13 itojun if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
234 1.13 itojun return NULL;
235 1.13 itojun naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
236 1.13 itojun if (idx <= 0 || naddr < idx)
237 1.13 itojun return NULL;
238 1.13 itojun return &rt0->ip6r0_addr[idx - 1];
239 1.13 itojun }
240 1.1 itojun
241 1.13 itojun default:
242 1.13 itojun return NULL;
243 1.13 itojun }
244 1.1 itojun }
245 1.1 itojun
246 1.1 itojun int
247 1.11 lukem inet6_rthdr_getflags(cmsg, idx)
248 1.13 itojun const struct cmsghdr *cmsg;
249 1.13 itojun int idx;
250 1.1 itojun {
251 1.13 itojun const struct ip6_rthdr *rthdr;
252 1.13 itojun
253 1.13 itojun _DIAGASSERT(cmsg != NULL);
254 1.3 lukem
255 1.13 itojun /*LINTED const castaway*/
256 1.13 itojun rthdr = (const struct ip6_rthdr *)(const void *)CMSG_DATA(cmsg);
257 1.3 lukem
258 1.13 itojun switch (rthdr->ip6r_type) {
259 1.13 itojun case IPV6_RTHDR_TYPE_0:
260 1.13 itojun {
261 1.13 itojun const struct ip6_rthdr0 *rt0 = (const struct ip6_rthdr0 *)
262 1.13 itojun (const void *)rthdr;
263 1.13 itojun int naddr;
264 1.13 itojun
265 1.13 itojun if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
266 1.13 itojun return (-1);
267 1.13 itojun naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
268 1.13 itojun if (idx < 0 || naddr < idx)
269 1.13 itojun return (-1);
270 1.13 itojun if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8)))
271 1.13 itojun return IPV6_RTHDR_STRICT;
272 1.13 itojun else
273 1.13 itojun return IPV6_RTHDR_LOOSE;
274 1.13 itojun }
275 1.1 itojun
276 1.13 itojun default:
277 1.13 itojun return (-1);
278 1.13 itojun }
279 1.1 itojun }
280