1*f14fb602SLionel Sambuc /* $NetBSD: rthdr.c,v 1.18 2012/03/13 21:13:42 christos Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /*
42fe8fb19SBen Gras * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
52fe8fb19SBen Gras * All rights reserved.
62fe8fb19SBen Gras *
72fe8fb19SBen Gras * Redistribution and use in source and binary forms, with or without
82fe8fb19SBen Gras * modification, are permitted provided that the following conditions
92fe8fb19SBen Gras * are met:
102fe8fb19SBen Gras * 1. Redistributions of source code must retain the above copyright
112fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer.
122fe8fb19SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
132fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer in the
142fe8fb19SBen Gras * documentation and/or other materials provided with the distribution.
152fe8fb19SBen Gras * 3. Neither the name of the project nor the names of its contributors
162fe8fb19SBen Gras * may be used to endorse or promote products derived from this software
172fe8fb19SBen Gras * without specific prior written permission.
182fe8fb19SBen Gras *
192fe8fb19SBen Gras * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
202fe8fb19SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
212fe8fb19SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
222fe8fb19SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
232fe8fb19SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
242fe8fb19SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
252fe8fb19SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
262fe8fb19SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
272fe8fb19SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
282fe8fb19SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
292fe8fb19SBen Gras * SUCH DAMAGE.
302fe8fb19SBen Gras */
312fe8fb19SBen Gras
322fe8fb19SBen Gras #include <sys/cdefs.h>
332fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
34*f14fb602SLionel Sambuc __RCSID("$NetBSD: rthdr.c,v 1.18 2012/03/13 21:13:42 christos Exp $");
352fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
362fe8fb19SBen Gras
372fe8fb19SBen Gras #include "namespace.h"
382fe8fb19SBen Gras #include <sys/param.h>
392fe8fb19SBen Gras #include <sys/types.h>
402fe8fb19SBen Gras #include <sys/socket.h>
412fe8fb19SBen Gras
422fe8fb19SBen Gras #include <netinet/in.h>
432fe8fb19SBen Gras #include <netinet/ip6.h>
442fe8fb19SBen Gras
452fe8fb19SBen Gras #include <assert.h>
462fe8fb19SBen Gras #include <string.h>
472fe8fb19SBen Gras #include <stdio.h>
482fe8fb19SBen Gras
492fe8fb19SBen Gras #ifdef __weak_alias
__weak_alias(inet6_rthdr_add,_inet6_rthdr_add)502fe8fb19SBen Gras __weak_alias(inet6_rthdr_add,_inet6_rthdr_add)
512fe8fb19SBen Gras __weak_alias(inet6_rthdr_getaddr,_inet6_rthdr_getaddr)
522fe8fb19SBen Gras __weak_alias(inet6_rthdr_getflags,_inet6_rthdr_getflags)
532fe8fb19SBen Gras __weak_alias(inet6_rthdr_init,_inet6_rthdr_init)
542fe8fb19SBen Gras __weak_alias(inet6_rthdr_lasthop,_inet6_rthdr_lasthop)
552fe8fb19SBen Gras __weak_alias(inet6_rthdr_segments,_inet6_rthdr_segments)
562fe8fb19SBen Gras __weak_alias(inet6_rthdr_space,_inet6_rthdr_space)
572fe8fb19SBen Gras __weak_alias(inet6_rth_space, _inet6_rth_space)
582fe8fb19SBen Gras __weak_alias(inet6_rth_init, _inet6_rth_init)
592fe8fb19SBen Gras __weak_alias(inet6_rth_add, _inet6_rth_add)
602fe8fb19SBen Gras __weak_alias(inet6_rth_reverse, _inet6_rth_reverse)
612fe8fb19SBen Gras __weak_alias(inet6_rth_segments, _inet6_rth_segments)
622fe8fb19SBen Gras __weak_alias(inet6_rth_getaddr, _inet6_rth_getaddr)
632fe8fb19SBen Gras #endif
642fe8fb19SBen Gras
652fe8fb19SBen Gras /*
662fe8fb19SBen Gras * RFC2292 API
672fe8fb19SBen Gras */
682fe8fb19SBen Gras
692fe8fb19SBen Gras size_t
70*f14fb602SLionel Sambuc inet6_rthdr_space(int type, int seg)
712fe8fb19SBen Gras {
722fe8fb19SBen Gras switch (type) {
732fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
742fe8fb19SBen Gras if (seg < 1 || seg > 23)
752fe8fb19SBen Gras return (0);
762fe8fb19SBen Gras return (CMSG_SPACE(sizeof(struct in6_addr) * seg +
772fe8fb19SBen Gras sizeof(struct ip6_rthdr0)));
782fe8fb19SBen Gras default:
792fe8fb19SBen Gras return (0);
802fe8fb19SBen Gras }
812fe8fb19SBen Gras }
822fe8fb19SBen Gras
832fe8fb19SBen Gras struct cmsghdr *
inet6_rthdr_init(void * bp,int type)84*f14fb602SLionel Sambuc inet6_rthdr_init(void *bp, int type)
852fe8fb19SBen Gras {
862fe8fb19SBen Gras struct cmsghdr *ch;
872fe8fb19SBen Gras struct ip6_rthdr *rthdr;
882fe8fb19SBen Gras
892fe8fb19SBen Gras _DIAGASSERT(bp != NULL);
902fe8fb19SBen Gras
912fe8fb19SBen Gras ch = (struct cmsghdr *)bp;
922fe8fb19SBen Gras rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(ch);
932fe8fb19SBen Gras
942fe8fb19SBen Gras ch->cmsg_level = IPPROTO_IPV6;
952fe8fb19SBen Gras ch->cmsg_type = IPV6_RTHDR;
962fe8fb19SBen Gras
972fe8fb19SBen Gras switch (type) {
982fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
992fe8fb19SBen Gras #ifdef COMPAT_RFC2292
1002fe8fb19SBen Gras ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) -
1012fe8fb19SBen Gras sizeof(struct in6_addr));
1022fe8fb19SBen Gras #else
1032fe8fb19SBen Gras ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0));
1042fe8fb19SBen Gras #endif
1052fe8fb19SBen Gras (void)memset(rthdr, 0, sizeof(struct ip6_rthdr0));
1062fe8fb19SBen Gras rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
1072fe8fb19SBen Gras return (ch);
1082fe8fb19SBen Gras default:
1092fe8fb19SBen Gras return (NULL);
1102fe8fb19SBen Gras }
1112fe8fb19SBen Gras }
1122fe8fb19SBen Gras
1132fe8fb19SBen Gras int
inet6_rthdr_add(struct cmsghdr * cmsg,const struct in6_addr * addr,u_int flags)114*f14fb602SLionel Sambuc inet6_rthdr_add(struct cmsghdr *cmsg, const struct in6_addr *addr, u_int flags)
1152fe8fb19SBen Gras {
1162fe8fb19SBen Gras struct ip6_rthdr *rthdr;
1172fe8fb19SBen Gras
1182fe8fb19SBen Gras _DIAGASSERT(cmsg != NULL);
1192fe8fb19SBen Gras _DIAGASSERT(addr != NULL);
1202fe8fb19SBen Gras
1212fe8fb19SBen Gras rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
1222fe8fb19SBen Gras
1232fe8fb19SBen Gras switch (rthdr->ip6r_type) {
1242fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
1252fe8fb19SBen Gras {
126*f14fb602SLionel Sambuc size_t len;
1272fe8fb19SBen Gras struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
1282fe8fb19SBen Gras if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
1292fe8fb19SBen Gras return (-1);
1302fe8fb19SBen Gras if (rt0->ip6r0_segleft == 23)
1312fe8fb19SBen Gras return (-1);
1322fe8fb19SBen Gras if (flags != IPV6_RTHDR_LOOSE)
1332fe8fb19SBen Gras return (-1);
1342fe8fb19SBen Gras rt0->ip6r0_segleft++;
1352fe8fb19SBen Gras (void)memcpy(((caddr_t)(void *)rt0) +
1362fe8fb19SBen Gras ((rt0->ip6r0_len + 1) << 3), addr, sizeof(struct in6_addr));
1372fe8fb19SBen Gras rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
138*f14fb602SLionel Sambuc len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
139*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(socklen_t, len));
140*f14fb602SLionel Sambuc cmsg->cmsg_len = (socklen_t)len;
1412fe8fb19SBen Gras break;
1422fe8fb19SBen Gras }
1432fe8fb19SBen Gras default:
1442fe8fb19SBen Gras return (-1);
1452fe8fb19SBen Gras }
1462fe8fb19SBen Gras
1472fe8fb19SBen Gras return (0);
1482fe8fb19SBen Gras }
1492fe8fb19SBen Gras
1502fe8fb19SBen Gras int
inet6_rthdr_lasthop(struct cmsghdr * cmsg,unsigned int flags)151*f14fb602SLionel Sambuc inet6_rthdr_lasthop(struct cmsghdr *cmsg, unsigned int flags)
1522fe8fb19SBen Gras {
1532fe8fb19SBen Gras struct ip6_rthdr *rthdr;
1542fe8fb19SBen Gras
1552fe8fb19SBen Gras _DIAGASSERT(cmsg != NULL);
1562fe8fb19SBen Gras
1572fe8fb19SBen Gras rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
1582fe8fb19SBen Gras
1592fe8fb19SBen Gras switch (rthdr->ip6r_type) {
1602fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
1612fe8fb19SBen Gras {
1622fe8fb19SBen Gras struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
1632fe8fb19SBen Gras if (rt0->ip6r0_segleft > 23)
1642fe8fb19SBen Gras return (-1);
1652fe8fb19SBen Gras if (flags != IPV6_RTHDR_LOOSE)
1662fe8fb19SBen Gras return (-1);
1672fe8fb19SBen Gras break;
1682fe8fb19SBen Gras }
1692fe8fb19SBen Gras default:
1702fe8fb19SBen Gras return (-1);
1712fe8fb19SBen Gras }
1722fe8fb19SBen Gras
1732fe8fb19SBen Gras return (0);
1742fe8fb19SBen Gras }
1752fe8fb19SBen Gras
1762fe8fb19SBen Gras #if 0
1772fe8fb19SBen Gras int
178*f14fb602SLionel Sambuc inet6_rthdr_reverse(const struct cmsghdr *in, struct cmsghdr *out)
1792fe8fb19SBen Gras {
1802fe8fb19SBen Gras
1812fe8fb19SBen Gras return (-1);
1822fe8fb19SBen Gras }
1832fe8fb19SBen Gras #endif
1842fe8fb19SBen Gras
1852fe8fb19SBen Gras int
inet6_rthdr_segments(const struct cmsghdr * cmsg)186*f14fb602SLionel Sambuc inet6_rthdr_segments(const struct cmsghdr *cmsg)
1872fe8fb19SBen Gras {
1882fe8fb19SBen Gras const struct ip6_rthdr *rthdr;
1892fe8fb19SBen Gras
1902fe8fb19SBen Gras _DIAGASSERT(cmsg != NULL);
1912fe8fb19SBen Gras
1922fe8fb19SBen Gras rthdr = __UNCONST(CCMSG_DATA(cmsg));
1932fe8fb19SBen Gras
1942fe8fb19SBen Gras switch (rthdr->ip6r_type) {
1952fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
1962fe8fb19SBen Gras {
1972fe8fb19SBen Gras const struct ip6_rthdr0 *rt0 =
1982fe8fb19SBen Gras (const struct ip6_rthdr0 *)(const void *)rthdr;
199*f14fb602SLionel Sambuc size_t len;
2002fe8fb19SBen Gras
2012fe8fb19SBen Gras if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
2022fe8fb19SBen Gras return (-1);
2032fe8fb19SBen Gras
204*f14fb602SLionel Sambuc len = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
205*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, len));
206*f14fb602SLionel Sambuc return (int)len;
2072fe8fb19SBen Gras }
2082fe8fb19SBen Gras
2092fe8fb19SBen Gras default:
2102fe8fb19SBen Gras return (-1);
2112fe8fb19SBen Gras }
2122fe8fb19SBen Gras }
2132fe8fb19SBen Gras
2142fe8fb19SBen Gras struct in6_addr *
inet6_rthdr_getaddr(struct cmsghdr * cmsg,int idx)215*f14fb602SLionel Sambuc inet6_rthdr_getaddr(struct cmsghdr *cmsg, int idx)
2162fe8fb19SBen Gras {
2172fe8fb19SBen Gras struct ip6_rthdr *rthdr;
2182fe8fb19SBen Gras
2192fe8fb19SBen Gras _DIAGASSERT(cmsg != NULL);
2202fe8fb19SBen Gras
2212fe8fb19SBen Gras rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
2222fe8fb19SBen Gras
2232fe8fb19SBen Gras switch (rthdr->ip6r_type) {
2242fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
2252fe8fb19SBen Gras {
2262fe8fb19SBen Gras struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
2272fe8fb19SBen Gras int naddr;
228*f14fb602SLionel Sambuc size_t len;
2292fe8fb19SBen Gras
2302fe8fb19SBen Gras if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
2312fe8fb19SBen Gras return NULL;
232*f14fb602SLionel Sambuc len = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
233*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, len));
234*f14fb602SLionel Sambuc naddr = (int)len;
2352fe8fb19SBen Gras if (idx <= 0 || naddr < idx)
2362fe8fb19SBen Gras return NULL;
2372fe8fb19SBen Gras #ifdef COMPAT_RFC2292
2382fe8fb19SBen Gras return ((struct in6_addr *)(void *)(rt0 + 1)) + idx - 1;
2392fe8fb19SBen Gras #else
2402fe8fb19SBen Gras return ((struct in6_addr *)(void *)(rt0 + 1)) + idx;
2412fe8fb19SBen Gras #endif
2422fe8fb19SBen Gras }
2432fe8fb19SBen Gras
2442fe8fb19SBen Gras default:
2452fe8fb19SBen Gras return NULL;
2462fe8fb19SBen Gras }
2472fe8fb19SBen Gras }
2482fe8fb19SBen Gras
2492fe8fb19SBen Gras int
inet6_rthdr_getflags(const struct cmsghdr * cmsg,int idx)250*f14fb602SLionel Sambuc inet6_rthdr_getflags(const struct cmsghdr *cmsg, int idx)
2512fe8fb19SBen Gras {
2522fe8fb19SBen Gras const struct ip6_rthdr *rthdr;
2532fe8fb19SBen Gras
2542fe8fb19SBen Gras _DIAGASSERT(cmsg != NULL);
2552fe8fb19SBen Gras
2562fe8fb19SBen Gras rthdr = __UNCONST(CCMSG_DATA(cmsg));
2572fe8fb19SBen Gras
2582fe8fb19SBen Gras switch (rthdr->ip6r_type) {
2592fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
2602fe8fb19SBen Gras {
2612fe8fb19SBen Gras const struct ip6_rthdr0 *rt0 = (const struct ip6_rthdr0 *)
2622fe8fb19SBen Gras (const void *)rthdr;
2632fe8fb19SBen Gras int naddr;
264*f14fb602SLionel Sambuc size_t len;
2652fe8fb19SBen Gras
2662fe8fb19SBen Gras if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
2672fe8fb19SBen Gras return (-1);
268*f14fb602SLionel Sambuc len = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
269*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, len));
270*f14fb602SLionel Sambuc naddr = (int)len;
2712fe8fb19SBen Gras if (idx < 0 || naddr < idx)
2722fe8fb19SBen Gras return (-1);
2732fe8fb19SBen Gras return IPV6_RTHDR_LOOSE;
2742fe8fb19SBen Gras }
2752fe8fb19SBen Gras
2762fe8fb19SBen Gras default:
2772fe8fb19SBen Gras return (-1);
2782fe8fb19SBen Gras }
2792fe8fb19SBen Gras }
2802fe8fb19SBen Gras
2812fe8fb19SBen Gras /*
2822fe8fb19SBen Gras * RFC3542 (2292bis) API
2832fe8fb19SBen Gras */
2842fe8fb19SBen Gras
2852fe8fb19SBen Gras socklen_t
inet6_rth_space(int type,int segments)2862fe8fb19SBen Gras inet6_rth_space(int type, int segments)
2872fe8fb19SBen Gras {
2882fe8fb19SBen Gras switch (type) {
2892fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
2902fe8fb19SBen Gras return (((segments * 2) + 1) << 3);
2912fe8fb19SBen Gras default:
2922fe8fb19SBen Gras return (0); /* type not suppported */
2932fe8fb19SBen Gras }
2942fe8fb19SBen Gras }
2952fe8fb19SBen Gras
2962fe8fb19SBen Gras void *
inet6_rth_init(void * bp,socklen_t bp_len,int type,int segments)2972fe8fb19SBen Gras inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
2982fe8fb19SBen Gras {
2992fe8fb19SBen Gras struct ip6_rthdr *rth;
3002fe8fb19SBen Gras struct ip6_rthdr0 *rth0;
3012fe8fb19SBen Gras
3022fe8fb19SBen Gras _DIAGASSERT(bp != NULL);
3032fe8fb19SBen Gras
3042fe8fb19SBen Gras rth = (struct ip6_rthdr *)bp;
3052fe8fb19SBen Gras
3062fe8fb19SBen Gras switch (type) {
3072fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
3082fe8fb19SBen Gras /* length validation */
3092fe8fb19SBen Gras if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments))
3102fe8fb19SBen Gras return (NULL);
3112fe8fb19SBen Gras
3122fe8fb19SBen Gras memset(bp, 0, bp_len);
3132fe8fb19SBen Gras rth0 = (struct ip6_rthdr0 *)(void *)rth;
3142fe8fb19SBen Gras rth0->ip6r0_len = segments * 2;
3152fe8fb19SBen Gras rth0->ip6r0_type = IPV6_RTHDR_TYPE_0;
3162fe8fb19SBen Gras rth0->ip6r0_segleft = 0;
3172fe8fb19SBen Gras rth0->ip6r0_reserved = 0;
3182fe8fb19SBen Gras break;
3192fe8fb19SBen Gras default:
3202fe8fb19SBen Gras return (NULL); /* type not supported */
3212fe8fb19SBen Gras }
3222fe8fb19SBen Gras
3232fe8fb19SBen Gras return (bp);
3242fe8fb19SBen Gras }
3252fe8fb19SBen Gras
3262fe8fb19SBen Gras int
inet6_rth_add(void * bp,const struct in6_addr * addr)3272fe8fb19SBen Gras inet6_rth_add(void *bp, const struct in6_addr *addr)
3282fe8fb19SBen Gras {
3292fe8fb19SBen Gras struct ip6_rthdr *rth;
3302fe8fb19SBen Gras struct ip6_rthdr0 *rth0;
3312fe8fb19SBen Gras struct in6_addr *nextaddr;
3322fe8fb19SBen Gras
3332fe8fb19SBen Gras _DIAGASSERT(bp != NULL);
3342fe8fb19SBen Gras
3352fe8fb19SBen Gras rth = (struct ip6_rthdr *)bp;
3362fe8fb19SBen Gras
3372fe8fb19SBen Gras switch (rth->ip6r_type) {
3382fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
3392fe8fb19SBen Gras rth0 = (struct ip6_rthdr0 *)(void *)rth;
3402fe8fb19SBen Gras nextaddr = (struct in6_addr *)(void *)(rth0 + 1)
3412fe8fb19SBen Gras + rth0->ip6r0_segleft;
3422fe8fb19SBen Gras *nextaddr = *addr;
3432fe8fb19SBen Gras rth0->ip6r0_segleft++;
3442fe8fb19SBen Gras break;
3452fe8fb19SBen Gras default:
3462fe8fb19SBen Gras return (-1); /* type not supported */
3472fe8fb19SBen Gras }
3482fe8fb19SBen Gras
3492fe8fb19SBen Gras return (0);
3502fe8fb19SBen Gras }
3512fe8fb19SBen Gras
3522fe8fb19SBen Gras int
inet6_rth_reverse(const void * in,void * out)3532fe8fb19SBen Gras inet6_rth_reverse(const void *in, void *out)
3542fe8fb19SBen Gras {
3552fe8fb19SBen Gras const struct ip6_rthdr *rth_in;
3562fe8fb19SBen Gras const struct ip6_rthdr0 *rth0_in;
3572fe8fb19SBen Gras struct ip6_rthdr0 *rth0_out;
3582fe8fb19SBen Gras int i, segments;
3592fe8fb19SBen Gras
3602fe8fb19SBen Gras _DIAGASSERT(in != NULL);
3612fe8fb19SBen Gras _DIAGASSERT(out != NULL);
3622fe8fb19SBen Gras
3632fe8fb19SBen Gras rth_in = (const struct ip6_rthdr *)in;
3642fe8fb19SBen Gras
3652fe8fb19SBen Gras switch (rth_in->ip6r_type) {
3662fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
3672fe8fb19SBen Gras rth0_in = (const struct ip6_rthdr0 *)in;
3682fe8fb19SBen Gras rth0_out = (struct ip6_rthdr0 *)out;
3692fe8fb19SBen Gras
3702fe8fb19SBen Gras /* parameter validation XXX too paranoid? */
3712fe8fb19SBen Gras if (rth0_in->ip6r0_len % 2)
3722fe8fb19SBen Gras return (-1);
3732fe8fb19SBen Gras segments = rth0_in->ip6r0_len / 2;
3742fe8fb19SBen Gras
3752fe8fb19SBen Gras /* we can't use memcpy here, since in and out may overlap */
3762fe8fb19SBen Gras memmove((void *)rth0_out, (const void *)rth0_in,
3772fe8fb19SBen Gras (unsigned int)(((rth0_in->ip6r0_len) + 1) << 3));
3782fe8fb19SBen Gras rth0_out->ip6r0_segleft = segments;
3792fe8fb19SBen Gras
3802fe8fb19SBen Gras /* reverse the addresses */
3812fe8fb19SBen Gras for (i = 0; i < segments / 2; i++) {
3822fe8fb19SBen Gras struct in6_addr addr_tmp, *addr1, *addr2;
3832fe8fb19SBen Gras
3842fe8fb19SBen Gras addr1 = (struct in6_addr *)(void *)(rth0_out + 1) + i;
3852fe8fb19SBen Gras addr2 = (struct in6_addr *)(void *)(rth0_out + 1) +
3862fe8fb19SBen Gras (segments - i - 1);
3872fe8fb19SBen Gras addr_tmp = *addr1;
3882fe8fb19SBen Gras *addr1 = *addr2;
3892fe8fb19SBen Gras *addr2 = addr_tmp;
3902fe8fb19SBen Gras }
3912fe8fb19SBen Gras
3922fe8fb19SBen Gras break;
3932fe8fb19SBen Gras default:
3942fe8fb19SBen Gras return (-1); /* type not supported */
3952fe8fb19SBen Gras }
3962fe8fb19SBen Gras
3972fe8fb19SBen Gras return (0);
3982fe8fb19SBen Gras }
3992fe8fb19SBen Gras
4002fe8fb19SBen Gras int
inet6_rth_segments(const void * bp)4012fe8fb19SBen Gras inet6_rth_segments(const void *bp)
4022fe8fb19SBen Gras {
4032fe8fb19SBen Gras const struct ip6_rthdr *rh;
4042fe8fb19SBen Gras const struct ip6_rthdr0 *rh0;
4052fe8fb19SBen Gras unsigned int addrs;
4062fe8fb19SBen Gras
4072fe8fb19SBen Gras _DIAGASSERT(bp != NULL);
4082fe8fb19SBen Gras
4092fe8fb19SBen Gras rh = (const struct ip6_rthdr *)bp;
4102fe8fb19SBen Gras
4112fe8fb19SBen Gras switch (rh->ip6r_type) {
4122fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
4132fe8fb19SBen Gras rh0 = (const struct ip6_rthdr0 *)bp;
4142fe8fb19SBen Gras
4152fe8fb19SBen Gras /*
4162fe8fb19SBen Gras * Validation for a type-0 routing header.
4172fe8fb19SBen Gras * Is this too strict?
4182fe8fb19SBen Gras */
4192fe8fb19SBen Gras if ((rh0->ip6r0_len % 2) != 0 ||
4202fe8fb19SBen Gras (addrs = (rh0->ip6r0_len / 2)) < rh0->ip6r0_segleft)
4212fe8fb19SBen Gras return (-1);
4222fe8fb19SBen Gras
4232fe8fb19SBen Gras return (addrs);
4242fe8fb19SBen Gras default:
4252fe8fb19SBen Gras return (-1); /* unknown type */
4262fe8fb19SBen Gras }
4272fe8fb19SBen Gras }
4282fe8fb19SBen Gras
4292fe8fb19SBen Gras struct in6_addr *
inet6_rth_getaddr(const void * bp,int idx)4302fe8fb19SBen Gras inet6_rth_getaddr(const void *bp, int idx)
4312fe8fb19SBen Gras {
4322fe8fb19SBen Gras const struct ip6_rthdr *rh;
4332fe8fb19SBen Gras const struct ip6_rthdr0 *rh0;
4342fe8fb19SBen Gras unsigned int addrs;
4352fe8fb19SBen Gras
4362fe8fb19SBen Gras _DIAGASSERT(bp != NULL);
4372fe8fb19SBen Gras
4382fe8fb19SBen Gras rh = (const struct ip6_rthdr *)bp;
4392fe8fb19SBen Gras
4402fe8fb19SBen Gras switch (rh->ip6r_type) {
4412fe8fb19SBen Gras case IPV6_RTHDR_TYPE_0:
4422fe8fb19SBen Gras rh0 = (const struct ip6_rthdr0 *)bp;
4432fe8fb19SBen Gras
4442fe8fb19SBen Gras /*
4452fe8fb19SBen Gras * Validation for a type-0 routing header.
4462fe8fb19SBen Gras * Is this too strict?
4472fe8fb19SBen Gras */
4482fe8fb19SBen Gras if ((rh0->ip6r0_len % 2) != 0 ||
4492fe8fb19SBen Gras (addrs = (rh0->ip6r0_len / 2)) < rh0->ip6r0_segleft)
4502fe8fb19SBen Gras return (NULL);
4512fe8fb19SBen Gras
4522fe8fb19SBen Gras if (idx < 0 || addrs <= (unsigned int)idx)
4532fe8fb19SBen Gras return (NULL);
4542fe8fb19SBen Gras
4552fe8fb19SBen Gras return (((struct in6_addr *)(void *)__UNCONST(rh0 + 1)) + idx);
4562fe8fb19SBen Gras default:
4572fe8fb19SBen Gras return (NULL); /* unknown type */
4582fe8fb19SBen Gras }
4592fe8fb19SBen Gras }
460