rthdr.c revision 1.14 1 /* $NetBSD: rthdr.c,v 1.14 2003/06/06 08:13:45 itojun Exp $ */
2
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.
30 */
31
32 #include <sys/cdefs.h>
33 #if defined(LIBC_SCCS) && !defined(lint)
34 __RCSID("$NetBSD: rthdr.c,v 1.14 2003/06/06 08:13:45 itojun Exp $");
35 #endif /* LIBC_SCCS and not lint */
36
37 #include "namespace.h"
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41
42 #include <netinet/in.h>
43 #include <netinet/ip6.h>
44
45 #include <assert.h>
46 #include <string.h>
47 #include <stdio.h>
48
49 #ifdef __weak_alias
50 __weak_alias(inet6_rthdr_add,_inet6_rthdr_add)
51 __weak_alias(inet6_rthdr_getaddr,_inet6_rthdr_getaddr)
52 __weak_alias(inet6_rthdr_getflags,_inet6_rthdr_getflags)
53 __weak_alias(inet6_rthdr_init,_inet6_rthdr_init)
54 __weak_alias(inet6_rthdr_lasthop,_inet6_rthdr_lasthop)
55 __weak_alias(inet6_rthdr_segments,_inet6_rthdr_segments)
56 __weak_alias(inet6_rthdr_space,_inet6_rthdr_space)
57 #endif
58
59 size_t
60 inet6_rthdr_space(type, seg)
61 int type, seg;
62 {
63 switch (type) {
64 case IPV6_RTHDR_TYPE_0:
65 if (seg < 1 || seg > 23)
66 return (0);
67 return (CMSG_SPACE(sizeof(struct in6_addr) * seg +
68 sizeof(struct ip6_rthdr0)));
69 default:
70 return (0);
71 }
72 }
73
74 struct cmsghdr *
75 inet6_rthdr_init(bp, type)
76 void *bp;
77 int type;
78 {
79 struct cmsghdr *ch;
80 struct ip6_rthdr *rthdr;
81
82 _DIAGASSERT(bp != NULL);
83
84 ch = (struct cmsghdr *)bp;
85 rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(ch);
86
87 ch->cmsg_level = IPPROTO_IPV6;
88 ch->cmsg_type = IPV6_RTHDR;
89
90 switch (type) {
91 case IPV6_RTHDR_TYPE_0:
92 ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0));
93 (void)memset(rthdr, 0, sizeof(struct ip6_rthdr0));
94 rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
95 return (ch);
96 default:
97 return (NULL);
98 }
99 }
100
101 int
102 inet6_rthdr_add(cmsg, addr, flags)
103 struct cmsghdr *cmsg;
104 const struct in6_addr *addr;
105 u_int flags;
106 {
107 struct ip6_rthdr *rthdr;
108
109 _DIAGASSERT(cmsg != NULL);
110 _DIAGASSERT(addr != NULL);
111
112 rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
113
114 switch (rthdr->ip6r_type) {
115 case IPV6_RTHDR_TYPE_0:
116 {
117 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
118 if (flags != IPV6_RTHDR_LOOSE)
119 return (-1);
120 if (rt0->ip6r0_segleft == 23)
121 return (-1);
122 rt0->ip6r0_segleft++;
123 (void)memcpy(((caddr_t)(void *)rt0) +
124 ((rt0->ip6r0_len + 1) << 3), addr, sizeof(struct in6_addr));
125 rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
126 cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
127 break;
128 }
129 default:
130 return (-1);
131 }
132
133 return (0);
134 }
135
136 int
137 inet6_rthdr_lasthop(cmsg, flags)
138 struct cmsghdr *cmsg;
139 unsigned int flags;
140 {
141 struct ip6_rthdr *rthdr;
142
143 _DIAGASSERT(cmsg != NULL);
144
145 rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
146
147 switch (rthdr->ip6r_type) {
148 case IPV6_RTHDR_TYPE_0:
149 {
150 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
151 if (flags != IPV6_RTHDR_LOOSE)
152 return (-1);
153 if (rt0->ip6r0_segleft > 23)
154 return (-1);
155 break;
156 }
157 default:
158 return (-1);
159 }
160
161 return (0);
162 }
163
164 #if 0
165 int
166 inet6_rthdr_reverse(in, out)
167 const struct cmsghdr *in;
168 struct cmsghdr *out;
169 {
170
171 return (-1);
172 }
173 #endif
174
175 int
176 inet6_rthdr_segments(cmsg)
177 const struct cmsghdr *cmsg;
178 {
179 const struct ip6_rthdr *rthdr;
180
181 _DIAGASSERT(cmsg != NULL);
182
183 /*LINTED const castaway*/
184 rthdr = (const struct ip6_rthdr *)(const void *)CMSG_DATA(cmsg);
185
186 switch (rthdr->ip6r_type) {
187 case IPV6_RTHDR_TYPE_0:
188 {
189 const struct ip6_rthdr0 *rt0 =
190 (const struct ip6_rthdr0 *)(const void *)rthdr;
191
192 if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
193 return (-1);
194
195 return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
196 }
197
198 default:
199 return (-1);
200 }
201 }
202
203 struct in6_addr *
204 inet6_rthdr_getaddr(cmsg, idx)
205 struct cmsghdr *cmsg;
206 int idx;
207 {
208 struct ip6_rthdr *rthdr;
209
210 _DIAGASSERT(cmsg != NULL);
211
212 rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
213
214 switch (rthdr->ip6r_type) {
215 case IPV6_RTHDR_TYPE_0:
216 {
217 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
218 int naddr;
219
220 if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
221 return NULL;
222 naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
223 if (idx <= 0 || naddr < idx)
224 return NULL;
225 return ((struct in6_addr *)(void *)(rt0 + 1)) + idx;
226 }
227
228 default:
229 return NULL;
230 }
231 }
232
233 int
234 inet6_rthdr_getflags(cmsg, idx)
235 const struct cmsghdr *cmsg;
236 int idx;
237 {
238 const struct ip6_rthdr *rthdr;
239
240 _DIAGASSERT(cmsg != NULL);
241
242 /*LINTED const castaway*/
243 rthdr = (const struct ip6_rthdr *)(const void *)CMSG_DATA(cmsg);
244
245 switch (rthdr->ip6r_type) {
246 case IPV6_RTHDR_TYPE_0:
247 {
248 const struct ip6_rthdr0 *rt0 = (const struct ip6_rthdr0 *)
249 (const void *)rthdr;
250 int naddr;
251
252 if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
253 return (-1);
254 naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
255 if (idx < 0 || naddr < idx)
256 return (-1);
257 return IPV6_RTHDR_LOOSE;
258 }
259
260 default:
261 return (-1);
262 }
263 }
264