1f95d4633SHajimu UMEMOTO /* $KAME: rthdr.c,v 1.19 2003/06/06 10:48:51 itojun Exp $ */ 288ff5695SSUZUKI Shinsuke 3*8a16b7a1SPedro F. Giffuni /*- 4*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 5*8a16b7a1SPedro F. Giffuni * 605a244b4SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 705a244b4SYoshinobu Inoue * All rights reserved. 805a244b4SYoshinobu Inoue * 905a244b4SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 1005a244b4SYoshinobu Inoue * modification, are permitted provided that the following conditions 1105a244b4SYoshinobu Inoue * are met: 1205a244b4SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 1305a244b4SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1405a244b4SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1505a244b4SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1605a244b4SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1705a244b4SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1805a244b4SYoshinobu Inoue * may be used to endorse or promote products derived from this software 1905a244b4SYoshinobu Inoue * without specific prior written permission. 2005a244b4SYoshinobu Inoue * 2105a244b4SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2205a244b4SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2305a244b4SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2405a244b4SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2505a244b4SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2605a244b4SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2705a244b4SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2805a244b4SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2905a244b4SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3005a244b4SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3105a244b4SYoshinobu Inoue * SUCH DAMAGE. 3205a244b4SYoshinobu Inoue */ 3305a244b4SYoshinobu Inoue 34333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 35333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 36333fc21eSDavid E. O'Brien 3705a244b4SYoshinobu Inoue #include <sys/param.h> 3805a244b4SYoshinobu Inoue #include <sys/socket.h> 3905a244b4SYoshinobu Inoue 4005a244b4SYoshinobu Inoue #include <netinet/in.h> 4105a244b4SYoshinobu Inoue #include <netinet/ip6.h> 4205a244b4SYoshinobu Inoue 4305a244b4SYoshinobu Inoue #include <string.h> 4405a244b4SYoshinobu Inoue #include <stdio.h> 4505a244b4SYoshinobu Inoue 46f95d4633SHajimu UMEMOTO /* 47f95d4633SHajimu UMEMOTO * RFC2292 API 48f95d4633SHajimu UMEMOTO */ 49f95d4633SHajimu UMEMOTO 5005a244b4SYoshinobu Inoue size_t 51626c9d74SCraig Rodrigues inet6_rthdr_space(int type, int 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 * 70626c9d74SCraig Rodrigues inet6_rthdr_init(void *bp, int type) 7105a244b4SYoshinobu Inoue { 728fb3f3f6SDavid E. O'Brien struct cmsghdr *ch = (struct cmsghdr *)bp; 738fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 747d0d8dc3SYoshinobu Inoue 757d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(ch); 7605a244b4SYoshinobu Inoue 7705a244b4SYoshinobu Inoue ch->cmsg_level = IPPROTO_IPV6; 7805a244b4SYoshinobu Inoue ch->cmsg_type = IPV6_RTHDR; 7905a244b4SYoshinobu Inoue 8005a244b4SYoshinobu Inoue switch (type) { 8105a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 82f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC2292 83f95d4633SHajimu UMEMOTO ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) - 84f95d4633SHajimu UMEMOTO sizeof(struct in6_addr)); 85f95d4633SHajimu UMEMOTO #else 86f95d4633SHajimu UMEMOTO ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0)); 87f95d4633SHajimu UMEMOTO #endif 88f95d4633SHajimu UMEMOTO 8905a244b4SYoshinobu Inoue bzero(rthdr, sizeof(struct ip6_rthdr0)); 9005a244b4SYoshinobu Inoue rthdr->ip6r_type = IPV6_RTHDR_TYPE_0; 9105a244b4SYoshinobu Inoue return (ch); 9205a244b4SYoshinobu Inoue default: 9305a244b4SYoshinobu Inoue return (NULL); 9405a244b4SYoshinobu Inoue } 9505a244b4SYoshinobu Inoue } 9605a244b4SYoshinobu Inoue 97f95d4633SHajimu UMEMOTO /* ARGSUSED */ 9805a244b4SYoshinobu Inoue int 99626c9d74SCraig Rodrigues inet6_rthdr_add(struct cmsghdr *cmsg, const struct in6_addr *addr, u_int flags) 10005a244b4SYoshinobu Inoue { 1018fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 1027d0d8dc3SYoshinobu Inoue 1037d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 10405a244b4SYoshinobu Inoue 10505a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 10605a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 10705a244b4SYoshinobu Inoue { 10805a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 109f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) 11005a244b4SYoshinobu Inoue return (-1); 111f95d4633SHajimu UMEMOTO if (rt0->ip6r0_segleft == 23) 11205a244b4SYoshinobu Inoue return (-1); 113f95d4633SHajimu UMEMOTO 114f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 11505a244b4SYoshinobu Inoue if (flags == IPV6_RTHDR_STRICT) { 11605a244b4SYoshinobu Inoue int c, b; 11705a244b4SYoshinobu Inoue c = rt0->ip6r0_segleft / 8; 11805a244b4SYoshinobu Inoue b = rt0->ip6r0_segleft % 8; 11905a244b4SYoshinobu Inoue rt0->ip6r0_slmap[c] |= (1 << (7 - b)); 12005a244b4SYoshinobu Inoue } 121f95d4633SHajimu UMEMOTO #else 122f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE) 123f95d4633SHajimu UMEMOTO return (-1); 124f95d4633SHajimu UMEMOTO #endif 12505a244b4SYoshinobu Inoue rt0->ip6r0_segleft++; 12605a244b4SYoshinobu Inoue bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3), 12705a244b4SYoshinobu Inoue sizeof(struct in6_addr)); 12805a244b4SYoshinobu Inoue rt0->ip6r0_len += sizeof(struct in6_addr) >> 3; 12905a244b4SYoshinobu Inoue cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3); 13005a244b4SYoshinobu Inoue break; 13105a244b4SYoshinobu Inoue } 13205a244b4SYoshinobu Inoue default: 13305a244b4SYoshinobu Inoue return (-1); 13405a244b4SYoshinobu Inoue } 13505a244b4SYoshinobu Inoue 13605a244b4SYoshinobu Inoue return (0); 13705a244b4SYoshinobu Inoue } 13805a244b4SYoshinobu Inoue 139f95d4633SHajimu UMEMOTO /* ARGSUSED */ 14005a244b4SYoshinobu Inoue int 141626c9d74SCraig Rodrigues inet6_rthdr_lasthop(struct cmsghdr *cmsg, unsigned int flags) 14205a244b4SYoshinobu Inoue { 1438fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 1447d0d8dc3SYoshinobu Inoue 1457d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 14605a244b4SYoshinobu Inoue 14705a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 14805a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 14905a244b4SYoshinobu Inoue { 15005a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 151f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 152f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) 15305a244b4SYoshinobu Inoue return (-1); 154f95d4633SHajimu UMEMOTO #endif /* COMPAT_RFC1883 */ 155f95d4633SHajimu UMEMOTO if (rt0->ip6r0_segleft > 23) 15605a244b4SYoshinobu Inoue return (-1); 157f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 15805a244b4SYoshinobu Inoue if (flags == IPV6_RTHDR_STRICT) { 15905a244b4SYoshinobu Inoue int c, b; 16005a244b4SYoshinobu Inoue c = rt0->ip6r0_segleft / 8; 16105a244b4SYoshinobu Inoue b = rt0->ip6r0_segleft % 8; 16205a244b4SYoshinobu Inoue rt0->ip6r0_slmap[c] |= (1 << (7 - b)); 16305a244b4SYoshinobu Inoue } 164f95d4633SHajimu UMEMOTO #else 165f95d4633SHajimu UMEMOTO if (flags != IPV6_RTHDR_LOOSE) 166f95d4633SHajimu UMEMOTO return (-1); 167f95d4633SHajimu UMEMOTO #endif /* COMPAT_RFC1883 */ 16805a244b4SYoshinobu Inoue break; 16905a244b4SYoshinobu Inoue } 17005a244b4SYoshinobu Inoue default: 17105a244b4SYoshinobu Inoue return (-1); 17205a244b4SYoshinobu Inoue } 17305a244b4SYoshinobu Inoue 17405a244b4SYoshinobu Inoue return (0); 17505a244b4SYoshinobu Inoue } 17605a244b4SYoshinobu Inoue 17705a244b4SYoshinobu Inoue #if 0 17805a244b4SYoshinobu Inoue int 179626c9d74SCraig Rodrigues inet6_rthdr_reverse(const struct cmsghdr *in, struct cmsghdr *out) 18005a244b4SYoshinobu Inoue { 181f95d4633SHajimu UMEMOTO 182f95d4633SHajimu UMEMOTO return (-1); 18305a244b4SYoshinobu Inoue } 18405a244b4SYoshinobu Inoue #endif 18505a244b4SYoshinobu Inoue 18605a244b4SYoshinobu Inoue int 187626c9d74SCraig Rodrigues inet6_rthdr_segments(const struct cmsghdr *cmsg) 18805a244b4SYoshinobu Inoue { 1898fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 1907d0d8dc3SYoshinobu Inoue 1917d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 19205a244b4SYoshinobu Inoue 19305a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 19405a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 19505a244b4SYoshinobu Inoue { 19605a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 19705a244b4SYoshinobu Inoue 198f95d4633SHajimu UMEMOTO if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) 199f95d4633SHajimu UMEMOTO return (-1); 20005a244b4SYoshinobu Inoue 20105a244b4SYoshinobu Inoue return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 20205a244b4SYoshinobu Inoue } 20305a244b4SYoshinobu Inoue 20405a244b4SYoshinobu Inoue default: 205f95d4633SHajimu UMEMOTO return (-1); 20605a244b4SYoshinobu Inoue } 20705a244b4SYoshinobu Inoue } 20805a244b4SYoshinobu Inoue 20905a244b4SYoshinobu Inoue struct in6_addr * 210626c9d74SCraig Rodrigues inet6_rthdr_getaddr(struct cmsghdr *cmsg, int idx) 21105a244b4SYoshinobu Inoue { 2128fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 2137d0d8dc3SYoshinobu Inoue 2147d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 21505a244b4SYoshinobu Inoue 21605a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 21705a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 21805a244b4SYoshinobu Inoue { 21905a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 22005a244b4SYoshinobu Inoue int naddr; 22105a244b4SYoshinobu Inoue 222f95d4633SHajimu UMEMOTO if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) 22305a244b4SYoshinobu Inoue return NULL; 22405a244b4SYoshinobu Inoue naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 225f95d4633SHajimu UMEMOTO if (idx <= 0 || naddr < idx) 22605a244b4SYoshinobu Inoue return NULL; 227f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC2292 228f95d4633SHajimu UMEMOTO return (((struct in6_addr *)(rt0 + 1)) + idx - 1); 229f95d4633SHajimu UMEMOTO #else 230f95d4633SHajimu UMEMOTO return (((struct in6_addr *)(rt0 + 1)) + idx); 231f95d4633SHajimu UMEMOTO #endif 23205a244b4SYoshinobu Inoue } 23305a244b4SYoshinobu Inoue 23405a244b4SYoshinobu Inoue default: 23505a244b4SYoshinobu Inoue return NULL; 23605a244b4SYoshinobu Inoue } 23705a244b4SYoshinobu Inoue } 23805a244b4SYoshinobu Inoue 23905a244b4SYoshinobu Inoue int 240626c9d74SCraig Rodrigues inet6_rthdr_getflags(const struct cmsghdr *cmsg, int idx) 24105a244b4SYoshinobu Inoue { 2428fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 2437d0d8dc3SYoshinobu Inoue 2447d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 24505a244b4SYoshinobu Inoue 24605a244b4SYoshinobu Inoue switch (rthdr->ip6r_type) { 24705a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 24805a244b4SYoshinobu Inoue { 24905a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 25005a244b4SYoshinobu Inoue int naddr; 25105a244b4SYoshinobu Inoue 252f95d4633SHajimu UMEMOTO if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) 253f95d4633SHajimu UMEMOTO return (-1); 25405a244b4SYoshinobu Inoue naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 255f95d4633SHajimu UMEMOTO if (idx < 0 || naddr < idx) 256f95d4633SHajimu UMEMOTO return (-1); 257f95d4633SHajimu UMEMOTO #ifdef COMPAT_RFC1883 /* XXX */ 25888ff5695SSUZUKI Shinsuke if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8))) 25905a244b4SYoshinobu Inoue return IPV6_RTHDR_STRICT; 26005a244b4SYoshinobu Inoue else 26105a244b4SYoshinobu Inoue return IPV6_RTHDR_LOOSE; 262f95d4633SHajimu UMEMOTO #else 263f95d4633SHajimu UMEMOTO return IPV6_RTHDR_LOOSE; 264f95d4633SHajimu UMEMOTO #endif /* COMPAT_RFC1883 */ 26505a244b4SYoshinobu Inoue } 26605a244b4SYoshinobu Inoue 26705a244b4SYoshinobu Inoue default: 268f95d4633SHajimu UMEMOTO return (-1); 269f95d4633SHajimu UMEMOTO } 270f95d4633SHajimu UMEMOTO } 271f95d4633SHajimu UMEMOTO 272f95d4633SHajimu UMEMOTO /* 273d84e2130SHajimu UMEMOTO * RFC3542 API 274f95d4633SHajimu UMEMOTO */ 275f95d4633SHajimu UMEMOTO 276f95d4633SHajimu UMEMOTO socklen_t 277f95d4633SHajimu UMEMOTO inet6_rth_space(int type, int segments) 278f95d4633SHajimu UMEMOTO { 279f95d4633SHajimu UMEMOTO switch (type) { 280f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 28118a60731SMike Makonnen if ((segments >= 0) && (segments <= 127)) 282f95d4633SHajimu UMEMOTO return (((segments * 2) + 1) << 3); 28318a60731SMike Makonnen /* FALLTHROUGH */ 284f95d4633SHajimu UMEMOTO default: 285f95d4633SHajimu UMEMOTO return (0); /* type not suppported */ 286f95d4633SHajimu UMEMOTO } 287f95d4633SHajimu UMEMOTO } 288f95d4633SHajimu UMEMOTO 289f95d4633SHajimu UMEMOTO void * 290f95d4633SHajimu UMEMOTO inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments) 291f95d4633SHajimu UMEMOTO { 292f95d4633SHajimu UMEMOTO struct ip6_rthdr *rth = (struct ip6_rthdr *)bp; 293f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rth0; 294f95d4633SHajimu UMEMOTO 295f95d4633SHajimu UMEMOTO switch (type) { 296f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 297f95d4633SHajimu UMEMOTO /* length validation */ 298f95d4633SHajimu UMEMOTO if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments)) 299f95d4633SHajimu UMEMOTO return (NULL); 30018a60731SMike Makonnen /* segment validation */ 30118a60731SMike Makonnen if ((segments < 0) || (segments > 127)) 30218a60731SMike Makonnen return (NULL); 303f95d4633SHajimu UMEMOTO 304f95d4633SHajimu UMEMOTO memset(bp, 0, bp_len); 305f95d4633SHajimu UMEMOTO rth0 = (struct ip6_rthdr0 *)rth; 306f95d4633SHajimu UMEMOTO rth0->ip6r0_len = segments * 2; 307f95d4633SHajimu UMEMOTO rth0->ip6r0_type = IPV6_RTHDR_TYPE_0; 308f95d4633SHajimu UMEMOTO rth0->ip6r0_segleft = 0; 309f95d4633SHajimu UMEMOTO rth0->ip6r0_reserved = 0; 310f95d4633SHajimu UMEMOTO break; 311f95d4633SHajimu UMEMOTO default: 312f95d4633SHajimu UMEMOTO return (NULL); /* type not supported */ 313f95d4633SHajimu UMEMOTO } 314f95d4633SHajimu UMEMOTO 315f95d4633SHajimu UMEMOTO return (bp); 316f95d4633SHajimu UMEMOTO } 317f95d4633SHajimu UMEMOTO 318f95d4633SHajimu UMEMOTO int 319f95d4633SHajimu UMEMOTO inet6_rth_add(void *bp, const struct in6_addr *addr) 320f95d4633SHajimu UMEMOTO { 321f95d4633SHajimu UMEMOTO struct ip6_rthdr *rth = (struct ip6_rthdr *)bp; 322f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rth0; 323f95d4633SHajimu UMEMOTO struct in6_addr *nextaddr; 324f95d4633SHajimu UMEMOTO 325f95d4633SHajimu UMEMOTO switch (rth->ip6r_type) { 326f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 327f95d4633SHajimu UMEMOTO rth0 = (struct ip6_rthdr0 *)rth; 32818a60731SMike Makonnen /* Don't exceed the number of stated segments */ 32918a60731SMike Makonnen if (rth0->ip6r0_segleft == (rth0->ip6r0_len / 2)) 33018a60731SMike Makonnen return (-1); 331f95d4633SHajimu UMEMOTO nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft; 332f95d4633SHajimu UMEMOTO *nextaddr = *addr; 333f95d4633SHajimu UMEMOTO rth0->ip6r0_segleft++; 334f95d4633SHajimu UMEMOTO break; 335f95d4633SHajimu UMEMOTO default: 336f95d4633SHajimu UMEMOTO return (-1); /* type not supported */ 337f95d4633SHajimu UMEMOTO } 338f95d4633SHajimu UMEMOTO 339f95d4633SHajimu UMEMOTO return (0); 340f95d4633SHajimu UMEMOTO } 341f95d4633SHajimu UMEMOTO 342f95d4633SHajimu UMEMOTO int 343f95d4633SHajimu UMEMOTO inet6_rth_reverse(const void *in, void *out) 344f95d4633SHajimu UMEMOTO { 345f95d4633SHajimu UMEMOTO struct ip6_rthdr *rth_in = (struct ip6_rthdr *)in; 346f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rth0_in, *rth0_out; 347f95d4633SHajimu UMEMOTO int i, segments; 348f95d4633SHajimu UMEMOTO 349f95d4633SHajimu UMEMOTO switch (rth_in->ip6r_type) { 350f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 351f95d4633SHajimu UMEMOTO rth0_in = (struct ip6_rthdr0 *)in; 352f95d4633SHajimu UMEMOTO rth0_out = (struct ip6_rthdr0 *)out; 353f95d4633SHajimu UMEMOTO 354f95d4633SHajimu UMEMOTO /* parameter validation XXX too paranoid? */ 355f95d4633SHajimu UMEMOTO if (rth0_in->ip6r0_len % 2) 356f95d4633SHajimu UMEMOTO return (-1); 357f95d4633SHajimu UMEMOTO segments = rth0_in->ip6r0_len / 2; 358f95d4633SHajimu UMEMOTO 359f95d4633SHajimu UMEMOTO /* we can't use memcpy here, since in and out may overlap */ 360f95d4633SHajimu UMEMOTO memmove((void *)rth0_out, (void *)rth0_in, 361f95d4633SHajimu UMEMOTO ((rth0_in->ip6r0_len) + 1) << 3); 362f95d4633SHajimu UMEMOTO rth0_out->ip6r0_segleft = segments; 363f95d4633SHajimu UMEMOTO 364f95d4633SHajimu UMEMOTO /* reverse the addresses */ 365f95d4633SHajimu UMEMOTO for (i = 0; i < segments / 2; i++) { 366f95d4633SHajimu UMEMOTO struct in6_addr addr_tmp, *addr1, *addr2; 367f95d4633SHajimu UMEMOTO 368f95d4633SHajimu UMEMOTO addr1 = (struct in6_addr *)(rth0_out + 1) + i; 369f95d4633SHajimu UMEMOTO addr2 = (struct in6_addr *)(rth0_out + 1) + 370f95d4633SHajimu UMEMOTO (segments - i - 1); 371f95d4633SHajimu UMEMOTO addr_tmp = *addr1; 372f95d4633SHajimu UMEMOTO *addr1 = *addr2; 373f95d4633SHajimu UMEMOTO *addr2 = addr_tmp; 374f95d4633SHajimu UMEMOTO } 375f95d4633SHajimu UMEMOTO 376f95d4633SHajimu UMEMOTO break; 377f95d4633SHajimu UMEMOTO default: 378f95d4633SHajimu UMEMOTO return (-1); /* type not supported */ 379f95d4633SHajimu UMEMOTO } 380f95d4633SHajimu UMEMOTO 381f95d4633SHajimu UMEMOTO return (0); 382f95d4633SHajimu UMEMOTO } 383f95d4633SHajimu UMEMOTO 384f95d4633SHajimu UMEMOTO int 385f95d4633SHajimu UMEMOTO inet6_rth_segments(const void *bp) 386f95d4633SHajimu UMEMOTO { 387f95d4633SHajimu UMEMOTO struct ip6_rthdr *rh = (struct ip6_rthdr *)bp; 388f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rh0; 389f95d4633SHajimu UMEMOTO int addrs; 390f95d4633SHajimu UMEMOTO 391f95d4633SHajimu UMEMOTO switch (rh->ip6r_type) { 392f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 393f95d4633SHajimu UMEMOTO rh0 = (struct ip6_rthdr0 *)bp; 394f95d4633SHajimu UMEMOTO 395f95d4633SHajimu UMEMOTO /* 396f95d4633SHajimu UMEMOTO * Validation for a type-0 routing header. 397f95d4633SHajimu UMEMOTO * Is this too strict? 398f95d4633SHajimu UMEMOTO */ 399f95d4633SHajimu UMEMOTO if ((rh0->ip6r0_len % 2) != 0 || 400f95d4633SHajimu UMEMOTO (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft) 401f95d4633SHajimu UMEMOTO return (-1); 402f95d4633SHajimu UMEMOTO 403f95d4633SHajimu UMEMOTO return (addrs); 404f95d4633SHajimu UMEMOTO default: 405f95d4633SHajimu UMEMOTO return (-1); /* unknown type */ 406f95d4633SHajimu UMEMOTO } 407f95d4633SHajimu UMEMOTO } 408f95d4633SHajimu UMEMOTO 409f95d4633SHajimu UMEMOTO struct in6_addr * 410f95d4633SHajimu UMEMOTO inet6_rth_getaddr(const void *bp, int idx) 411f95d4633SHajimu UMEMOTO { 412f95d4633SHajimu UMEMOTO struct ip6_rthdr *rh = (struct ip6_rthdr *)bp; 413f95d4633SHajimu UMEMOTO struct ip6_rthdr0 *rh0; 414d5cbe1abSHajimu UMEMOTO int addrs; 415f95d4633SHajimu UMEMOTO 416f95d4633SHajimu UMEMOTO switch (rh->ip6r_type) { 417f95d4633SHajimu UMEMOTO case IPV6_RTHDR_TYPE_0: 418f95d4633SHajimu UMEMOTO rh0 = (struct ip6_rthdr0 *)bp; 419f95d4633SHajimu UMEMOTO 420f95d4633SHajimu UMEMOTO /* 421f95d4633SHajimu UMEMOTO * Validation for a type-0 routing header. 422f95d4633SHajimu UMEMOTO * Is this too strict? 423f95d4633SHajimu UMEMOTO */ 424d5cbe1abSHajimu UMEMOTO if ((rh0->ip6r0_len % 2) != 0 || 425d5cbe1abSHajimu UMEMOTO (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft) 426f95d4633SHajimu UMEMOTO return (NULL); 427f95d4633SHajimu UMEMOTO 428f95d4633SHajimu UMEMOTO if (idx < 0 || addrs <= idx) 429f95d4633SHajimu UMEMOTO return (NULL); 430f95d4633SHajimu UMEMOTO 431f95d4633SHajimu UMEMOTO return (((struct in6_addr *)(rh0 + 1)) + idx); 432f95d4633SHajimu UMEMOTO default: 433f95d4633SHajimu UMEMOTO return (NULL); /* unknown type */ 434f95d4633SHajimu UMEMOTO break; 43505a244b4SYoshinobu Inoue } 43605a244b4SYoshinobu Inoue } 437