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