Home | History | Annotate | Line # | Download | only in net
rthdr.c revision 1.8
      1 /*	$NetBSD: rthdr.c,v 1.8 2000/04/24 09:27:31 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 "namespace.h"
     33 #include <sys/param.h>
     34 #include <sys/types.h>
     35 #include <sys/socket.h>
     36 
     37 #include <netinet/in.h>
     38 #include <netinet/ip6.h>
     39 
     40 #include <assert.h>
     41 #include <string.h>
     42 #include <stdio.h>
     43 
     44 #ifdef __weak_alias
     45 __weak_alias(inet6_rthdr_add,_inet6_rthdr_add)
     46 __weak_alias(inet6_rthdr_getaddr,_inet6_rthdr_getaddr)
     47 __weak_alias(inet6_rthdr_getflags,_inet6_rthdr_getflags)
     48 __weak_alias(inet6_rthdr_init,_inet6_rthdr_init)
     49 __weak_alias(inet6_rthdr_lasthop,_inet6_rthdr_lasthop)
     50 __weak_alias(inet6_rthdr_segments,_inet6_rthdr_segments)
     51 __weak_alias(inet6_rthdr_space,_inet6_rthdr_space)
     52 #endif
     53 
     54 size_t
     55 inet6_rthdr_space(type, seg)
     56     int type, seg;
     57 {
     58     switch(type) {
     59      case IPV6_RTHDR_TYPE_0:
     60 	 if (seg < 1 || seg > 23)
     61 	     return(0);
     62 	 return(CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1)
     63 			   + sizeof(struct ip6_rthdr0)));
     64      default:
     65 #ifdef DEBUG
     66 	 fprintf(stderr, "inet6_rthdr_space: unknown type(%d)\n", type);
     67 #endif
     68 	 return(0);
     69     }
     70 }
     71 
     72 struct cmsghdr *
     73 inet6_rthdr_init(bp, type)
     74     void *bp;
     75     int type;
     76 {
     77     register struct cmsghdr *ch;
     78     register struct ip6_rthdr *rthdr;
     79 
     80     _DIAGASSERT(bp != NULL);
     81 
     82     ch = (struct cmsghdr *)bp;
     83     rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
     84 
     85     ch->cmsg_level = IPPROTO_IPV6;
     86     ch->cmsg_type = IPV6_RTHDR;
     87 
     88     switch(type) {
     89      case IPV6_RTHDR_TYPE_0:
     90 	 ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) - sizeof(struct in6_addr));
     91 	 (void)memset(rthdr, 0, sizeof(struct ip6_rthdr0));
     92 	 rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
     93 	 return(ch);
     94      default:
     95 #ifdef DEBUG
     96 	 fprintf(stderr, "inet6_rthdr_init: unknown type(%d)\n", type);
     97 #endif
     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     register struct ip6_rthdr *rthdr;
    109 
    110     _DIAGASSERT(cmsg != NULL);
    111     _DIAGASSERT(addr != NULL);
    112 
    113     rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
    114 
    115     switch(rthdr->ip6r_type) {
    116      case IPV6_RTHDR_TYPE_0:
    117      {
    118 	 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
    119 	 if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
    120 #ifdef DEBUG
    121 	     fprintf(stderr, "inet6_rthdr_add: unsupported flag(%d)\n", flags);
    122 #endif
    123 	     return(-1);
    124 	 }
    125 	 if (rt0->ip6r0_segleft == 23) {
    126 #ifdef DEBUG
    127 	     fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
    128 #endif
    129 	     return(-1);
    130 	 }
    131 	 if (flags == IPV6_RTHDR_STRICT) {
    132 	     int c, b;
    133 	     c = rt0->ip6r0_segleft / 8;
    134 	     b = rt0->ip6r0_segleft % 8;
    135 	     rt0->ip6r0_slmap[c] |= (1 << (7 - b));
    136 	 }
    137 	 rt0->ip6r0_segleft++;
    138 	 (void)memcpy((caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3), addr,
    139 	       sizeof(struct in6_addr));
    140 	 rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
    141 	 cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
    142 	 break;
    143      }
    144      default:
    145 #ifdef DEBUG
    146 	 fprintf(stderr, "inet6_rthdr_add: unknown type(%d)\n",
    147 		 rthdr->ip6r_type);
    148 #endif
    149 	 return(-1);
    150     }
    151 
    152     return(0);
    153 }
    154 
    155 int
    156 inet6_rthdr_lasthop(cmsg, flags)
    157     struct cmsghdr *cmsg;
    158     unsigned int flags;
    159 {
    160     register struct ip6_rthdr *rthdr;
    161 
    162     _DIAGASSERT(cmsg != NULL);
    163 
    164     rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
    165 
    166     switch(rthdr->ip6r_type) {
    167      case IPV6_RTHDR_TYPE_0:
    168      {
    169 	 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
    170 	 if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
    171 #ifdef DEBUG
    172 	     fprintf(stderr, "inet6_rthdr_lasthop: unsupported flag(%d)\n", flags);
    173 #endif
    174 	     return(-1);
    175 	 }
    176 	 if (rt0->ip6r0_segleft > 23) {
    177 #ifdef DEBUG
    178 	     fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
    179 #endif
    180 	     return(-1);
    181 	 }
    182 	 if (flags == IPV6_RTHDR_STRICT) {
    183 	     int c, b;
    184 	     c = rt0->ip6r0_segleft / 8;
    185 	     b = rt0->ip6r0_segleft % 8;
    186 	     rt0->ip6r0_slmap[c] |= (1 << (7 - b));
    187 	 }
    188 	 break;
    189      }
    190      default:
    191 #ifdef DEBUG
    192 	 fprintf(stderr, "inet6_rthdr_lasthop: unknown type(%d)\n",
    193 		 rthdr->ip6r_type);
    194 #endif
    195 	 return(-1);
    196     }
    197 
    198     return(0);
    199 }
    200 
    201 #if 0
    202 int
    203 inet6_rthdr_reverse(in, out)
    204     const struct cmsghdr *in;
    205     struct cmsghdr *out;
    206 {
    207 #ifdef DEBUG
    208     fprintf(stderr, "inet6_rthdr_reverse: not implemented yet\n");
    209 #endif
    210     return -1;
    211 }
    212 #endif
    213 
    214 int
    215 inet6_rthdr_segments(cmsg)
    216     const struct cmsghdr *cmsg;
    217 {
    218     const register struct ip6_rthdr *rthdr;
    219 
    220     _DIAGASSERT(cmsg != NULL);
    221 
    222     rthdr = (const struct ip6_rthdr *)CMSG_DATA(cmsg);
    223 
    224     switch(rthdr->ip6r_type) {
    225     case IPV6_RTHDR_TYPE_0:
    226       {
    227 	const struct ip6_rthdr0 *rt0 = (const struct ip6_rthdr0 *)rthdr;
    228 
    229 	if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
    230 #ifdef DEBUG
    231 	    fprintf(stderr, "inet6_rthdr_segments: invalid size(%d)\n",
    232 		rt0->ip6r0_len);
    233 #endif
    234 	    return -1;
    235 	}
    236 
    237 	return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
    238       }
    239 
    240     default:
    241 #ifdef DEBUG
    242 	fprintf(stderr, "inet6_rthdr_segments: unknown type(%d)\n",
    243 	    rthdr->ip6r_type);
    244 #endif
    245 	return -1;
    246     }
    247 }
    248 
    249 struct in6_addr *
    250 inet6_rthdr_getaddr(cmsg, index)
    251     struct cmsghdr *cmsg;
    252     int index;
    253 {
    254     register struct ip6_rthdr *rthdr;
    255 
    256     _DIAGASSERT(cmsg != NULL);
    257 
    258     rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
    259 
    260     switch(rthdr->ip6r_type) {
    261     case IPV6_RTHDR_TYPE_0:
    262       {
    263 	struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
    264 	int naddr;
    265 
    266 	if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
    267 #ifdef DEBUG
    268 	    fprintf(stderr, "inet6_rthdr_getaddr: invalid size(%d)\n",
    269 		rt0->ip6r0_len);
    270 #endif
    271 	    return NULL;
    272 	}
    273 	naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
    274 	if (index <= 0 || naddr < index) {
    275 #ifdef DEBUG
    276 	    fprintf(stderr, "inet6_rthdr_getaddr: invalid index(%d)\n", index);
    277 #endif
    278 	    return NULL;
    279 	}
    280 	return &rt0->ip6r0_addr[index - 1];
    281       }
    282 
    283     default:
    284 #ifdef DEBUG
    285 	fprintf(stderr, "inet6_rthdr_getaddr: unknown type(%d)\n",
    286 	    rthdr->ip6r_type);
    287 #endif
    288 	return NULL;
    289     }
    290 }
    291 
    292 int
    293 inet6_rthdr_getflags(cmsg, index)
    294     const struct cmsghdr *cmsg;
    295     int index;
    296 {
    297     const register struct ip6_rthdr *rthdr;
    298 
    299     _DIAGASSERT(cmsg != NULL);
    300 
    301     rthdr = (const struct ip6_rthdr *)CMSG_DATA(cmsg);
    302 
    303     switch(rthdr->ip6r_type) {
    304     case IPV6_RTHDR_TYPE_0:
    305       {
    306 	const struct ip6_rthdr0 *rt0 = (const struct ip6_rthdr0 *)rthdr;
    307 	int naddr;
    308 
    309 	if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
    310 #ifdef DEBUG
    311 	    fprintf(stderr, "inet6_rthdr_getflags: invalid size(%d)\n",
    312 		rt0->ip6r0_len);
    313 #endif
    314 	    return -1;
    315 	}
    316 	naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
    317 	if (index < 0 || naddr < index) {
    318 #ifdef DEBUG
    319 	    fprintf(stderr, "inet6_rthdr_getflags: invalid index(%d)\n", index);
    320 #endif
    321 	    return -1;
    322 	}
    323 	if (rt0->ip6r0_slmap[index / 8] & (0x80 >> (index % 8)))
    324 	    return IPV6_RTHDR_STRICT;
    325 	else
    326 	    return IPV6_RTHDR_LOOSE;
    327       }
    328 
    329     default:
    330 #ifdef DEBUG
    331 	fprintf(stderr, "inet6_rthdr_getflags: unknown type(%d)\n",
    332 	    rthdr->ip6r_type);
    333 #endif
    334 	return -1;
    335     }
    336 }
    337