rthdr.c revision 1.15 1 1.15 christos /* $NetBSD: rthdr.c,v 1.15 2005/11/29 03:12:00 christos 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.15 christos __RCSID("$NetBSD: rthdr.c,v 1.15 2005/11/29 03:12:00 christos 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.14 itojun return (CMSG_SPACE(sizeof(struct in6_addr) * seg +
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.14 itojun ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0));
93 1.13 itojun (void)memset(rthdr, 0, sizeof(struct ip6_rthdr0));
94 1.13 itojun rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
95 1.13 itojun return (ch);
96 1.13 itojun default:
97 1.13 itojun return (NULL);
98 1.13 itojun }
99 1.1 itojun }
100 1.1 itojun
101 1.1 itojun int
102 1.1 itojun inet6_rthdr_add(cmsg, addr, flags)
103 1.13 itojun struct cmsghdr *cmsg;
104 1.13 itojun const struct in6_addr *addr;
105 1.13 itojun u_int flags;
106 1.1 itojun {
107 1.13 itojun struct ip6_rthdr *rthdr;
108 1.3 lukem
109 1.13 itojun _DIAGASSERT(cmsg != NULL);
110 1.13 itojun _DIAGASSERT(addr != NULL);
111 1.3 lukem
112 1.13 itojun rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
113 1.1 itojun
114 1.13 itojun switch (rthdr->ip6r_type) {
115 1.13 itojun case IPV6_RTHDR_TYPE_0:
116 1.13 itojun {
117 1.13 itojun struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
118 1.14 itojun if (flags != IPV6_RTHDR_LOOSE)
119 1.13 itojun return (-1);
120 1.13 itojun if (rt0->ip6r0_segleft == 23)
121 1.13 itojun return (-1);
122 1.13 itojun rt0->ip6r0_segleft++;
123 1.13 itojun (void)memcpy(((caddr_t)(void *)rt0) +
124 1.13 itojun ((rt0->ip6r0_len + 1) << 3), addr, sizeof(struct in6_addr));
125 1.13 itojun rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
126 1.13 itojun cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
127 1.13 itojun break;
128 1.13 itojun }
129 1.13 itojun default:
130 1.13 itojun return (-1);
131 1.13 itojun }
132 1.1 itojun
133 1.13 itojun return (0);
134 1.1 itojun }
135 1.1 itojun
136 1.1 itojun int
137 1.1 itojun inet6_rthdr_lasthop(cmsg, flags)
138 1.13 itojun struct cmsghdr *cmsg;
139 1.13 itojun unsigned int flags;
140 1.1 itojun {
141 1.13 itojun struct ip6_rthdr *rthdr;
142 1.3 lukem
143 1.13 itojun _DIAGASSERT(cmsg != NULL);
144 1.3 lukem
145 1.13 itojun rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
146 1.1 itojun
147 1.13 itojun switch (rthdr->ip6r_type) {
148 1.13 itojun case IPV6_RTHDR_TYPE_0:
149 1.13 itojun {
150 1.13 itojun struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
151 1.14 itojun if (flags != IPV6_RTHDR_LOOSE)
152 1.13 itojun return (-1);
153 1.13 itojun if (rt0->ip6r0_segleft > 23)
154 1.13 itojun return (-1);
155 1.13 itojun break;
156 1.13 itojun }
157 1.13 itojun default:
158 1.13 itojun return (-1);
159 1.13 itojun }
160 1.1 itojun
161 1.13 itojun return (0);
162 1.1 itojun }
163 1.1 itojun
164 1.1 itojun #if 0
165 1.1 itojun int
166 1.1 itojun inet6_rthdr_reverse(in, out)
167 1.13 itojun const struct cmsghdr *in;
168 1.13 itojun struct cmsghdr *out;
169 1.1 itojun {
170 1.13 itojun
171 1.13 itojun return (-1);
172 1.1 itojun }
173 1.1 itojun #endif
174 1.1 itojun
175 1.1 itojun int
176 1.1 itojun inet6_rthdr_segments(cmsg)
177 1.13 itojun const struct cmsghdr *cmsg;
178 1.1 itojun {
179 1.13 itojun const struct ip6_rthdr *rthdr;
180 1.13 itojun
181 1.13 itojun _DIAGASSERT(cmsg != NULL);
182 1.13 itojun
183 1.15 christos rthdr = __UNCONST(CCMSG_DATA(cmsg));
184 1.3 lukem
185 1.13 itojun switch (rthdr->ip6r_type) {
186 1.13 itojun case IPV6_RTHDR_TYPE_0:
187 1.13 itojun {
188 1.13 itojun const struct ip6_rthdr0 *rt0 =
189 1.14 itojun (const struct ip6_rthdr0 *)(const void *)rthdr;
190 1.3 lukem
191 1.13 itojun if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
192 1.13 itojun return (-1);
193 1.1 itojun
194 1.13 itojun return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
195 1.13 itojun }
196 1.13 itojun
197 1.13 itojun default:
198 1.13 itojun return (-1);
199 1.13 itojun }
200 1.1 itojun }
201 1.1 itojun
202 1.1 itojun struct in6_addr *
203 1.11 lukem inet6_rthdr_getaddr(cmsg, idx)
204 1.13 itojun struct cmsghdr *cmsg;
205 1.13 itojun int idx;
206 1.1 itojun {
207 1.13 itojun struct ip6_rthdr *rthdr;
208 1.3 lukem
209 1.13 itojun _DIAGASSERT(cmsg != NULL);
210 1.3 lukem
211 1.13 itojun rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
212 1.13 itojun
213 1.13 itojun switch (rthdr->ip6r_type) {
214 1.13 itojun case IPV6_RTHDR_TYPE_0:
215 1.13 itojun {
216 1.13 itojun struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
217 1.13 itojun int naddr;
218 1.13 itojun
219 1.13 itojun if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
220 1.13 itojun return NULL;
221 1.13 itojun naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
222 1.13 itojun if (idx <= 0 || naddr < idx)
223 1.13 itojun return NULL;
224 1.14 itojun return ((struct in6_addr *)(void *)(rt0 + 1)) + idx;
225 1.13 itojun }
226 1.1 itojun
227 1.13 itojun default:
228 1.13 itojun return NULL;
229 1.13 itojun }
230 1.1 itojun }
231 1.1 itojun
232 1.1 itojun int
233 1.11 lukem inet6_rthdr_getflags(cmsg, idx)
234 1.13 itojun const struct cmsghdr *cmsg;
235 1.13 itojun int idx;
236 1.1 itojun {
237 1.13 itojun const struct ip6_rthdr *rthdr;
238 1.13 itojun
239 1.13 itojun _DIAGASSERT(cmsg != NULL);
240 1.3 lukem
241 1.15 christos rthdr = __UNCONST(CCMSG_DATA(cmsg));
242 1.3 lukem
243 1.13 itojun switch (rthdr->ip6r_type) {
244 1.13 itojun case IPV6_RTHDR_TYPE_0:
245 1.13 itojun {
246 1.13 itojun const struct ip6_rthdr0 *rt0 = (const struct ip6_rthdr0 *)
247 1.13 itojun (const void *)rthdr;
248 1.13 itojun int naddr;
249 1.13 itojun
250 1.13 itojun if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
251 1.13 itojun return (-1);
252 1.13 itojun naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
253 1.13 itojun if (idx < 0 || naddr < idx)
254 1.13 itojun return (-1);
255 1.14 itojun return IPV6_RTHDR_LOOSE;
256 1.13 itojun }
257 1.1 itojun
258 1.13 itojun default:
259 1.13 itojun return (-1);
260 1.13 itojun }
261 1.1 itojun }
262