1 /* $KAME: rthdr.c,v 1.8 2001/08/20 02:32:40 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 * $FreeBSD: src/lib/libc/net/rthdr.c,v 1.2.2.1 2002/04/28 05:40:24 suz Exp $ 32 * $DragonFly: src/lib/libc/net/rthdr.c,v 1.5 2007/05/29 10:58:11 hasso Exp $ 33 */ 34 35 #include <sys/param.h> 36 #include <sys/types.h> 37 #include <sys/socket.h> 38 39 #include <netinet/in.h> 40 #include <netinet/ip6.h> 41 42 #include <string.h> 43 #include <stdio.h> 44 45 size_t 46 inet6_rthdr_space(int type, int seg) 47 { 48 switch(type) { 49 case IPV6_RTHDR_TYPE_0: 50 if (seg < 1 || seg > 23) 51 return(0); 52 return(CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) 53 + sizeof(struct ip6_rthdr0))); 54 default: 55 #ifdef DEBUG 56 fprintf(stderr, "inet6_rthdr_space: unknown type(%d)\n", type); 57 #endif 58 return(0); 59 } 60 } 61 62 struct cmsghdr * 63 inet6_rthdr_init(void *bp, int type) 64 { 65 struct cmsghdr *ch = (struct cmsghdr *)bp; 66 struct ip6_rthdr *rthdr; 67 68 rthdr = (struct ip6_rthdr *)CMSG_DATA(ch); 69 70 ch->cmsg_level = IPPROTO_IPV6; 71 ch->cmsg_type = IPV6_RTHDR; 72 73 switch(type) { 74 case IPV6_RTHDR_TYPE_0: 75 ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) - sizeof(struct in6_addr)); 76 bzero(rthdr, sizeof(struct ip6_rthdr0)); 77 rthdr->ip6r_type = IPV6_RTHDR_TYPE_0; 78 return(ch); 79 default: 80 #ifdef DEBUG 81 fprintf(stderr, "inet6_rthdr_init: unknown type(%d)\n", type); 82 #endif 83 return(NULL); 84 } 85 } 86 87 int 88 inet6_rthdr_add(struct cmsghdr *cmsg, const struct in6_addr *addr, u_int flags) 89 { 90 struct ip6_rthdr *rthdr; 91 92 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 93 94 switch(rthdr->ip6r_type) { 95 case IPV6_RTHDR_TYPE_0: 96 { 97 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 98 if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) { 99 #ifdef DEBUG 100 fprintf(stderr, "inet6_rthdr_add: unsupported flag(%d)\n", flags); 101 #endif 102 return(-1); 103 } 104 if (rt0->ip6r0_segleft == 23) { 105 #ifdef DEBUG 106 fprintf(stderr, "inet6_rthdr_add: segment overflow\n"); 107 #endif 108 return(-1); 109 } 110 if (flags == IPV6_RTHDR_STRICT) { 111 int c, b; 112 c = rt0->ip6r0_segleft / 8; 113 b = rt0->ip6r0_segleft % 8; 114 rt0->ip6r0_slmap[c] |= (1 << (7 - b)); 115 } 116 rt0->ip6r0_segleft++; 117 bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3), 118 sizeof(struct in6_addr)); 119 rt0->ip6r0_len += sizeof(struct in6_addr) >> 3; 120 cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3); 121 break; 122 } 123 default: 124 #ifdef DEBUG 125 fprintf(stderr, "inet6_rthdr_add: unknown type(%d)\n", 126 rthdr->ip6r_type); 127 #endif 128 return(-1); 129 } 130 131 return(0); 132 } 133 134 int 135 inet6_rthdr_lasthop(struct cmsghdr *cmsg, unsigned int flags) 136 { 137 struct ip6_rthdr *rthdr; 138 139 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 140 141 switch(rthdr->ip6r_type) { 142 case IPV6_RTHDR_TYPE_0: 143 { 144 struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; 145 if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) { 146 #ifdef DEBUG 147 fprintf(stderr, "inet6_rthdr_lasthop: unsupported flag(%d)\n", flags); 148 #endif 149 return(-1); 150 } 151 if (rt0->ip6r0_segleft > 23) { 152 #ifdef DEBUG 153 fprintf(stderr, "inet6_rthdr_add: segment overflow\n"); 154 #endif 155 return(-1); 156 } 157 if (flags == IPV6_RTHDR_STRICT) { 158 int c, b; 159 c = rt0->ip6r0_segleft / 8; 160 b = rt0->ip6r0_segleft % 8; 161 rt0->ip6r0_slmap[c] |= (1 << (7 - b)); 162 } 163 break; 164 } 165 default: 166 #ifdef DEBUG 167 fprintf(stderr, "inet6_rthdr_lasthop: unknown type(%d)\n", 168 rthdr->ip6r_type); 169 #endif 170 return(-1); 171 } 172 173 return(0); 174 } 175 176 #if 0 177 int 178 inet6_rthdr_reverse(const struct cmsghdr *in, struct cmsghdr *out) 179 { 180 #ifdef DEBUG 181 fprintf(stderr, "inet6_rthdr_reverse: not implemented yet\n"); 182 #endif 183 return -1; 184 } 185 #endif 186 187 int 188 inet6_rthdr_segments(const struct cmsghdr *cmsg) 189 { 190 struct ip6_rthdr *rthdr; 191 192 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 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(struct cmsghdr *cmsg, int idx) 221 { 222 struct ip6_rthdr *rthdr; 223 224 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 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 (idx <= 0 || naddr < idx) { 241 #ifdef DEBUG 242 fprintf(stderr, "inet6_rthdr_getaddr: invalid idx(%d)\n", idx); 243 #endif 244 return NULL; 245 } 246 return &rt0->ip6r0_addr[idx - 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(const struct cmsghdr *cmsg, int idx) 260 { 261 struct ip6_rthdr *rthdr; 262 263 rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); 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 (idx < 0 || naddr < idx) { 280 #ifdef DEBUG 281 fprintf(stderr, "inet6_rthdr_getflags: invalid idx(%d)\n", idx); 282 #endif 283 return -1; 284 } 285 if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 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 300 /* 301 * RFC3542 (2292bis) API 302 */ 303 304 socklen_t 305 inet6_rth_space(int type __unused, int segments __unused) 306 { 307 return (0); /* type not suppported */ 308 } 309 310 void * 311 inet6_rth_init(void *bp __unused, socklen_t bp_len __unused, int type __unused, 312 int segments __unused) 313 { 314 return (NULL); /* type not supported */ 315 } 316 317 int 318 inet6_rth_add(void *bp __unused, const struct in6_addr *addr __unused) 319 { 320 return (-1); /* type not supported */ 321 } 322 323 int 324 inet6_rth_reverse(const void *in __unused, void *out __unused) 325 { 326 return (-1); /* type not supported */ 327 } 328 329 int 330 inet6_rth_segments(const void *bp __unused) 331 { 332 return (-1); /* type not supported */ 333 } 334 335 struct in6_addr * 336 inet6_rth_getaddr(const void *bp __unused, int idx __unused) 337 { 338 return (NULL); /* type not supported */ 339 } 340