105a244b4SYoshinobu Inoue /* 205a244b4SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 305a244b4SYoshinobu Inoue * All rights reserved. 405a244b4SYoshinobu Inoue * 505a244b4SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 605a244b4SYoshinobu Inoue * modification, are permitted provided that the following conditions 705a244b4SYoshinobu Inoue * are met: 805a244b4SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 905a244b4SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1005a244b4SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1105a244b4SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1205a244b4SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1305a244b4SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1405a244b4SYoshinobu Inoue * may be used to endorse or promote products derived from this software 1505a244b4SYoshinobu Inoue * without specific prior written permission. 1605a244b4SYoshinobu Inoue * 1705a244b4SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1805a244b4SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1905a244b4SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2005a244b4SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2105a244b4SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2205a244b4SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2305a244b4SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2405a244b4SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2505a244b4SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2605a244b4SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2705a244b4SYoshinobu Inoue * SUCH DAMAGE. 2805a244b4SYoshinobu Inoue * 2905a244b4SYoshinobu Inoue * $FreeBSD$ 3005a244b4SYoshinobu Inoue */ 3105a244b4SYoshinobu Inoue 3205a244b4SYoshinobu Inoue #include <sys/param.h> 3305a244b4SYoshinobu Inoue #include <sys/types.h> 3405a244b4SYoshinobu Inoue #include <sys/socket.h> 3505a244b4SYoshinobu Inoue 3605a244b4SYoshinobu Inoue #include <netinet/in.h> 3705a244b4SYoshinobu Inoue #include <netinet/ip6.h> 3805a244b4SYoshinobu Inoue 3905a244b4SYoshinobu Inoue #include <string.h> 4005a244b4SYoshinobu Inoue #include <stdio.h> 4105a244b4SYoshinobu Inoue 4205a244b4SYoshinobu Inoue size_t 4305a244b4SYoshinobu Inoue inet6_rthdr_space(type, seg) 4405a244b4SYoshinobu Inoue int type, seg; 4505a244b4SYoshinobu Inoue { 4605a244b4SYoshinobu Inoue switch(type) { 4705a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 4805a244b4SYoshinobu Inoue if (seg < 1 || seg > 23) 4905a244b4SYoshinobu Inoue return(0); 5005a244b4SYoshinobu Inoue return(CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) 5105a244b4SYoshinobu Inoue + sizeof(struct ip6_rthdr0))); 5205a244b4SYoshinobu Inoue default: 5305a244b4SYoshinobu Inoue #ifdef DEBUG 5405a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_space: unknown type(%d)\n", type); 5505a244b4SYoshinobu Inoue #endif 5605a244b4SYoshinobu Inoue return(0); 5705a244b4SYoshinobu Inoue } 5805a244b4SYoshinobu Inoue } 5905a244b4SYoshinobu Inoue 6005a244b4SYoshinobu Inoue struct cmsghdr * 6105a244b4SYoshinobu Inoue inet6_rthdr_init(bp, type) 6205a244b4SYoshinobu Inoue void *bp; 6305a244b4SYoshinobu Inoue int type; 6405a244b4SYoshinobu Inoue { 658fb3f3f6SDavid E. O'Brien struct cmsghdr *ch = (struct cmsghdr *)bp; 668fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 677d0d8dc3SYoshinobu Inoue 687d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(ch); 6905a244b4SYoshinobu Inoue 7005a244b4SYoshinobu Inoue ch->cmsg_level = IPPROTO_IPV6; 7105a244b4SYoshinobu Inoue ch->cmsg_type = IPV6_RTHDR; 7205a244b4SYoshinobu Inoue 7305a244b4SYoshinobu Inoue switch(type) { 7405a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 7505a244b4SYoshinobu Inoue ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) - sizeof(struct in6_addr)); 7605a244b4SYoshinobu Inoue bzero(rthdr, sizeof(struct ip6_rthdr0)); 7705a244b4SYoshinobu Inoue rthdr->ip6r_type = IPV6_RTHDR_TYPE_0; 7805a244b4SYoshinobu Inoue return(ch); 7905a244b4SYoshinobu Inoue default: 8005a244b4SYoshinobu Inoue #ifdef DEBUG 8105a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_init: unknown type(%d)\n", type); 8205a244b4SYoshinobu Inoue #endif 8305a244b4SYoshinobu Inoue return(NULL); 8405a244b4SYoshinobu Inoue } 8505a244b4SYoshinobu Inoue } 8605a244b4SYoshinobu Inoue 8705a244b4SYoshinobu Inoue int 8805a244b4SYoshinobu Inoue inet6_rthdr_add(cmsg, addr, flags) 8905a244b4SYoshinobu Inoue struct cmsghdr *cmsg; 9005a244b4SYoshinobu Inoue const struct in6_addr *addr; 9105a244b4SYoshinobu Inoue u_int flags; 9205a244b4SYoshinobu Inoue { 938fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 947d0d8dc3SYoshinobu Inoue 957d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 9605a244b4SYoshinobu Inoue 9705a244b4SYoshinobu Inoue switch(rthdr->ip6r_type) { 9805a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 9905a244b4SYoshinobu Inoue { 10005a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 10105a244b4SYoshinobu Inoue if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) { 10205a244b4SYoshinobu Inoue #ifdef DEBUG 10305a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_add: unsupported flag(%d)\n", flags); 10405a244b4SYoshinobu Inoue #endif 10505a244b4SYoshinobu Inoue return(-1); 10605a244b4SYoshinobu Inoue } 10705a244b4SYoshinobu Inoue if (rt0->ip6r0_segleft == 23) { 10805a244b4SYoshinobu Inoue #ifdef DEBUG 10905a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_add: segment overflow\n"); 11005a244b4SYoshinobu Inoue #endif 11105a244b4SYoshinobu Inoue return(-1); 11205a244b4SYoshinobu Inoue } 11305a244b4SYoshinobu Inoue if (flags == IPV6_RTHDR_STRICT) { 11405a244b4SYoshinobu Inoue int c, b; 11505a244b4SYoshinobu Inoue c = rt0->ip6r0_segleft / 8; 11605a244b4SYoshinobu Inoue b = rt0->ip6r0_segleft % 8; 11705a244b4SYoshinobu Inoue rt0->ip6r0_slmap[c] |= (1 << (7 - b)); 11805a244b4SYoshinobu Inoue } 11905a244b4SYoshinobu Inoue rt0->ip6r0_segleft++; 12005a244b4SYoshinobu Inoue bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3), 12105a244b4SYoshinobu Inoue sizeof(struct in6_addr)); 12205a244b4SYoshinobu Inoue rt0->ip6r0_len += sizeof(struct in6_addr) >> 3; 12305a244b4SYoshinobu Inoue cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3); 12405a244b4SYoshinobu Inoue break; 12505a244b4SYoshinobu Inoue } 12605a244b4SYoshinobu Inoue default: 12705a244b4SYoshinobu Inoue #ifdef DEBUG 12805a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_add: unknown type(%d)\n", 12905a244b4SYoshinobu Inoue rthdr->ip6r_type); 13005a244b4SYoshinobu Inoue #endif 13105a244b4SYoshinobu Inoue return(-1); 13205a244b4SYoshinobu Inoue } 13305a244b4SYoshinobu Inoue 13405a244b4SYoshinobu Inoue return(0); 13505a244b4SYoshinobu Inoue } 13605a244b4SYoshinobu Inoue 13705a244b4SYoshinobu Inoue int 13805a244b4SYoshinobu Inoue inet6_rthdr_lasthop(cmsg, flags) 13905a244b4SYoshinobu Inoue struct cmsghdr *cmsg; 14005a244b4SYoshinobu Inoue 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; 15005a244b4SYoshinobu Inoue if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) { 15105a244b4SYoshinobu Inoue #ifdef DEBUG 15205a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_lasthop: unsupported flag(%d)\n", flags); 15305a244b4SYoshinobu Inoue #endif 15405a244b4SYoshinobu Inoue return(-1); 15505a244b4SYoshinobu Inoue } 15605a244b4SYoshinobu Inoue if (rt0->ip6r0_segleft > 23) { 15705a244b4SYoshinobu Inoue #ifdef DEBUG 15805a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_add: segment overflow\n"); 15905a244b4SYoshinobu Inoue #endif 16005a244b4SYoshinobu Inoue return(-1); 16105a244b4SYoshinobu Inoue } 16205a244b4SYoshinobu Inoue if (flags == IPV6_RTHDR_STRICT) { 16305a244b4SYoshinobu Inoue int c, b; 16405a244b4SYoshinobu Inoue c = rt0->ip6r0_segleft / 8; 16505a244b4SYoshinobu Inoue b = rt0->ip6r0_segleft % 8; 16605a244b4SYoshinobu Inoue rt0->ip6r0_slmap[c] |= (1 << (7 - b)); 16705a244b4SYoshinobu Inoue } 16805a244b4SYoshinobu Inoue break; 16905a244b4SYoshinobu Inoue } 17005a244b4SYoshinobu Inoue default: 17105a244b4SYoshinobu Inoue #ifdef DEBUG 17205a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_lasthop: unknown type(%d)\n", 17305a244b4SYoshinobu Inoue rthdr->ip6r_type); 17405a244b4SYoshinobu Inoue #endif 17505a244b4SYoshinobu Inoue return(-1); 17605a244b4SYoshinobu Inoue } 17705a244b4SYoshinobu Inoue 17805a244b4SYoshinobu Inoue return(0); 17905a244b4SYoshinobu Inoue } 18005a244b4SYoshinobu Inoue 18105a244b4SYoshinobu Inoue #if 0 18205a244b4SYoshinobu Inoue int 18305a244b4SYoshinobu Inoue inet6_rthdr_reverse(in, out) 18405a244b4SYoshinobu Inoue const struct cmsghdr *in; 18505a244b4SYoshinobu Inoue struct cmsghdr *out; 18605a244b4SYoshinobu Inoue { 18705a244b4SYoshinobu Inoue #ifdef DEBUG 18805a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_reverse: not implemented yet\n"); 18905a244b4SYoshinobu Inoue #endif 19005a244b4SYoshinobu Inoue return -1; 19105a244b4SYoshinobu Inoue } 19205a244b4SYoshinobu Inoue #endif 19305a244b4SYoshinobu Inoue 19405a244b4SYoshinobu Inoue int 19505a244b4SYoshinobu Inoue inet6_rthdr_segments(cmsg) 19605a244b4SYoshinobu Inoue const struct cmsghdr *cmsg; 19705a244b4SYoshinobu Inoue { 1988fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 1997d0d8dc3SYoshinobu Inoue 2007d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 20105a244b4SYoshinobu Inoue 20205a244b4SYoshinobu Inoue switch(rthdr->ip6r_type) { 20305a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 20405a244b4SYoshinobu Inoue { 20505a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 20605a244b4SYoshinobu Inoue 20705a244b4SYoshinobu Inoue if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) { 20805a244b4SYoshinobu Inoue #ifdef DEBUG 20905a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_segments: invalid size(%d)\n", 21005a244b4SYoshinobu Inoue rt0->ip6r0_len); 21105a244b4SYoshinobu Inoue #endif 21205a244b4SYoshinobu Inoue return -1; 21305a244b4SYoshinobu Inoue } 21405a244b4SYoshinobu Inoue 21505a244b4SYoshinobu Inoue return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 21605a244b4SYoshinobu Inoue } 21705a244b4SYoshinobu Inoue 21805a244b4SYoshinobu Inoue default: 21905a244b4SYoshinobu Inoue #ifdef DEBUG 22005a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_segments: unknown type(%d)\n", 22105a244b4SYoshinobu Inoue rthdr->ip6r_type); 22205a244b4SYoshinobu Inoue #endif 22305a244b4SYoshinobu Inoue return -1; 22405a244b4SYoshinobu Inoue } 22505a244b4SYoshinobu Inoue } 22605a244b4SYoshinobu Inoue 22705a244b4SYoshinobu Inoue struct in6_addr * 22805a244b4SYoshinobu Inoue inet6_rthdr_getaddr(cmsg, index) 22905a244b4SYoshinobu Inoue struct cmsghdr *cmsg; 23005a244b4SYoshinobu Inoue int index; 23105a244b4SYoshinobu Inoue { 2328fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 2337d0d8dc3SYoshinobu Inoue 2347d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 23505a244b4SYoshinobu Inoue 23605a244b4SYoshinobu Inoue switch(rthdr->ip6r_type) { 23705a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 23805a244b4SYoshinobu Inoue { 23905a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 24005a244b4SYoshinobu Inoue int naddr; 24105a244b4SYoshinobu Inoue 24205a244b4SYoshinobu Inoue if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) { 24305a244b4SYoshinobu Inoue #ifdef DEBUG 24405a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_getaddr: invalid size(%d)\n", 24505a244b4SYoshinobu Inoue rt0->ip6r0_len); 24605a244b4SYoshinobu Inoue #endif 24705a244b4SYoshinobu Inoue return NULL; 24805a244b4SYoshinobu Inoue } 24905a244b4SYoshinobu Inoue naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 25005a244b4SYoshinobu Inoue if (index <= 0 || naddr < index) { 25105a244b4SYoshinobu Inoue #ifdef DEBUG 25205a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_getaddr: invalid index(%d)\n", index); 25305a244b4SYoshinobu Inoue #endif 25405a244b4SYoshinobu Inoue return NULL; 25505a244b4SYoshinobu Inoue } 25605a244b4SYoshinobu Inoue return &rt0->ip6r0_addr[index - 1]; 25705a244b4SYoshinobu Inoue } 25805a244b4SYoshinobu Inoue 25905a244b4SYoshinobu Inoue default: 26005a244b4SYoshinobu Inoue #ifdef DEBUG 26105a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_getaddr: unknown type(%d)\n", 26205a244b4SYoshinobu Inoue rthdr->ip6r_type); 26305a244b4SYoshinobu Inoue #endif 26405a244b4SYoshinobu Inoue return NULL; 26505a244b4SYoshinobu Inoue } 26605a244b4SYoshinobu Inoue } 26705a244b4SYoshinobu Inoue 26805a244b4SYoshinobu Inoue int 26905a244b4SYoshinobu Inoue inet6_rthdr_getflags(cmsg, index) 27005a244b4SYoshinobu Inoue const struct cmsghdr *cmsg; 27105a244b4SYoshinobu Inoue int index; 27205a244b4SYoshinobu Inoue { 2738fb3f3f6SDavid E. O'Brien struct ip6_rthdr *rthdr; 2747d0d8dc3SYoshinobu Inoue 2757d0d8dc3SYoshinobu Inoue rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 27605a244b4SYoshinobu Inoue 27705a244b4SYoshinobu Inoue switch(rthdr->ip6r_type) { 27805a244b4SYoshinobu Inoue case IPV6_RTHDR_TYPE_0: 27905a244b4SYoshinobu Inoue { 28005a244b4SYoshinobu Inoue struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 28105a244b4SYoshinobu Inoue int naddr; 28205a244b4SYoshinobu Inoue 28305a244b4SYoshinobu Inoue if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) { 28405a244b4SYoshinobu Inoue #ifdef DEBUG 28505a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_getflags: invalid size(%d)\n", 28605a244b4SYoshinobu Inoue rt0->ip6r0_len); 28705a244b4SYoshinobu Inoue #endif 28805a244b4SYoshinobu Inoue return -1; 28905a244b4SYoshinobu Inoue } 29005a244b4SYoshinobu Inoue naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr); 29105a244b4SYoshinobu Inoue if (index < 0 || naddr < index) { 29205a244b4SYoshinobu Inoue #ifdef DEBUG 29305a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_getflags: invalid index(%d)\n", index); 29405a244b4SYoshinobu Inoue #endif 29505a244b4SYoshinobu Inoue return -1; 29605a244b4SYoshinobu Inoue } 29705a244b4SYoshinobu Inoue if (rt0->ip6r0_slmap[index / 8] & (0x80 >> (index % 8))) 29805a244b4SYoshinobu Inoue return IPV6_RTHDR_STRICT; 29905a244b4SYoshinobu Inoue else 30005a244b4SYoshinobu Inoue return IPV6_RTHDR_LOOSE; 30105a244b4SYoshinobu Inoue } 30205a244b4SYoshinobu Inoue 30305a244b4SYoshinobu Inoue default: 30405a244b4SYoshinobu Inoue #ifdef DEBUG 30505a244b4SYoshinobu Inoue fprintf(stderr, "inet6_rthdr_getflags: unknown type(%d)\n", 30605a244b4SYoshinobu Inoue rthdr->ip6r_type); 30705a244b4SYoshinobu Inoue #endif 30805a244b4SYoshinobu Inoue return -1; 30905a244b4SYoshinobu Inoue } 31005a244b4SYoshinobu Inoue } 311