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 50*626c9d74SCraig Rodrigues inet6_rthdr_space(int type, int seg) 5105a244b4SYoshinobu Inoue { 5205a244b4SYoshinobu Inoue switch (type) { 5305a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 5405a244b4SYoshinobu Inoue if (seg < 1 || seg > 23) 5505a244b4SYoshinobu Inoue return (0); 56f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC2292 57f95d4633SHajimu UMEMOTO return (CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) + 58f95d4633SHajimu UMEMOTO sizeof(struct ip6_rthdr0))); 59f95d4633SHajimu UMEMOTO #else 60f95d4633SHajimu UMEMOTO return (CMSG_SPACE(sizeof(struct in6_addr) * seg + 61f95d4633SHajimu UMEMOTO sizeof(struct ip6_rthdr0))); 6205a244b4SYoshinobu Inoue #endif 63f95d4633SHajimu UMEMOTO default: 6405a244b4SYoshinobu Inoue return (0); 6505a244b4SYoshinobu Inoue } 6605a244b4SYoshinobu Inoue } 6705a244b4SYoshinobu Inoue 6805a244b4SYoshinobu Inoue struct cmsghdr * 69*626c9d74SCraig Rodrigues inet6_rthdr_init(void *bp, int type) 7005a244b4SYoshinobu Inoue { 718fb3f3f6SDavid E. O'Brien struct cmsghdr *ch = (struct cmsghdr *)bp; 728fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 737d0d8dc3SYoshinobu Inoue 747d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(ch); 7505a244b4SYoshinobu Inoue 7605a244b4SYoshinobu Inoue ch->cmsg_level = IPPROTO_IPV6; 7705a244b4SYoshinobu Inoue ch->cmsg_type = IPV6_RTHDR; 7805a244b4SYoshinobu Inoue 7905a244b4SYoshinobu Inoue switch (type) { 8005a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 81f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC2292 82f95d4633SHajimu UMEMOTO ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) - 83f95d4633SHajimu UMEMOTO sizeof(struct in6_addr)); 84f95d4633SHajimu UMEMOTO #else 85f95d4633SHajimu UMEMOTO ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0)); 86f95d4633SHajimu UMEMOTO #endif 87f95d4633SHajimu UMEMOTO 8805a244b4SYoshinobu Inoue bzero(rthdr, sizeof(struct ip6_rthdr0)); 8905a244b4SYoshinobu Inoue rthdr->ip6r_type = IPV6_RTHDR_TYPE_0; 9005a244b4SYoshinobu Inoue return (ch); 9105a244b4SYoshinobu Inoue default: 9205a244b4SYoshinobu Inoue return (NULL); 9305a244b4SYoshinobu Inoue } 9405a244b4SYoshinobu Inoue } 9505a244b4SYoshinobu Inoue 96f95d4633SHajimu UMEMOTO /* ARGSUSED */ 9705a244b4SYoshinobu Inoue int 98*626c9d74SCraig Rodrigues inet6_rthdr_add(struct cmsghdr *cmsg, const struct in6_addr *addr, u_int flags) 9905a244b4SYoshinobu Inoue { 1008fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 1017d0d8dc3SYoshinobu Inoue 1027d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 10305a244b4SYoshinobu Inoue 10405a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 10505a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 10605a244b4SYoshinobu Inoue { 10705a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 108f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) 10905a244b4SYoshinobu Inoue return (-1); 110f95d4633SHajimu UMEMOTO if (rt0->ip6r0_segleft == 23) 11105a244b4SYoshinobu Inoue return (-1); 112f95d4633SHajimu UMEMOTO 113f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 11405a244b4SYoshinobu Inoue if (flags == IPV6_RTHDR_STRICT) { 11505a244b4SYoshinobu Inoue int c, b; 11605a244b4SYoshinobu Inoue c = rt0->ip6r0_segleft / 8; 11705a244b4SYoshinobu Inoue b = rt0->ip6r0_segleft % 8; 11805a244b4SYoshinobu Inoue rt0->ip6r0_slmap[c] |= (1 << (7 - b)); 11905a244b4SYoshinobu Inoue } 120f95d4633SHajimu UMEMOTO #else 121f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE) 122f95d4633SHajimu UMEMOTO return (-1); 123f95d4633SHajimu UMEMOTO #endif 12405a244b4SYoshinobu Inoue rt0->ip6r0_segleft++; 12505a244b4SYoshinobu Inoue bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3), 12605a244b4SYoshinobu Inoue sizeof(struct in6_addr)); 12705a244b4SYoshinobu Inoue rt0->ip6r0_len += sizeof(struct in6_addr) >> 3; 12805a244b4SYoshinobu Inoue cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3); 12905a244b4SYoshinobu Inoue break; 13005a244b4SYoshinobu Inoue } 13105a244b4SYoshinobu Inoue default: 13205a244b4SYoshinobu Inoue return (-1); 13305a244b4SYoshinobu Inoue } 13405a244b4SYoshinobu Inoue 13505a244b4SYoshinobu Inoue return (0); 13605a244b4SYoshinobu Inoue } 13705a244b4SYoshinobu Inoue 138f95d4633SHajimu UMEMOTO /* ARGSUSED */ 13905a244b4SYoshinobu Inoue int 140*626c9d74SCraig Rodrigues inet6_rthdr_lasthop(struct cmsghdr *cmsg, unsigned int flags) 14105a244b4SYoshinobu Inoue { 1428fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 1437d0d8dc3SYoshinobu Inoue 1447d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 14505a244b4SYoshinobu Inoue 14605a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 14705a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 14805a244b4SYoshinobu Inoue { 14905a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 150f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 151f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) 15205a244b4SYoshinobu Inoue return (-1); 153f95d4633SHajimu UMEMOTO #endif /* COMPAT_RFC1883 */ 154f95d4633SHajimu UMEMOTO if (rt0->ip6r0_segleft > 23) 15505a244b4SYoshinobu Inoue return (-1); 156f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 15705a244b4SYoshinobu Inoue if (flags == IPV6_RTHDR_STRICT) { 15805a244b4SYoshinobu Inoue int c, b; 15905a244b4SYoshinobu Inoue c = rt0->ip6r0_segleft / 8; 16005a244b4SYoshinobu Inoue b = rt0->ip6r0_segleft % 8; 16105a244b4SYoshinobu Inoue rt0->ip6r0_slmap[c] |= (1 << (7 - b)); 16205a244b4SYoshinobu Inoue } 163f95d4633SHajimu UMEMOTO #else 164f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE) 165f95d4633SHajimu UMEMOTO return (-1); 166f95d4633SHajimu UMEMOTO #endif /* COMPAT_RFC1883 */ 16705a244b4SYoshinobu Inoue break; 16805a244b4SYoshinobu Inoue } 16905a244b4SYoshinobu Inoue default: 17005a244b4SYoshinobu Inoue return (-1); 17105a244b4SYoshinobu Inoue } 17205a244b4SYoshinobu Inoue 17305a244b4SYoshinobu Inoue return (0); 17405a244b4SYoshinobu Inoue } 17505a244b4SYoshinobu Inoue 17605a244b4SYoshinobu Inoue #if 0 17705a244b4SYoshinobu Inoue int 178*626c9d74SCraig Rodrigues inet6_rthdr_reverse(const struct cmsghdr *in, struct cmsghdr *out) 17905a244b4SYoshinobu Inoue { 180f95d4633SHajimu UMEMOTO 181f95d4633SHajimu UMEMOTO return (-1); 18205a244b4SYoshinobu Inoue } 18305a244b4SYoshinobu Inoue #endif 18405a244b4SYoshinobu Inoue 18505a244b4SYoshinobu Inoue int 186*626c9d74SCraig Rodrigues inet6_rthdr_segments(const struct cmsghdr *cmsg) 18705a244b4SYoshinobu Inoue { 1888fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 1897d0d8dc3SYoshinobu Inoue 1907d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 19105a244b4SYoshinobu Inoue 19205a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 19305a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 19405a244b4SYoshinobu Inoue { 19505a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 19605a244b4SYoshinobu Inoue 197f95d4633SHajimu UMEMOTO if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) 198f95d4633SHajimu UMEMOTO return (-1); 19905a244b4SYoshinobu Inoue 20005a244b4SYoshinobu Inoue return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 20105a244b4SYoshinobu Inoue } 20205a244b4SYoshinobu Inoue 20305a244b4SYoshinobu Inoue default: 204f95d4633SHajimu UMEMOTO return (-1); 20505a244b4SYoshinobu Inoue } 20605a244b4SYoshinobu Inoue } 20705a244b4SYoshinobu Inoue 20805a244b4SYoshinobu Inoue struct in6_addr * 209*626c9d74SCraig Rodrigues inet6_rthdr_getaddr(struct cmsghdr *cmsg, int idx) 21005a244b4SYoshinobu Inoue { 2118fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 2127d0d8dc3SYoshinobu Inoue 2137d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 21405a244b4SYoshinobu Inoue 21505a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 21605a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 21705a244b4SYoshinobu Inoue { 21805a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 21905a244b4SYoshinobu Inoue int naddr; 22005a244b4SYoshinobu Inoue 221f95d4633SHajimu UMEMOTO if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) 22205a244b4SYoshinobu Inoue return NULL; 22305a244b4SYoshinobu Inoue naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 224f95d4633SHajimu UMEMOTO if (idx <= 0 || naddr < idx) 22505a244b4SYoshinobu Inoue return NULL; 226f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC2292 227f95d4633SHajimu UMEMOTO return (((struct in6_addr *)(rt0 + 1)) + idx - 1); 228f95d4633SHajimu UMEMOTO #else 229f95d4633SHajimu UMEMOTO return (((struct in6_addr *)(rt0 + 1)) + idx); 230f95d4633SHajimu UMEMOTO #endif 23105a244b4SYoshinobu Inoue } 23205a244b4SYoshinobu Inoue 23305a244b4SYoshinobu Inoue default: 23405a244b4SYoshinobu Inoue return NULL; 23505a244b4SYoshinobu Inoue } 23605a244b4SYoshinobu Inoue } 23705a244b4SYoshinobu Inoue 23805a244b4SYoshinobu Inoue int 239*626c9d74SCraig Rodrigues inet6_rthdr_getflags(const struct cmsghdr *cmsg, int idx) 24005a244b4SYoshinobu Inoue { 2418fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 2427d0d8dc3SYoshinobu Inoue 2437d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 24405a244b4SYoshinobu Inoue 24505a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 24605a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 24705a244b4SYoshinobu Inoue { 24805a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 24905a244b4SYoshinobu Inoue int naddr; 25005a244b4SYoshinobu Inoue 251f95d4633SHajimu UMEMOTO if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) 252f95d4633SHajimu UMEMOTO return (-1); 25305a244b4SYoshinobu Inoue naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 254f95d4633SHajimu UMEMOTO if (idx < 0 || naddr < idx) 255f95d4633SHajimu UMEMOTO return (-1); 256f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 25788ff5695SSUZUKI Shinsuke if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8))) 25805a244b4SYoshinobu Inoue return IPV6_RTHDR_STRICT; 25905a244b4SYoshinobu Inoue else 26005a244b4SYoshinobu Inoue return IPV6_RTHDR_LOOSE; 261f95d4633SHajimu UMEMOTO #else 262f95d4633SHajimu UMEMOTO return IPV6_RTHDR_LOOSE; 263f95d4633SHajimu UMEMOTO #endif /* COMPAT_RFC1883 */ 26405a244b4SYoshinobu Inoue } 26505a244b4SYoshinobu Inoue 26605a244b4SYoshinobu Inoue default: 267f95d4633SHajimu UMEMOTO return (-1); 268f95d4633SHajimu UMEMOTO } 269f95d4633SHajimu UMEMOTO } 270f95d4633SHajimu UMEMOTO 271f95d4633SHajimu UMEMOTO /* 272d84e2130SHajimu UMEMOTO * RFC3542 API 273f95d4633SHajimu UMEMOTO */ 274f95d4633SHajimu UMEMOTO 275f95d4633SHajimu UMEMOTO socklen_t 276f95d4633SHajimu UMEMOTO inet6_rth_space(int type, int segments) 277f95d4633SHajimu UMEMOTO { 278f95d4633SHajimu UMEMOTO switch (type) { 279f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 28018a60731SMike Makonnen if ((segments >= 0) && (segments <= 127)) 281f95d4633SHajimu UMEMOTO return (((segments * 2) + 1) << 3); 28218a60731SMike Makonnen /* FALLTHROUGH */ 283f95d4633SHajimu UMEMOTO default: 284f95d4633SHajimu UMEMOTO return (0); /* type not suppported */ 285f95d4633SHajimu UMEMOTO } 286f95d4633SHajimu UMEMOTO } 287f95d4633SHajimu UMEMOTO 288f95d4633SHajimu UMEMOTO void * 289f95d4633SHajimu UMEMOTO inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments) 290f95d4633SHajimu UMEMOTO { 291f95d4633SHajimu UMEMOTO struct ip6_rthdr *rth = (struct ip6_rthdr *)bp; 292f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rth0; 293f95d4633SHajimu UMEMOTO 294f95d4633SHajimu UMEMOTO switch (type) { 295f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 296f95d4633SHajimu UMEMOTO /* length validation */ 297f95d4633SHajimu UMEMOTO if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments)) 298f95d4633SHajimu UMEMOTO return (NULL); 29918a60731SMike Makonnen /* segment validation */ 30018a60731SMike Makonnen if ((segments < 0) || (segments > 127)) 30118a60731SMike Makonnen return (NULL); 302f95d4633SHajimu UMEMOTO 303f95d4633SHajimu UMEMOTO memset(bp, 0, bp_len); 304f95d4633SHajimu UMEMOTO rth0 = (struct ip6_rthdr0 *)rth; 305f95d4633SHajimu UMEMOTO rth0->ip6r0_len = segments * 2; 306f95d4633SHajimu UMEMOTO rth0->ip6r0_type = IPV6_RTHDR_TYPE_0; 307f95d4633SHajimu UMEMOTO rth0->ip6r0_segleft = 0; 308f95d4633SHajimu UMEMOTO rth0->ip6r0_reserved = 0; 309f95d4633SHajimu UMEMOTO break; 310f95d4633SHajimu UMEMOTO default: 311f95d4633SHajimu UMEMOTO return (NULL); /* type not supported */ 312f95d4633SHajimu UMEMOTO } 313f95d4633SHajimu UMEMOTO 314f95d4633SHajimu UMEMOTO return (bp); 315f95d4633SHajimu UMEMOTO } 316f95d4633SHajimu UMEMOTO 317f95d4633SHajimu UMEMOTO int 318f95d4633SHajimu UMEMOTO inet6_rth_add(void *bp, const struct in6_addr *addr) 319f95d4633SHajimu UMEMOTO { 320f95d4633SHajimu UMEMOTO struct ip6_rthdr *rth = (struct ip6_rthdr *)bp; 321f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rth0; 322f95d4633SHajimu UMEMOTO struct in6_addr *nextaddr; 323f95d4633SHajimu UMEMOTO 324f95d4633SHajimu UMEMOTO switch (rth->ip6r_type) { 325f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 326f95d4633SHajimu UMEMOTO rth0 = (struct ip6_rthdr0 *)rth; 32718a60731SMike Makonnen /* Don't exceed the number of stated segments */ 32818a60731SMike Makonnen if (rth0->ip6r0_segleft == (rth0->ip6r0_len / 2)) 32918a60731SMike Makonnen return (-1); 330f95d4633SHajimu UMEMOTO nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft; 331f95d4633SHajimu UMEMOTO *nextaddr = *addr; 332f95d4633SHajimu UMEMOTO rth0->ip6r0_segleft++; 333f95d4633SHajimu UMEMOTO break; 334f95d4633SHajimu UMEMOTO default: 335f95d4633SHajimu UMEMOTO return (-1); /* type not supported */ 336f95d4633SHajimu UMEMOTO } 337f95d4633SHajimu UMEMOTO 338f95d4633SHajimu UMEMOTO return (0); 339f95d4633SHajimu UMEMOTO } 340f95d4633SHajimu UMEMOTO 341f95d4633SHajimu UMEMOTO int 342f95d4633SHajimu UMEMOTO inet6_rth_reverse(const void *in, void *out) 343f95d4633SHajimu UMEMOTO { 344f95d4633SHajimu UMEMOTO struct ip6_rthdr *rth_in = (struct ip6_rthdr *)in; 345f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rth0_in, *rth0_out; 346f95d4633SHajimu UMEMOTO int i, segments; 347f95d4633SHajimu UMEMOTO 348f95d4633SHajimu UMEMOTO switch (rth_in->ip6r_type) { 349f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 350f95d4633SHajimu UMEMOTO rth0_in = (struct ip6_rthdr0 *)in; 351f95d4633SHajimu UMEMOTO rth0_out = (struct ip6_rthdr0 *)out; 352f95d4633SHajimu UMEMOTO 353f95d4633SHajimu UMEMOTO /* parameter validation XXX too paranoid? */ 354f95d4633SHajimu UMEMOTO if (rth0_in->ip6r0_len % 2) 355f95d4633SHajimu UMEMOTO return (-1); 356f95d4633SHajimu UMEMOTO segments = rth0_in->ip6r0_len / 2; 357f95d4633SHajimu UMEMOTO 358f95d4633SHajimu UMEMOTO /* we can't use memcpy here, since in and out may overlap */ 359f95d4633SHajimu UMEMOTO memmove((void *)rth0_out, (void *)rth0_in, 360f95d4633SHajimu UMEMOTO ((rth0_in->ip6r0_len) + 1) << 3); 361f95d4633SHajimu UMEMOTO rth0_out->ip6r0_segleft = segments; 362f95d4633SHajimu UMEMOTO 363f95d4633SHajimu UMEMOTO /* reverse the addresses */ 364f95d4633SHajimu UMEMOTO for (i = 0; i < segments / 2; i++) { 365f95d4633SHajimu UMEMOTO struct in6_addr addr_tmp, *addr1, *addr2; 366f95d4633SHajimu UMEMOTO 367f95d4633SHajimu UMEMOTO addr1 = (struct in6_addr *)(rth0_out + 1) + i; 368f95d4633SHajimu UMEMOTO addr2 = (struct in6_addr *)(rth0_out + 1) + 369f95d4633SHajimu UMEMOTO (segments - i - 1); 370f95d4633SHajimu UMEMOTO addr_tmp = *addr1; 371f95d4633SHajimu UMEMOTO *addr1 = *addr2; 372f95d4633SHajimu UMEMOTO *addr2 = addr_tmp; 373f95d4633SHajimu UMEMOTO } 374f95d4633SHajimu UMEMOTO 375f95d4633SHajimu UMEMOTO break; 376f95d4633SHajimu UMEMOTO default: 377f95d4633SHajimu UMEMOTO return (-1); /* type not supported */ 378f95d4633SHajimu UMEMOTO } 379f95d4633SHajimu UMEMOTO 380f95d4633SHajimu UMEMOTO return (0); 381f95d4633SHajimu UMEMOTO } 382f95d4633SHajimu UMEMOTO 383f95d4633SHajimu UMEMOTO int 384f95d4633SHajimu UMEMOTO inet6_rth_segments(const void *bp) 385f95d4633SHajimu UMEMOTO { 386f95d4633SHajimu UMEMOTO struct ip6_rthdr *rh = (struct ip6_rthdr *)bp; 387f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rh0; 388f95d4633SHajimu UMEMOTO int addrs; 389f95d4633SHajimu UMEMOTO 390f95d4633SHajimu UMEMOTO switch (rh->ip6r_type) { 391f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 392f95d4633SHajimu UMEMOTO rh0 = (struct ip6_rthdr0 *)bp; 393f95d4633SHajimu UMEMOTO 394f95d4633SHajimu UMEMOTO /* 395f95d4633SHajimu UMEMOTO * Validation for a type-0 routing header. 396f95d4633SHajimu UMEMOTO * Is this too strict? 397f95d4633SHajimu UMEMOTO */ 398f95d4633SHajimu UMEMOTO if ((rh0->ip6r0_len % 2) != 0 || 399f95d4633SHajimu UMEMOTO (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft) 400f95d4633SHajimu UMEMOTO return (-1); 401f95d4633SHajimu UMEMOTO 402f95d4633SHajimu UMEMOTO return (addrs); 403f95d4633SHajimu UMEMOTO default: 404f95d4633SHajimu UMEMOTO return (-1); /* unknown type */ 405f95d4633SHajimu UMEMOTO } 406f95d4633SHajimu UMEMOTO } 407f95d4633SHajimu UMEMOTO 408f95d4633SHajimu UMEMOTO struct in6_addr * 409f95d4633SHajimu UMEMOTO inet6_rth_getaddr(const void *bp, int idx) 410f95d4633SHajimu UMEMOTO { 411f95d4633SHajimu UMEMOTO struct ip6_rthdr *rh = (struct ip6_rthdr *)bp; 412f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rh0; 413d5cbe1abSHajimu UMEMOTO int addrs; 414f95d4633SHajimu UMEMOTO 415f95d4633SHajimu UMEMOTO switch (rh->ip6r_type) { 416f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 417f95d4633SHajimu UMEMOTO rh0 = (struct ip6_rthdr0 *)bp; 418f95d4633SHajimu UMEMOTO 419f95d4633SHajimu UMEMOTO /* 420f95d4633SHajimu UMEMOTO * Validation for a type-0 routing header. 421f95d4633SHajimu UMEMOTO * Is this too strict? 422f95d4633SHajimu UMEMOTO */ 423d5cbe1abSHajimu UMEMOTO if ((rh0->ip6r0_len % 2) != 0 || 424d5cbe1abSHajimu UMEMOTO (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft) 425f95d4633SHajimu UMEMOTO return (NULL); 426f95d4633SHajimu UMEMOTO 427f95d4633SHajimu UMEMOTO if (idx < 0 || addrs <= idx) 428f95d4633SHajimu UMEMOTO return (NULL); 429f95d4633SHajimu UMEMOTO 430f95d4633SHajimu UMEMOTO return (((struct in6_addr *)(rh0 + 1)) + idx); 431f95d4633SHajimu UMEMOTO default: 432f95d4633SHajimu UMEMOTO return (NULL); /* unknown type */ 433f95d4633SHajimu UMEMOTO break; 43405a244b4SYoshinobu Inoue } 43505a244b4SYoshinobu Inoue } 436