1f95d4633SHajimu UMEMOTO /* $KAME: rthdr.c,v 1.19 2003/06/06 10:48:51 itojun Exp $ */ 288ff5695SSUZUKI Shinsuke 305a244b4SYoshinobu Inoue /* 405a244b4SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 505a244b4SYoshinobu Inoue * All rights reserved. 605a244b4SYoshinobu Inoue * 705a244b4SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 805a244b4SYoshinobu Inoue * modification, are permitted provided that the following conditions 905a244b4SYoshinobu Inoue * are met: 1005a244b4SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 1105a244b4SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1205a244b4SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1305a244b4SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1405a244b4SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1505a244b4SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1605a244b4SYoshinobu Inoue * may be used to endorse or promote products derived from this software 1705a244b4SYoshinobu Inoue * without specific prior written permission. 1805a244b4SYoshinobu Inoue * 1905a244b4SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2005a244b4SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2105a244b4SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2205a244b4SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2305a244b4SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2405a244b4SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2505a244b4SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2605a244b4SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2705a244b4SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2805a244b4SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2905a244b4SYoshinobu Inoue * SUCH DAMAGE. 3005a244b4SYoshinobu Inoue */ 3105a244b4SYoshinobu Inoue 32333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 33333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 34333fc21eSDavid E. O'Brien 3505a244b4SYoshinobu Inoue #include <sys/param.h> 3605a244b4SYoshinobu Inoue #include <sys/types.h> 3705a244b4SYoshinobu Inoue #include <sys/socket.h> 3805a244b4SYoshinobu Inoue 3905a244b4SYoshinobu Inoue #include <netinet/in.h> 4005a244b4SYoshinobu Inoue #include <netinet/ip6.h> 4105a244b4SYoshinobu Inoue 4205a244b4SYoshinobu Inoue #include <string.h> 4305a244b4SYoshinobu Inoue #include <stdio.h> 4405a244b4SYoshinobu Inoue 45f95d4633SHajimu UMEMOTO /* 46f95d4633SHajimu UMEMOTO * RFC2292 API 47f95d4633SHajimu UMEMOTO */ 48f95d4633SHajimu UMEMOTO 4905a244b4SYoshinobu Inoue size_t 5005a244b4SYoshinobu Inoue inet6_rthdr_space(type, seg) 5105a244b4SYoshinobu Inoue int type, seg; 5205a244b4SYoshinobu Inoue { 5305a244b4SYoshinobu Inoue switch (type) { 5405a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 5505a244b4SYoshinobu Inoue if (seg < 1 || seg > 23) 5605a244b4SYoshinobu Inoue return (0); 57f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC2292 58f95d4633SHajimu UMEMOTO return (CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) + 59f95d4633SHajimu UMEMOTO sizeof(struct ip6_rthdr0))); 60f95d4633SHajimu UMEMOTO #else 61f95d4633SHajimu UMEMOTO return (CMSG_SPACE(sizeof(struct in6_addr) * seg + 62f95d4633SHajimu UMEMOTO sizeof(struct ip6_rthdr0))); 6305a244b4SYoshinobu Inoue #endif 64f95d4633SHajimu UMEMOTO default: 6505a244b4SYoshinobu Inoue return (0); 6605a244b4SYoshinobu Inoue } 6705a244b4SYoshinobu Inoue } 6805a244b4SYoshinobu Inoue 6905a244b4SYoshinobu Inoue struct cmsghdr * 7005a244b4SYoshinobu Inoue inet6_rthdr_init(bp, type) 7105a244b4SYoshinobu Inoue void *bp; 7205a244b4SYoshinobu Inoue int type; 7305a244b4SYoshinobu Inoue { 748fb3f3f6SDavid E. O'Brien struct cmsghdr *ch = (struct cmsghdr *)bp; 758fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 767d0d8dc3SYoshinobu Inoue 777d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(ch); 7805a244b4SYoshinobu Inoue 7905a244b4SYoshinobu Inoue ch->cmsg_level = IPPROTO_IPV6; 8005a244b4SYoshinobu Inoue ch->cmsg_type = IPV6_RTHDR; 8105a244b4SYoshinobu Inoue 8205a244b4SYoshinobu Inoue switch (type) { 8305a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 84f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC2292 85f95d4633SHajimu UMEMOTO ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) - 86f95d4633SHajimu UMEMOTO sizeof(struct in6_addr)); 87f95d4633SHajimu UMEMOTO #else 88f95d4633SHajimu UMEMOTO ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0)); 89f95d4633SHajimu UMEMOTO #endif 90f95d4633SHajimu UMEMOTO 9105a244b4SYoshinobu Inoue bzero(rthdr, sizeof(struct ip6_rthdr0)); 9205a244b4SYoshinobu Inoue rthdr->ip6r_type = IPV6_RTHDR_TYPE_0; 9305a244b4SYoshinobu Inoue return (ch); 9405a244b4SYoshinobu Inoue default: 9505a244b4SYoshinobu Inoue return (NULL); 9605a244b4SYoshinobu Inoue } 9705a244b4SYoshinobu Inoue } 9805a244b4SYoshinobu Inoue 99f95d4633SHajimu UMEMOTO /* ARGSUSED */ 10005a244b4SYoshinobu Inoue int 10105a244b4SYoshinobu Inoue inet6_rthdr_add(cmsg, addr, flags) 10205a244b4SYoshinobu Inoue struct cmsghdr *cmsg; 10305a244b4SYoshinobu Inoue const struct in6_addr *addr; 10405a244b4SYoshinobu Inoue u_int flags; 10505a244b4SYoshinobu Inoue { 1068fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 1077d0d8dc3SYoshinobu Inoue 1087d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 10905a244b4SYoshinobu Inoue 11005a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 11105a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 11205a244b4SYoshinobu Inoue { 11305a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 114f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) 11505a244b4SYoshinobu Inoue return (-1); 116f95d4633SHajimu UMEMOTO if (rt0->ip6r0_segleft == 23) 11705a244b4SYoshinobu Inoue return (-1); 118f95d4633SHajimu UMEMOTO 119f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 12005a244b4SYoshinobu Inoue if (flags == IPV6_RTHDR_STRICT) { 12105a244b4SYoshinobu Inoue int c, b; 12205a244b4SYoshinobu Inoue c = rt0->ip6r0_segleft / 8; 12305a244b4SYoshinobu Inoue b = rt0->ip6r0_segleft % 8; 12405a244b4SYoshinobu Inoue rt0->ip6r0_slmap[c] |= (1 << (7 - b)); 12505a244b4SYoshinobu Inoue } 126f95d4633SHajimu UMEMOTO #else 127f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE) 128f95d4633SHajimu UMEMOTO return (-1); 129f95d4633SHajimu UMEMOTO #endif 13005a244b4SYoshinobu Inoue rt0->ip6r0_segleft++; 13105a244b4SYoshinobu Inoue bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3), 13205a244b4SYoshinobu Inoue sizeof(struct in6_addr)); 13305a244b4SYoshinobu Inoue rt0->ip6r0_len += sizeof(struct in6_addr) >> 3; 13405a244b4SYoshinobu Inoue cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3); 13505a244b4SYoshinobu Inoue break; 13605a244b4SYoshinobu Inoue } 13705a244b4SYoshinobu Inoue default: 13805a244b4SYoshinobu Inoue return (-1); 13905a244b4SYoshinobu Inoue } 14005a244b4SYoshinobu Inoue 14105a244b4SYoshinobu Inoue return (0); 14205a244b4SYoshinobu Inoue } 14305a244b4SYoshinobu Inoue 144f95d4633SHajimu UMEMOTO /* ARGSUSED */ 14505a244b4SYoshinobu Inoue int 14605a244b4SYoshinobu Inoue inet6_rthdr_lasthop(cmsg, flags) 14705a244b4SYoshinobu Inoue struct cmsghdr *cmsg; 14805a244b4SYoshinobu Inoue unsigned int flags; 14905a244b4SYoshinobu Inoue { 1508fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 1517d0d8dc3SYoshinobu Inoue 1527d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 15305a244b4SYoshinobu Inoue 15405a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 15505a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 15605a244b4SYoshinobu Inoue { 15705a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 158f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 159f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) 16005a244b4SYoshinobu Inoue return (-1); 161f95d4633SHajimu UMEMOTO #endif /* COMPAT_RFC1883 */ 162f95d4633SHajimu UMEMOTO if (rt0->ip6r0_segleft > 23) 16305a244b4SYoshinobu Inoue return (-1); 164f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 16505a244b4SYoshinobu Inoue if (flags == IPV6_RTHDR_STRICT) { 16605a244b4SYoshinobu Inoue int c, b; 16705a244b4SYoshinobu Inoue c = rt0->ip6r0_segleft / 8; 16805a244b4SYoshinobu Inoue b = rt0->ip6r0_segleft % 8; 16905a244b4SYoshinobu Inoue rt0->ip6r0_slmap[c] |= (1 << (7 - b)); 17005a244b4SYoshinobu Inoue } 171f95d4633SHajimu UMEMOTO #else 172f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE) 173f95d4633SHajimu UMEMOTO return (-1); 174f95d4633SHajimu UMEMOTO #endif /* COMPAT_RFC1883 */ 17505a244b4SYoshinobu Inoue break; 17605a244b4SYoshinobu Inoue } 17705a244b4SYoshinobu Inoue default: 17805a244b4SYoshinobu Inoue return (-1); 17905a244b4SYoshinobu Inoue } 18005a244b4SYoshinobu Inoue 18105a244b4SYoshinobu Inoue return (0); 18205a244b4SYoshinobu Inoue } 18305a244b4SYoshinobu Inoue 18405a244b4SYoshinobu Inoue #if 0 18505a244b4SYoshinobu Inoue int 18605a244b4SYoshinobu Inoue inet6_rthdr_reverse(in, out) 18705a244b4SYoshinobu Inoue const struct cmsghdr *in; 18805a244b4SYoshinobu Inoue struct cmsghdr *out; 18905a244b4SYoshinobu Inoue { 190f95d4633SHajimu UMEMOTO 191f95d4633SHajimu UMEMOTO return (-1); 19205a244b4SYoshinobu Inoue } 19305a244b4SYoshinobu Inoue #endif 19405a244b4SYoshinobu Inoue 19505a244b4SYoshinobu Inoue int 19605a244b4SYoshinobu Inoue inet6_rthdr_segments(cmsg) 19705a244b4SYoshinobu Inoue const struct cmsghdr *cmsg; 19805a244b4SYoshinobu Inoue { 1998fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 2007d0d8dc3SYoshinobu Inoue 2017d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 20205a244b4SYoshinobu Inoue 20305a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 20405a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 20505a244b4SYoshinobu Inoue { 20605a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 20705a244b4SYoshinobu Inoue 208f95d4633SHajimu UMEMOTO if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) 209f95d4633SHajimu UMEMOTO return (-1); 21005a244b4SYoshinobu Inoue 21105a244b4SYoshinobu Inoue return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 21205a244b4SYoshinobu Inoue } 21305a244b4SYoshinobu Inoue 21405a244b4SYoshinobu Inoue default: 215f95d4633SHajimu UMEMOTO return (-1); 21605a244b4SYoshinobu Inoue } 21705a244b4SYoshinobu Inoue } 21805a244b4SYoshinobu Inoue 21905a244b4SYoshinobu Inoue struct in6_addr * 22088ff5695SSUZUKI Shinsuke inet6_rthdr_getaddr(cmsg, idx) 22105a244b4SYoshinobu Inoue struct cmsghdr *cmsg; 22288ff5695SSUZUKI Shinsuke int idx; 22305a244b4SYoshinobu Inoue { 2248fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 2257d0d8dc3SYoshinobu Inoue 2267d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 22705a244b4SYoshinobu Inoue 22805a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 22905a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 23005a244b4SYoshinobu Inoue { 23105a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 23205a244b4SYoshinobu Inoue int naddr; 23305a244b4SYoshinobu Inoue 234f95d4633SHajimu UMEMOTO if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) 23505a244b4SYoshinobu Inoue return NULL; 23605a244b4SYoshinobu Inoue naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 237f95d4633SHajimu UMEMOTO if (idx <= 0 || naddr < idx) 23805a244b4SYoshinobu Inoue return NULL; 239f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC2292 240f95d4633SHajimu UMEMOTO return (((struct in6_addr *)(rt0 + 1)) + idx - 1); 241f95d4633SHajimu UMEMOTO #else 242f95d4633SHajimu UMEMOTO return (((struct in6_addr *)(rt0 + 1)) + idx); 243f95d4633SHajimu UMEMOTO #endif 24405a244b4SYoshinobu Inoue } 24505a244b4SYoshinobu Inoue 24605a244b4SYoshinobu Inoue default: 24705a244b4SYoshinobu Inoue return NULL; 24805a244b4SYoshinobu Inoue } 24905a244b4SYoshinobu Inoue } 25005a244b4SYoshinobu Inoue 25105a244b4SYoshinobu Inoue int 25288ff5695SSUZUKI Shinsuke inet6_rthdr_getflags(cmsg, idx) 25305a244b4SYoshinobu Inoue const struct cmsghdr *cmsg; 25488ff5695SSUZUKI Shinsuke int idx; 25505a244b4SYoshinobu Inoue { 2568fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 2577d0d8dc3SYoshinobu Inoue 2587d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 25905a244b4SYoshinobu Inoue 26005a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 26105a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 26205a244b4SYoshinobu Inoue { 26305a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 26405a244b4SYoshinobu Inoue int naddr; 26505a244b4SYoshinobu Inoue 266f95d4633SHajimu UMEMOTO if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) 267f95d4633SHajimu UMEMOTO return (-1); 26805a244b4SYoshinobu Inoue naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 269f95d4633SHajimu UMEMOTO if (idx < 0 || naddr < idx) 270f95d4633SHajimu UMEMOTO return (-1); 271f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 27288ff5695SSUZUKI Shinsuke if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8))) 27305a244b4SYoshinobu Inoue return IPV6_RTHDR_STRICT; 27405a244b4SYoshinobu Inoue else 27505a244b4SYoshinobu Inoue return IPV6_RTHDR_LOOSE; 276f95d4633SHajimu UMEMOTO #else 277f95d4633SHajimu UMEMOTO return IPV6_RTHDR_LOOSE; 278f95d4633SHajimu UMEMOTO #endif /* COMPAT_RFC1883 */ 27905a244b4SYoshinobu Inoue } 28005a244b4SYoshinobu Inoue 28105a244b4SYoshinobu Inoue default: 282f95d4633SHajimu UMEMOTO return (-1); 283f95d4633SHajimu UMEMOTO } 284f95d4633SHajimu UMEMOTO } 285f95d4633SHajimu UMEMOTO 286f95d4633SHajimu UMEMOTO /* 287f95d4633SHajimu UMEMOTO * RFC3542 (2292bis) API 288f95d4633SHajimu UMEMOTO */ 289f95d4633SHajimu UMEMOTO 290f95d4633SHajimu UMEMOTO socklen_t 291f95d4633SHajimu UMEMOTO inet6_rth_space(int type, int segments) 292f95d4633SHajimu UMEMOTO { 293f95d4633SHajimu UMEMOTO switch (type) { 294f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 295f95d4633SHajimu UMEMOTO return (((segments * 2) + 1) << 3); 296f95d4633SHajimu UMEMOTO default: 297f95d4633SHajimu UMEMOTO return (0); /* type not suppported */ 298f95d4633SHajimu UMEMOTO } 299f95d4633SHajimu UMEMOTO } 300f95d4633SHajimu UMEMOTO 301f95d4633SHajimu UMEMOTO void * 302f95d4633SHajimu UMEMOTO inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments) 303f95d4633SHajimu UMEMOTO { 304f95d4633SHajimu UMEMOTO struct ip6_rthdr *rth = (struct ip6_rthdr *)bp; 305f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rth0; 306f95d4633SHajimu UMEMOTO 307f95d4633SHajimu UMEMOTO switch (type) { 308f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 309f95d4633SHajimu UMEMOTO /* length validation */ 310f95d4633SHajimu UMEMOTO if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments)) 311f95d4633SHajimu UMEMOTO return (NULL); 312f95d4633SHajimu UMEMOTO 313f95d4633SHajimu UMEMOTO memset(bp, 0, bp_len); 314f95d4633SHajimu UMEMOTO rth0 = (struct ip6_rthdr0 *)rth; 315f95d4633SHajimu UMEMOTO rth0->ip6r0_len = segments * 2; 316f95d4633SHajimu UMEMOTO rth0->ip6r0_type = IPV6_RTHDR_TYPE_0; 317f95d4633SHajimu UMEMOTO rth0->ip6r0_segleft = 0; 318f95d4633SHajimu UMEMOTO rth0->ip6r0_reserved = 0; 319f95d4633SHajimu UMEMOTO break; 320f95d4633SHajimu UMEMOTO default: 321f95d4633SHajimu UMEMOTO return (NULL); /* type not supported */ 322f95d4633SHajimu UMEMOTO } 323f95d4633SHajimu UMEMOTO 324f95d4633SHajimu UMEMOTO return (bp); 325f95d4633SHajimu UMEMOTO } 326f95d4633SHajimu UMEMOTO 327f95d4633SHajimu UMEMOTO int 328f95d4633SHajimu UMEMOTO inet6_rth_add(void *bp, const struct in6_addr *addr) 329f95d4633SHajimu UMEMOTO { 330f95d4633SHajimu UMEMOTO struct ip6_rthdr *rth = (struct ip6_rthdr *)bp; 331f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rth0; 332f95d4633SHajimu UMEMOTO struct in6_addr *nextaddr; 333f95d4633SHajimu UMEMOTO 334f95d4633SHajimu UMEMOTO switch (rth->ip6r_type) { 335f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 336f95d4633SHajimu UMEMOTO rth0 = (struct ip6_rthdr0 *)rth; 337f95d4633SHajimu UMEMOTO nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft; 338f95d4633SHajimu UMEMOTO *nextaddr = *addr; 339f95d4633SHajimu UMEMOTO rth0->ip6r0_segleft++; 340f95d4633SHajimu UMEMOTO break; 341f95d4633SHajimu UMEMOTO default: 342f95d4633SHajimu UMEMOTO return (-1); /* type not supported */ 343f95d4633SHajimu UMEMOTO } 344f95d4633SHajimu UMEMOTO 345f95d4633SHajimu UMEMOTO return (0); 346f95d4633SHajimu UMEMOTO } 347f95d4633SHajimu UMEMOTO 348f95d4633SHajimu UMEMOTO int 349f95d4633SHajimu UMEMOTO inet6_rth_reverse(const void *in, void *out) 350f95d4633SHajimu UMEMOTO { 351f95d4633SHajimu UMEMOTO struct ip6_rthdr *rth_in = (struct ip6_rthdr *)in; 352f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rth0_in, *rth0_out; 353f95d4633SHajimu UMEMOTO int i, segments; 354f95d4633SHajimu UMEMOTO 355f95d4633SHajimu UMEMOTO switch (rth_in->ip6r_type) { 356f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 357f95d4633SHajimu UMEMOTO rth0_in = (struct ip6_rthdr0 *)in; 358f95d4633SHajimu UMEMOTO rth0_out = (struct ip6_rthdr0 *)out; 359f95d4633SHajimu UMEMOTO 360f95d4633SHajimu UMEMOTO /* parameter validation XXX too paranoid? */ 361f95d4633SHajimu UMEMOTO if (rth0_in->ip6r0_len % 2) 362f95d4633SHajimu UMEMOTO return (-1); 363f95d4633SHajimu UMEMOTO segments = rth0_in->ip6r0_len / 2; 364f95d4633SHajimu UMEMOTO 365f95d4633SHajimu UMEMOTO /* we can't use memcpy here, since in and out may overlap */ 366f95d4633SHajimu UMEMOTO memmove((void *)rth0_out, (void *)rth0_in, 367f95d4633SHajimu UMEMOTO ((rth0_in->ip6r0_len) + 1) << 3); 368f95d4633SHajimu UMEMOTO rth0_out->ip6r0_segleft = segments; 369f95d4633SHajimu UMEMOTO 370f95d4633SHajimu UMEMOTO /* reverse the addresses */ 371f95d4633SHajimu UMEMOTO for (i = 0; i < segments / 2; i++) { 372f95d4633SHajimu UMEMOTO struct in6_addr addr_tmp, *addr1, *addr2; 373f95d4633SHajimu UMEMOTO 374f95d4633SHajimu UMEMOTO addr1 = (struct in6_addr *)(rth0_out + 1) + i; 375f95d4633SHajimu UMEMOTO addr2 = (struct in6_addr *)(rth0_out + 1) + 376f95d4633SHajimu UMEMOTO (segments - i - 1); 377f95d4633SHajimu UMEMOTO addr_tmp = *addr1; 378f95d4633SHajimu UMEMOTO *addr1 = *addr2; 379f95d4633SHajimu UMEMOTO *addr2 = addr_tmp; 380f95d4633SHajimu UMEMOTO } 381f95d4633SHajimu UMEMOTO 382f95d4633SHajimu UMEMOTO break; 383f95d4633SHajimu UMEMOTO default: 384f95d4633SHajimu UMEMOTO return (-1); /* type not supported */ 385f95d4633SHajimu UMEMOTO } 386f95d4633SHajimu UMEMOTO 387f95d4633SHajimu UMEMOTO return (0); 388f95d4633SHajimu UMEMOTO } 389f95d4633SHajimu UMEMOTO 390f95d4633SHajimu UMEMOTO int 391f95d4633SHajimu UMEMOTO inet6_rth_segments(const void *bp) 392f95d4633SHajimu UMEMOTO { 393f95d4633SHajimu UMEMOTO struct ip6_rthdr *rh = (struct ip6_rthdr *)bp; 394f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rh0; 395f95d4633SHajimu UMEMOTO int addrs; 396f95d4633SHajimu UMEMOTO 397f95d4633SHajimu UMEMOTO switch (rh->ip6r_type) { 398f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 399f95d4633SHajimu UMEMOTO rh0 = (struct ip6_rthdr0 *)bp; 400f95d4633SHajimu UMEMOTO 401f95d4633SHajimu UMEMOTO /* 402f95d4633SHajimu UMEMOTO * Validation for a type-0 routing header. 403f95d4633SHajimu UMEMOTO * Is this too strict? 404f95d4633SHajimu UMEMOTO */ 405f95d4633SHajimu UMEMOTO if ((rh0->ip6r0_len % 2) != 0 || 406f95d4633SHajimu UMEMOTO (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft) 407f95d4633SHajimu UMEMOTO return (-1); 408f95d4633SHajimu UMEMOTO 409f95d4633SHajimu UMEMOTO return (addrs); 410f95d4633SHajimu UMEMOTO default: 411f95d4633SHajimu UMEMOTO return (-1); /* unknown type */ 412f95d4633SHajimu UMEMOTO } 413f95d4633SHajimu UMEMOTO } 414f95d4633SHajimu UMEMOTO 415f95d4633SHajimu UMEMOTO struct in6_addr * 416f95d4633SHajimu UMEMOTO inet6_rth_getaddr(const void *bp, int idx) 417f95d4633SHajimu UMEMOTO { 418f95d4633SHajimu UMEMOTO struct ip6_rthdr *rh = (struct ip6_rthdr *)bp; 419f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rh0; 420d5cbe1abSHajimu UMEMOTO int addrs; 421f95d4633SHajimu UMEMOTO 422f95d4633SHajimu UMEMOTO switch (rh->ip6r_type) { 423f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 424f95d4633SHajimu UMEMOTO rh0 = (struct ip6_rthdr0 *)bp; 425f95d4633SHajimu UMEMOTO 426f95d4633SHajimu UMEMOTO /* 427f95d4633SHajimu UMEMOTO * Validation for a type-0 routing header. 428f95d4633SHajimu UMEMOTO * Is this too strict? 429f95d4633SHajimu UMEMOTO */ 430d5cbe1abSHajimu UMEMOTO if ((rh0->ip6r0_len % 2) != 0 || 431d5cbe1abSHajimu UMEMOTO (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft) 432f95d4633SHajimu UMEMOTO return (NULL); 433f95d4633SHajimu UMEMOTO 434f95d4633SHajimu UMEMOTO if (idx < 0 || addrs <= idx) 435f95d4633SHajimu UMEMOTO return (NULL); 436f95d4633SHajimu UMEMOTO 437f95d4633SHajimu UMEMOTO return (((struct in6_addr *)(rh0 + 1)) + idx); 438f95d4633SHajimu UMEMOTO default: 439f95d4633SHajimu UMEMOTO return (NULL); /* unknown type */ 440f95d4633SHajimu UMEMOTO break; 44105a244b4SYoshinobu Inoue } 44205a244b4SYoshinobu Inoue } 443