summaryrefslogtreecommitdiff
path: root/lib/libc/net/rthdr.c
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>1999-12-11 08:09:12 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>1999-12-11 08:09:12 +0000
commit819a282f8ad2a473c702d4d0cba73bc4f8fe19ad (patch)
tree1da913c54fd5e79ddf17f2b962c884b184953898 /lib/libc/net/rthdr.c
parentd3dc19a11444547994a5b725fcab6019e4624c40 (diff)
add inet6_option_* and inet6_rthdr_*.
increase shlib minor.
Diffstat (limited to 'lib/libc/net/rthdr.c')
-rw-r--r--lib/libc/net/rthdr.c298
1 files changed, 298 insertions, 0 deletions
diff --git a/lib/libc/net/rthdr.c b/lib/libc/net/rthdr.c
new file mode 100644
index 00000000000..2dff59668eb
--- /dev/null
+++ b/lib/libc/net/rthdr.c
@@ -0,0 +1,298 @@
+/* $OpenBSD: rthdr.c,v 1.1 1999/12/11 08:09:11 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+#include <string.h>
+#include <stdio.h>
+
+size_t
+inet6_rthdr_space(type, seg)
+ int type, seg;
+{
+ switch(type) {
+ case IPV6_RTHDR_TYPE_0:
+ if (seg < 1 || seg > 23)
+ return(0);
+ return(CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1)
+ + sizeof(struct ip6_rthdr0)));
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_space: unknown type(%d)\n", type);
+#endif
+ return(0);
+ }
+}
+
+struct cmsghdr *
+inet6_rthdr_init(bp, type)
+ void *bp;
+ int type;
+{
+ register struct cmsghdr *ch = (struct cmsghdr *)bp;
+ register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(ch + 1);
+
+ ch->cmsg_level = IPPROTO_IPV6;
+ ch->cmsg_type = IPV6_RTHDR;
+
+ switch(type) {
+ case IPV6_RTHDR_TYPE_0:
+ ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) - sizeof(struct in6_addr));
+ bzero(rthdr, sizeof(struct ip6_rthdr0));
+ rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
+ return(ch);
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_init: unknown type(%d)\n", type);
+#endif
+ return(NULL);
+ }
+}
+
+int
+inet6_rthdr_add(cmsg, addr, flags)
+ struct cmsghdr *cmsg;
+ const struct in6_addr *addr;
+ u_int flags;
+{
+ register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(cmsg + 1);
+
+ switch(rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_add: unsupported flag(%d)\n", flags);
+#endif
+ return(-1);
+ }
+ if (rt0->ip6r0_segleft == 23) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
+#endif
+ return(-1);
+ }
+ if (flags == IPV6_RTHDR_STRICT) {
+ int c, b;
+ c = rt0->ip6r0_segleft / 8;
+ b = rt0->ip6r0_segleft % 8;
+ rt0->ip6r0_slmap[c] |= (1 << (7 - b));
+ }
+ rt0->ip6r0_segleft++;
+ bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3),
+ sizeof(struct in6_addr));
+ rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
+ cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
+ break;
+ }
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_add: unknown type(%d)\n",
+ rthdr->ip6r_type);
+#endif
+ return(-1);
+ }
+
+ return(0);
+}
+
+int
+inet6_rthdr_lasthop(cmsg, flags)
+ struct cmsghdr *cmsg;
+ unsigned int flags;
+{
+ register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(cmsg + 1);
+
+ switch(rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_lasthop: unsupported flag(%d)\n", flags);
+#endif
+ return(-1);
+ }
+ if (rt0->ip6r0_segleft > 23) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
+#endif
+ return(-1);
+ }
+ if (flags == IPV6_RTHDR_STRICT) {
+ int c, b;
+ c = rt0->ip6r0_segleft / 8;
+ b = rt0->ip6r0_segleft % 8;
+ rt0->ip6r0_slmap[c] |= (1 << (7 - b));
+ }
+ break;
+ }
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_lasthop: unknown type(%d)\n",
+ rthdr->ip6r_type);
+#endif
+ return(-1);
+ }
+
+ return(0);
+}
+
+#if 0
+int
+inet6_rthdr_reverse(in, out)
+ const struct cmsghdr *in;
+ struct cmsghdr *out;
+{
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_reverse: not implemented yet\n");
+#endif
+ return -1;
+}
+#endif
+
+int
+inet6_rthdr_segments(cmsg)
+ const struct cmsghdr *cmsg;
+{
+ register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(cmsg + 1);
+
+ switch(rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_segments: invalid size(%d)\n",
+ rt0->ip6r0_len);
+#endif
+ return -1;
+ }
+
+ return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
+ }
+
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_segments: unknown type(%d)\n",
+ rthdr->ip6r_type);
+#endif
+ return -1;
+ }
+}
+
+struct in6_addr *
+inet6_rthdr_getaddr(cmsg, index)
+ struct cmsghdr *cmsg;
+ int index;
+{
+ register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(cmsg + 1);
+
+ switch(rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ int naddr;
+
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getaddr: invalid size(%d)\n",
+ rt0->ip6r0_len);
+#endif
+ return NULL;
+ }
+ naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
+ if (index <= 0 || naddr < index) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getaddr: invalid index(%d)\n", index);
+#endif
+ return NULL;
+ }
+ return &rt0->ip6r0_addr[index - 1];
+ }
+
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getaddr: unknown type(%d)\n",
+ rthdr->ip6r_type);
+#endif
+ return NULL;
+ }
+}
+
+int
+inet6_rthdr_getflags(cmsg, index)
+ const struct cmsghdr *cmsg;
+ int index;
+{
+ register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(cmsg + 1);
+
+ switch(rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ int naddr;
+
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getflags: invalid size(%d)\n",
+ rt0->ip6r0_len);
+#endif
+ return -1;
+ }
+ naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
+ if (index < 0 || naddr < index) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getflags: invalid index(%d)\n", index);
+#endif
+ return -1;
+ }
+ if (rt0->ip6r0_slmap[index / 8] & (0x80 >> (index % 8)))
+ return IPV6_RTHDR_STRICT;
+ else
+ return IPV6_RTHDR_LOOSE;
+ }
+
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getflags: unknown type(%d)\n",
+ rthdr->ip6r_type);
+#endif
+ return -1;
+ }
+}