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