Home | History | Annotate | Line # | Download | only in net
rthdr.c revision 1.13
      1 /*	$NetBSD: rthdr.c,v 1.13 2003/06/06 06:43:18 itojun Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the project nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #if defined(LIBC_SCCS) && !defined(lint)
     34 __RCSID("$NetBSD: rthdr.c,v 1.13 2003/06/06 06:43:18 itojun Exp $");
     35 #endif /* LIBC_SCCS and not lint */
     36 
     37 #include "namespace.h"
     38 #include <sys/param.h>
     39 #include <sys/types.h>
     40 #include <sys/socket.h>
     41 
     42 #include <netinet/in.h>
     43 #include <netinet/ip6.h>
     44 
     45 #include <assert.h>
     46 #include <string.h>
     47 #include <stdio.h>
     48 
     49 #ifdef __weak_alias
     50 __weak_alias(inet6_rthdr_add,_inet6_rthdr_add)
     51 __weak_alias(inet6_rthdr_getaddr,_inet6_rthdr_getaddr)
     52 __weak_alias(inet6_rthdr_getflags,_inet6_rthdr_getflags)
     53 __weak_alias(inet6_rthdr_init,_inet6_rthdr_init)
     54 __weak_alias(inet6_rthdr_lasthop,_inet6_rthdr_lasthop)
     55 __weak_alias(inet6_rthdr_segments,_inet6_rthdr_segments)
     56 __weak_alias(inet6_rthdr_space,_inet6_rthdr_space)
     57 #endif
     58 
     59 size_t
     60 inet6_rthdr_space(type, seg)
     61 	int type, seg;
     62 {
     63 	switch (type) {
     64 	case IPV6_RTHDR_TYPE_0:
     65 		if (seg < 1 || seg > 23)
     66 			return (0);
     67 		return (CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) +
     68 		    sizeof(struct ip6_rthdr0)));
     69 	default:
     70 		return (0);
     71 	}
     72 }
     73 
     74 struct cmsghdr *
     75 inet6_rthdr_init(bp, type)
     76 	void *bp;
     77 	int type;
     78 {
     79 	struct cmsghdr *ch;
     80 	struct ip6_rthdr *rthdr;
     81 
     82 	_DIAGASSERT(bp != NULL);
     83 
     84 	ch = (struct cmsghdr *)bp;
     85 	rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(ch);
     86 
     87 	ch->cmsg_level = IPPROTO_IPV6;
     88 	ch->cmsg_type = IPV6_RTHDR;
     89 
     90 	switch (type) {
     91 	case IPV6_RTHDR_TYPE_0:
     92 		ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) -
     93 		    sizeof(struct in6_addr));
     94 		(void)memset(rthdr, 0, sizeof(struct ip6_rthdr0));
     95 		rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
     96 		return (ch);
     97 	default:
     98 		return (NULL);
     99 	}
    100 }
    101 
    102 int
    103 inet6_rthdr_add(cmsg, addr, flags)
    104 	struct cmsghdr *cmsg;
    105 	const struct in6_addr *addr;
    106 	u_int flags;
    107 {
    108 	struct ip6_rthdr *rthdr;
    109 
    110 	_DIAGASSERT(cmsg != NULL);
    111 	_DIAGASSERT(addr != NULL);
    112 
    113 	rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
    114 
    115 	switch (rthdr->ip6r_type) {
    116 	case IPV6_RTHDR_TYPE_0:
    117 	{
    118 		struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
    119 		if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
    120 			return (-1);
    121 		if (rt0->ip6r0_segleft == 23)
    122 			return (-1);
    123 		if (flags == IPV6_RTHDR_STRICT) {
    124 			int c, b;
    125 			c = rt0->ip6r0_segleft / 8;
    126 			b = rt0->ip6r0_segleft % 8;
    127 			rt0->ip6r0_slmap[c] |= (1 << (7 - b));
    128 		}
    129 		rt0->ip6r0_segleft++;
    130 		(void)memcpy(((caddr_t)(void *)rt0) +
    131 		    ((rt0->ip6r0_len + 1) << 3), addr, sizeof(struct in6_addr));
    132 		rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
    133 		cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
    134 		break;
    135 	}
    136 	default:
    137 		return (-1);
    138 	}
    139 
    140 	return (0);
    141 }
    142 
    143 int
    144 inet6_rthdr_lasthop(cmsg, flags)
    145 	struct cmsghdr *cmsg;
    146 	unsigned int flags;
    147 {
    148 	struct ip6_rthdr *rthdr;
    149 
    150 	_DIAGASSERT(cmsg != NULL);
    151 
    152 	rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
    153 
    154 	switch (rthdr->ip6r_type) {
    155 	case IPV6_RTHDR_TYPE_0:
    156 	{
    157 		struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
    158 		if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
    159 			return (-1);
    160 		if (rt0->ip6r0_segleft > 23)
    161 			return (-1);
    162 		if (flags == IPV6_RTHDR_STRICT) {
    163 			int c, b;
    164 			c = rt0->ip6r0_segleft / 8;
    165 			b = rt0->ip6r0_segleft % 8;
    166 			rt0->ip6r0_slmap[c] |= (1 << (7 - b));
    167 		}
    168 		break;
    169 	}
    170 	default:
    171 		return (-1);
    172 	}
    173 
    174 	return (0);
    175 }
    176 
    177 #if 0
    178 int
    179 inet6_rthdr_reverse(in, out)
    180 	const struct cmsghdr *in;
    181 	struct cmsghdr *out;
    182 {
    183 
    184 	return (-1);
    185 }
    186 #endif
    187 
    188 int
    189 inet6_rthdr_segments(cmsg)
    190 	const struct cmsghdr *cmsg;
    191 {
    192 	const struct ip6_rthdr *rthdr;
    193 
    194 	_DIAGASSERT(cmsg != NULL);
    195 
    196 	/*LINTED const castaway*/
    197 	rthdr = (const struct ip6_rthdr *)(const void *)CMSG_DATA(cmsg);
    198 
    199 	switch (rthdr->ip6r_type) {
    200 	case IPV6_RTHDR_TYPE_0:
    201 	{
    202 		const struct ip6_rthdr0 *rt0 =
    203 		(const struct ip6_rthdr0 *)(const void *)rthdr;
    204 
    205 		if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
    206 			return (-1);
    207 
    208 		return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
    209 	}
    210 
    211 	default:
    212 		return (-1);
    213 	}
    214 }
    215 
    216 struct in6_addr *
    217 inet6_rthdr_getaddr(cmsg, idx)
    218 	struct cmsghdr *cmsg;
    219 	int idx;
    220 {
    221 	struct ip6_rthdr *rthdr;
    222 
    223 	_DIAGASSERT(cmsg != NULL);
    224 
    225 	rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
    226 
    227 	switch (rthdr->ip6r_type) {
    228 	case IPV6_RTHDR_TYPE_0:
    229 	{
    230 		struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
    231 		int naddr;
    232 
    233 		if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
    234 			return NULL;
    235 		naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
    236 		if (idx <= 0 || naddr < idx)
    237 			return NULL;
    238 		return &rt0->ip6r0_addr[idx - 1];
    239 	}
    240 
    241 	default:
    242 		return NULL;
    243 	}
    244 }
    245 
    246 int
    247 inet6_rthdr_getflags(cmsg, idx)
    248 	const struct cmsghdr *cmsg;
    249 	int idx;
    250 {
    251 	const struct ip6_rthdr *rthdr;
    252 
    253 	_DIAGASSERT(cmsg != NULL);
    254 
    255 	/*LINTED const castaway*/
    256 	rthdr = (const struct ip6_rthdr *)(const void *)CMSG_DATA(cmsg);
    257 
    258 	switch (rthdr->ip6r_type) {
    259 	case IPV6_RTHDR_TYPE_0:
    260 	{
    261 		const struct ip6_rthdr0 *rt0 = (const struct ip6_rthdr0 *)
    262 		(const void *)rthdr;
    263 		int naddr;
    264 
    265 		if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
    266 			return (-1);
    267 		naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
    268 		if (idx < 0 || naddr < idx)
    269 			return (-1);
    270 		if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8)))
    271 			return IPV6_RTHDR_STRICT;
    272 		else
    273 			return IPV6_RTHDR_LOOSE;
    274 	}
    275 
    276 	default:
    277 		return (-1);
    278 	}
    279 }
    280