summaryrefslogtreecommitdiffstats
path: root/lib/libc/net/rthdr.c
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2003-10-24 18:26:30 +0000
committerume <ume@FreeBSD.org>2003-10-24 18:26:30 +0000
commit881c4fa39150df7d0de2dae7ae808f6a73cb199a (patch)
tree6ce05cb7459c9a9be90d670c12bfddbbbcb6946d /lib/libc/net/rthdr.c
parent0b2009d038122fd790a91ca95c5d9044ff2715c0 (diff)
downloadFreeBSD-src-881c4fa39150df7d0de2dae7ae808f6a73cb199a.zip
FreeBSD-src-881c4fa39150df7d0de2dae7ae808f6a73cb199a.tar.gz
Switch Advanced Sockets API for IPv6 from RFC2292 to RFC3542
(aka RFC2292bis). Though I believe this commit doesn't break backward compatibility againt existing binaries, it breaks backward compatibility of API. Now, the applications which use Advanced Sockets API such as telnet, ping6, mld6query and traceroute6 use RFC3542 API. Obtained from: KAME
Diffstat (limited to 'lib/libc/net/rthdr.c')
-rw-r--r--lib/libc/net/rthdr.c548
1 files changed, 339 insertions, 209 deletions
diff --git a/lib/libc/net/rthdr.c b/lib/libc/net/rthdr.c
index abfe34a..d7b0077 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;
-
- rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
-
- 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);
+ struct cmsghdr *ch = (struct cmsghdr *)bp;
+ struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
+
+ ch->cmsg_level = IPPROTO_IPV6;
+ ch->cmsg_type = IPV6_RTHDR;
+
+ 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;
-
- 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);
+ struct ip6_rthdr *rthdr;
+
+ 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)
+ 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;
-
- 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);
- }
+ struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+
+ 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);
+
+ 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)
+ 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
+ }
- rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+ default:
+ return NULL;
+ }
+}
- switch(rthdr->ip6r_type) {
- case IPV6_RTHDR_TYPE_0:
- {
- struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
- int naddr;
+int
+inet6_rthdr_getflags(cmsg, idx)
+ const struct cmsghdr *cmsg;
+ int idx;
+{
+ struct ip6_rthdr *rthdr;
+
+ 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;
+
+ 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 */
+ }
- 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;
+ default:
+ return (-1);
}
- 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;
+}
+
+/*
+ * 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 */
}
- return &rt0->ip6r0_addr[idx - 1];
- }
+}
- default:
-#ifdef DEBUG
- fprintf(stderr, "inet6_rthdr_getaddr: unknown type(%d)\n",
- rthdr->ip6r_type);
-#endif
- return NULL;
- }
+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_rthdr_getflags(cmsg, idx)
- const struct cmsghdr *cmsg;
- int idx;
+inet6_rth_add(void *bp, const struct in6_addr *addr)
{
- struct ip6_rthdr *rthdr;
+ 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);
+}
- rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+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 */
+ }
- switch(rthdr->ip6r_type) {
- case IPV6_RTHDR_TYPE_0:
- {
- struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
- int naddr;
+ return (0);
+}
- 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;
+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 */
}
- 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;
+}
+
+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;
}
- 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;
- }
}
OpenPOWER on IntegriCloud