summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/rthdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/net/rthdr.c')
-rw-r--r--src/lib/libc/net/rthdr.c165
1 files changed, 164 insertions, 1 deletions
diff --git a/src/lib/libc/net/rthdr.c b/src/lib/libc/net/rthdr.c
index 36ac5a3554..d10334e027 100644
--- a/src/lib/libc/net/rthdr.c
+++ b/src/lib/libc/net/rthdr.c
@@ -1,4 +1,5 @@
1/* $OpenBSD: rthdr.c,v 1.7 2005/03/25 13:24:12 otto Exp $ */ 1/* $OpenBSD: rthdr.c,v 1.8 2006/12/09 01:12:28 itojun Exp $ */
2/* $KAME: rthdr.c,v 1.22 2006/02/09 08:18:58 keiichi Exp $ */
2 3
3/* 4/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -39,6 +40,10 @@
39#include <string.h> 40#include <string.h>
40#include <stdio.h> 41#include <stdio.h>
41 42
43/*
44 * RFC2292 API
45 */
46
42size_t 47size_t
43inet6_rthdr_space(int type, int seg) 48inet6_rthdr_space(int type, int seg)
44{ 49{
@@ -213,3 +218,161 @@ inet6_rthdr_getflags(const struct cmsghdr *cmsg, int index)
213 return (-1); 218 return (-1);
214 } 219 }
215} 220}
221
222/*
223 * RFC3542 (2292bis) API
224 */
225
226socklen_t
227inet6_rth_space(int type, int segments)
228{
229 switch (type) {
230 case IPV6_RTHDR_TYPE_0:
231 return (((segments * 2) + 1) << 3);
232 default:
233 return (0); /* type not suppported */
234 }
235}
236
237void *
238inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
239{
240 struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
241 struct ip6_rthdr0 *rth0;
242
243 switch (type) {
244 case IPV6_RTHDR_TYPE_0:
245 /* length validation */
246 if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments))
247 return (NULL);
248
249 memset(bp, 0, bp_len);
250 rth0 = (struct ip6_rthdr0 *)rth;
251 rth0->ip6r0_len = segments * 2;
252 rth0->ip6r0_type = IPV6_RTHDR_TYPE_0;
253 rth0->ip6r0_segleft = 0;
254 rth0->ip6r0_reserved = 0;
255 break;
256 default:
257 return (NULL); /* type not supported */
258 }
259
260 return (bp);
261}
262
263int
264inet6_rth_add(void *bp, const struct in6_addr *addr)
265{
266 struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
267 struct ip6_rthdr0 *rth0;
268 struct in6_addr *nextaddr;
269
270 switch (rth->ip6r_type) {
271 case IPV6_RTHDR_TYPE_0:
272 rth0 = (struct ip6_rthdr0 *)rth;
273 nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft;
274 *nextaddr = *addr;
275 rth0->ip6r0_segleft++;
276 break;
277 default:
278 return (-1); /* type not supported */
279 }
280
281 return (0);
282}
283
284int
285inet6_rth_reverse(const void *in, void *out)
286{
287 struct ip6_rthdr *rth_in = (struct ip6_rthdr *)in;
288 struct ip6_rthdr0 *rth0_in, *rth0_out;
289 int i, segments;
290
291 switch (rth_in->ip6r_type) {
292 case IPV6_RTHDR_TYPE_0:
293 rth0_in = (struct ip6_rthdr0 *)in;
294 rth0_out = (struct ip6_rthdr0 *)out;
295
296 /* parameter validation XXX too paranoid? */
297 if (rth0_in->ip6r0_len % 2)
298 return (-1);
299 segments = rth0_in->ip6r0_len / 2;
300
301 /* we can't use memcpy here, since in and out may overlap */
302 memmove((void *)rth0_out, (void *)rth0_in,
303 ((rth0_in->ip6r0_len) + 1) << 3);
304 rth0_out->ip6r0_segleft = segments;
305
306 /* reverse the addresses */
307 for (i = 0; i < segments / 2; i++) {
308 struct in6_addr addr_tmp, *addr1, *addr2;
309
310 addr1 = (struct in6_addr *)(rth0_out + 1) + i;
311 addr2 = (struct in6_addr *)(rth0_out + 1) +
312 (segments - i - 1);
313 addr_tmp = *addr1;
314 *addr1 = *addr2;
315 *addr2 = addr_tmp;
316 }
317
318 break;
319 default:
320 return (-1); /* type not supported */
321 }
322
323 return (0);
324}
325
326int
327inet6_rth_segments(const void *bp)
328{
329 struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
330 struct ip6_rthdr0 *rh0;
331 int addrs;
332
333 switch (rh->ip6r_type) {
334 case IPV6_RTHDR_TYPE_0:
335 rh0 = (struct ip6_rthdr0 *)bp;
336
337 /*
338 * Validation for a type-0 routing header.
339 * Is this too strict?
340 */
341 if ((rh0->ip6r0_len % 2) != 0 ||
342 (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
343 return (-1);
344
345 return (addrs);
346 default:
347 return (-1); /* unknown type */
348 }
349}
350
351struct in6_addr *
352inet6_rth_getaddr(const void *bp, int idx)
353{
354 struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
355 struct ip6_rthdr0 *rh0;
356 int addrs;
357
358 switch (rh->ip6r_type) {
359 case IPV6_RTHDR_TYPE_0:
360 rh0 = (struct ip6_rthdr0 *)bp;
361
362 /*
363 * Validation for a type-0 routing header.
364 * Is this too strict?
365 */
366 if ((rh0->ip6r0_len % 2) != 0 ||
367 (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
368 return (NULL);
369
370 if (idx < 0 || addrs <= idx)
371 return (NULL);
372
373 return (((struct in6_addr *)(rh0 + 1)) + idx);
374 default:
375 return (NULL); /* unknown type */
376 break;
377 }
378}