aboutsummaryrefslogtreecommitdiff
path: root/lib/libc/net/rthdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/net/rthdr.c')
-rw-r--r--lib/libc/net/rthdr.c532
1 files changed, 331 insertions, 201 deletions
diff --git a/lib/libc/net/rthdr.c b/lib/libc/net/rthdr.c
index abfe34a93ad8d..d7b0077f606e1 100644
--- a/lib/libc/net/rthdr.c
+++ b/lib/libc/net/rthdr.c
@@ -1,4 +1,4 @@
-/* $KAME: rthdr.c,v 1.8 2001/08/20 02:32:40 itojun Exp $ */
+/* $KAME: rthdr.c,v 1.19 2003/06/06 10:48:51 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -42,272 +42,402 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <stdio.h>
+/*
+ * RFC2292 API
+ */
+
size_t
inet6_rthdr_space(type, seg)
- int 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);
+ switch (type) {
+ case IPV6_RTHDR_TYPE_0:
+ if (seg < 1 || seg > 23)
+ return (0);
+#ifdef COMPAT_RFC2292
+ return (CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) +
+ sizeof(struct ip6_rthdr0)));
+#else
+ return (CMSG_SPACE(sizeof(struct in6_addr) * seg +
+ sizeof(struct ip6_rthdr0)));
#endif
- return(0);
- }
+ default:
+ return (0);
+ }
}
struct cmsghdr *
inet6_rthdr_init(bp, type)
- void *bp;
- int type;
+ void *bp;
+ int type;
{
- struct cmsghdr *ch = (struct cmsghdr *)bp;
- struct ip6_rthdr *rthdr;
+ struct cmsghdr *ch = (struct cmsghdr *)bp;
+ struct ip6_rthdr *rthdr;
- rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
- ch->cmsg_level = IPPROTO_IPV6;
- ch->cmsg_type = IPV6_RTHDR;
+ 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);
+ switch (type) {
+ case IPV6_RTHDR_TYPE_0:
+#ifdef COMPAT_RFC2292
+ ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) -
+ sizeof(struct in6_addr));
+#else
+ ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0));
#endif
- return(NULL);
- }
+
+ bzero(rthdr, sizeof(struct ip6_rthdr0));
+ rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
+ return (ch);
+ default:
+ return (NULL);
+ }
}
+/* ARGSUSED */
int
inet6_rthdr_add(cmsg, addr, flags)
- struct cmsghdr *cmsg;
- const struct in6_addr *addr;
- u_int flags;
+ struct cmsghdr *cmsg;
+ const struct in6_addr *addr;
+ u_int flags;
{
- struct ip6_rthdr *rthdr;
+ struct ip6_rthdr *rthdr;
- rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
- 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);
+ 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)
+ return (-1);
+ if (rt0->ip6r0_segleft == 23)
+ return (-1);
+
+#ifdef COMPAT_RFC1883 /* XXX */
+ 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));
+ }
+#else
+ if (flags != IPV6_RTHDR_LOOSE)
+ return (-1);
#endif
- return(-1);
- }
+ 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:
+ return (-1);
+ }
- return(0);
+ return (0);
}
+/* ARGSUSED */
int
inet6_rthdr_lasthop(cmsg, flags)
- struct cmsghdr *cmsg;
- unsigned int flags;
+ struct cmsghdr *cmsg;
+ unsigned int flags;
{
- struct ip6_rthdr *rthdr;
+ struct ip6_rthdr *rthdr;
- rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
- 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);
- }
+ switch (rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+#ifdef COMPAT_RFC1883 /* XXX */
+ if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
+ return (-1);
+#endif /* COMPAT_RFC1883 */
+ if (rt0->ip6r0_segleft > 23)
+ return (-1);
+#ifdef COMPAT_RFC1883 /* XXX */
+ 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));
+ }
+#else
+ if (flags != IPV6_RTHDR_LOOSE)
+ return (-1);
+#endif /* COMPAT_RFC1883 */
+ break;
+ }
+ default:
+ return (-1);
+ }
- return(0);
+ return (0);
}
#if 0
int
inet6_rthdr_reverse(in, out)
- const struct cmsghdr *in;
- struct cmsghdr *out;
+ const struct cmsghdr *in;
+ struct cmsghdr *out;
{
-#ifdef DEBUG
- fprintf(stderr, "inet6_rthdr_reverse: not implemented yet\n");
-#endif
- return -1;
+
+ return (-1);
}
#endif
int
inet6_rthdr_segments(cmsg)
- const struct cmsghdr *cmsg;
+ const struct cmsghdr *cmsg;
{
- struct ip6_rthdr *rthdr;
+ struct ip6_rthdr *rthdr;
- rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
- switch(rthdr->ip6r_type) {
- case IPV6_RTHDR_TYPE_0:
- {
- struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ 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;
- }
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
+ return (-1);
- return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
- }
+ 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;
- }
+ default:
+ return (-1);
+ }
}
struct in6_addr *
inet6_rthdr_getaddr(cmsg, idx)
- struct cmsghdr *cmsg;
- int idx;
+ struct cmsghdr *cmsg;
+ int idx;
{
- struct ip6_rthdr *rthdr;
+ struct ip6_rthdr *rthdr;
- rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
- switch(rthdr->ip6r_type) {
- case IPV6_RTHDR_TYPE_0:
- {
- struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
- int naddr;
+ 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 (idx <= 0 || naddr < idx) {
-#ifdef DEBUG
- fprintf(stderr, "inet6_rthdr_getaddr: invalid idx(%d)\n", idx);
-#endif
- return NULL;
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
+ return NULL;
+ naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
+ if (idx <= 0 || naddr < idx)
+ return NULL;
+#ifdef COMPAT_RFC2292
+ return (((struct in6_addr *)(rt0 + 1)) + idx - 1);
+#else
+ return (((struct in6_addr *)(rt0 + 1)) + idx);
+#endif
}
- return &rt0->ip6r0_addr[idx - 1];
- }
- default:
-#ifdef DEBUG
- fprintf(stderr, "inet6_rthdr_getaddr: unknown type(%d)\n",
- rthdr->ip6r_type);
-#endif
- return NULL;
- }
+ default:
+ return NULL;
+ }
}
int
inet6_rthdr_getflags(cmsg, idx)
- const struct cmsghdr *cmsg;
- int idx;
+ const struct cmsghdr *cmsg;
+ int idx;
{
- struct ip6_rthdr *rthdr;
+ struct ip6_rthdr *rthdr;
- rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
- switch(rthdr->ip6r_type) {
- case IPV6_RTHDR_TYPE_0:
- {
- struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
- int naddr;
+ 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;
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
+ return (-1);
+ naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
+ if (idx < 0 || naddr < idx)
+ return (-1);
+#ifdef COMPAT_RFC1883 /* XXX */
+ if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8)))
+ return IPV6_RTHDR_STRICT;
+ else
+ return IPV6_RTHDR_LOOSE;
+#else
+ return IPV6_RTHDR_LOOSE;
+#endif /* COMPAT_RFC1883 */
}
- naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
- if (idx < 0 || naddr < idx) {
-#ifdef DEBUG
- fprintf(stderr, "inet6_rthdr_getflags: invalid idx(%d)\n", idx);
-#endif
- return -1;
+
+ default:
+ return (-1);
}
- if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 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;
- }
+/*
+ * RFC3542 (2292bis) API
+ */
+
+socklen_t
+inet6_rth_space(int type, int segments)
+{
+ switch (type) {
+ case IPV6_RTHDR_TYPE_0:
+ return (((segments * 2) + 1) << 3);
+ default:
+ return (0); /* type not suppported */
+ }
+}
+
+void *
+inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
+{
+ struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
+ struct ip6_rthdr0 *rth0;
+
+ switch (type) {
+ case IPV6_RTHDR_TYPE_0:
+ /* length validation */
+ if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments))
+ return (NULL);
+
+ memset(bp, 0, bp_len);
+ rth0 = (struct ip6_rthdr0 *)rth;
+ rth0->ip6r0_len = segments * 2;
+ rth0->ip6r0_type = IPV6_RTHDR_TYPE_0;
+ rth0->ip6r0_segleft = 0;
+ rth0->ip6r0_reserved = 0;
+ break;
+ default:
+ return (NULL); /* type not supported */
+ }
+
+ return (bp);
+}
+
+int
+inet6_rth_add(void *bp, const struct in6_addr *addr)
+{
+ struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
+ struct ip6_rthdr0 *rth0;
+ struct in6_addr *nextaddr;
+
+ switch (rth->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ rth0 = (struct ip6_rthdr0 *)rth;
+ nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft;
+ *nextaddr = *addr;
+ rth0->ip6r0_segleft++;
+ break;
+ default:
+ return (-1); /* type not supported */
+ }
+
+ return (0);
+}
+
+int
+inet6_rth_reverse(const void *in, void *out)
+{
+ struct ip6_rthdr *rth_in = (struct ip6_rthdr *)in;
+ struct ip6_rthdr0 *rth0_in, *rth0_out;
+ int i, segments;
+
+ switch (rth_in->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ rth0_in = (struct ip6_rthdr0 *)in;
+ rth0_out = (struct ip6_rthdr0 *)out;
+
+ /* parameter validation XXX too paranoid? */
+ if (rth0_in->ip6r0_len % 2)
+ return (-1);
+ segments = rth0_in->ip6r0_len / 2;
+
+ /* we can't use memcpy here, since in and out may overlap */
+ memmove((void *)rth0_out, (void *)rth0_in,
+ ((rth0_in->ip6r0_len) + 1) << 3);
+ rth0_out->ip6r0_segleft = segments;
+
+ /* reverse the addresses */
+ for (i = 0; i < segments / 2; i++) {
+ struct in6_addr addr_tmp, *addr1, *addr2;
+
+ addr1 = (struct in6_addr *)(rth0_out + 1) + i;
+ addr2 = (struct in6_addr *)(rth0_out + 1) +
+ (segments - i - 1);
+ addr_tmp = *addr1;
+ *addr1 = *addr2;
+ *addr2 = addr_tmp;
+ }
+
+ break;
+ default:
+ return (-1); /* type not supported */
+ }
+
+ return (0);
+}
+
+int
+inet6_rth_segments(const void *bp)
+{
+ struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
+ struct ip6_rthdr0 *rh0;
+ int addrs;
+
+ switch (rh->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ rh0 = (struct ip6_rthdr0 *)bp;
+
+ /*
+ * Validation for a type-0 routing header.
+ * Is this too strict?
+ */
+ if ((rh0->ip6r0_len % 2) != 0 ||
+ (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
+ return (-1);
+
+ return (addrs);
+ default:
+ return (-1); /* unknown type */
+ }
+}
+
+struct in6_addr *
+inet6_rth_getaddr(const void *bp, int idx)
+{
+ struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
+ struct ip6_rthdr0 *rh0;
+ int rthlen, addrs;
+
+ switch (rh->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ rh0 = (struct ip6_rthdr0 *)bp;
+ rthlen = (rh0->ip6r0_len + 1) << 3;
+
+ /*
+ * Validation for a type-0 routing header.
+ * Is this too strict?
+ */
+ if ((rthlen % 2) != 0 ||
+ (addrs = (rthlen >> 1)) < rh0->ip6r0_segleft)
+ return (NULL);
+
+ if (idx < 0 || addrs <= idx)
+ return (NULL);
+
+ return (((struct in6_addr *)(rh0 + 1)) + idx);
+ default:
+ return (NULL); /* unknown type */
+ break;
+ }
}