summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/net/Makefile.inc16
-rw-r--r--lib/libc/net/getaddrinfo.c430
-rw-r--r--lib/libc/net/inet6_opt_init.3291
-rw-r--r--lib/libc/net/inet6_rth_space.3254
-rw-r--r--lib/libc/net/ip6opt.c227
-rw-r--r--lib/libc/net/rthdr.c548
-rw-r--r--lib/libsdp/search.c1
7 files changed, 1401 insertions, 366 deletions
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc
index 01dc3b61e091..a00269e04bd1 100644
--- a/lib/libc/net/Makefile.inc
+++ b/lib/libc/net/Makefile.inc
@@ -44,7 +44,8 @@ MAN+= addr2ascii.3 byteorder.3 ethers.3 getaddrinfo.3 gethostbyname.3 \
getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 hesiod.3 \
if_indextoname.3 \
inet.3 inet_net.3 \
- inet6_option_space.3 inet6_rthdr_space.3 linkaddr.3 \
+ inet6_opt_init.3 inet6_option_space.3 inet6_rth_space.3 \
+ inet6_rthdr_space.3 linkaddr.3 \
nsdispatch.3 rcmd.3 rcmdsh.3 resolver.3 sockatmark.3
MLINKS+=addr2ascii.3 ascii2addr.3
@@ -73,11 +74,22 @@ MLINKS+=inet.3 addr.3 inet.3 inet_addr.3 inet.3 inet_aton.3 \
inet.3 inet_ntop.3 inet.3 inet_pton.3 \
inet.3 network.3 inet.3 ntoa.3
MLINKS+=inet_net.3 inet_net_ntop.3 inet_net.3 inet_net_pton.3
-MLINKS+=inet6_option_space.3 inet6_option_alloc.3 \
+MLINKS+=inet6_opt_init.3 inet6_opt_append.3 \
+ inet6_opt_init.3 inet6_opt_find.3 \
+ inet6_opt_init.3 inet6_opt_finish.3 \
+ inet6_opt_init.3 inet6_opt_get_val.3 \
+ inet6_opt_init.3 inet6_opt_next.3 \
+ inet6_opt_init.3 inet6_opt_set_val.3 \
+ inet6_option_space.3 inet6_option_alloc.3 \
inet6_option_space.3 inet6_option_append.3 \
inet6_option_space.3 inet6_option_find.3 \
inet6_option_space.3 inet6_option_init.3 \
inet6_option_space.3 inet6_option_next.3 \
+ inet6_rth_space.3 inet6_rth_add.3 \
+ inet6_rth_space.3 inet6_rth_getaddr.3 \
+ inet6_rth_space.3 inet6_rth_init.3 \
+ inet6_rth_space.3 inet6_rth_reverse.3 \
+ inet6_rth_space.3 inet6_rth_segments.3 \
inet6_rthdr_space.3 inet6_rthdr_add.3 \
inet6_rthdr_space.3 inet6_rthdr_getaddr.3 \
inet6_rthdr_space.3 inet6_rthdr_getflags.3 \
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
index e8c6d4fa912f..026909af40a8 100644
--- a/lib/libc/net/getaddrinfo.c
+++ b/lib/libc/net/getaddrinfo.c
@@ -1,4 +1,4 @@
-/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */
+/* $KAME: getaddrinfo.c,v 1.160 2003/05/17 01:30:42 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -37,6 +37,10 @@
* - Return values. There are nonstandard return values defined and used
* in the source code. This is because RFC2553 is silent about which error
* code must be returned for which situation.
+ * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2
+ * says to use inet_aton() to convert IPv4 numeric to binary (allows
+ * classful form as a result).
+ * current code - disallow classful form for IPv4 (due to use of inet_pton).
* - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
* invalid. current code - SEGV on freeaddrinfo(NULL)
*
@@ -71,11 +75,15 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
+#ifdef INET6
+#include <sys/queue.h>
+#include <net/if_var.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <netinet6/in6_var.h> /* XXX */
+#endif /* INET6 */
#include <arpa/inet.h>
#include <arpa/nameser.h>
-#include <rpc/rpc.h>
-#include <rpcsvc/yp_prot.h>
-#include <rpcsvc/ypclnt.h>
#include <netdb.h>
#include <pthread.h>
#include <resolv.h>
@@ -153,23 +161,24 @@ struct explore {
#define WILD_AF(ex) ((ex)->e_wild & 0x01)
#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
+#define WILD_ACTIVE(ex) ((ex)->e_wild & 0x08)
+#define WILD_PASSIVE(ex) ((ex)->e_wild & 0x10)
};
static const struct explore explore[] = {
#if 0
- { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
+ { PF_LOCAL, ANY, ANY, NULL, 0x01 },
#endif
#ifdef INET6
- { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
- { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
- { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
+ { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x1f },
+ { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x0f }, /* !PASSIVE */
+ { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x17 }, /* PASSIVE */
+ { PF_INET6, SOCK_RAW, ANY, NULL, 0x1d },
#endif
- { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
- { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
- { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
- { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
- { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
- { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
+ { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x1f },
+ { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x0f }, /* !PASSIVE */
+ { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x17 }, /* PASSIVE */
+ { PF_INET, SOCK_RAW, ANY, NULL, 0x1d },
{ -1, 0, 0, NULL, 0 },
};
@@ -179,6 +188,8 @@ static const struct explore explore[] = {
#define PTON_MAX 4
#endif
+#define AIO_SRCFLAG_DEPRECATED 0x1
+
static const ns_src default_dns_files[] = {
{ NSSRC_FILES, NS_SUCCESS },
{ NSSRC_DNS, NS_SUCCESS },
@@ -202,20 +213,23 @@ typedef union {
} querybuf;
static int str_isnumber(const char *);
+static int explore_copy(const struct addrinfo *, const struct addrinfo *,
+ struct addrinfo **);
static int explore_null(const struct addrinfo *,
const char *, struct addrinfo **);
static int explore_numeric(const struct addrinfo *, const char *,
- const char *, struct addrinfo **);
+ const char *, struct addrinfo **, const char *);
static int explore_numeric_scope(const struct addrinfo *, const char *,
const char *, struct addrinfo **);
static int get_canonname(const struct addrinfo *,
struct addrinfo *, const char *);
static struct addrinfo *get_ai(const struct addrinfo *,
const struct afd *, const char *);
+static struct addrinfo *copy_ai(const struct addrinfo *);
static int get_portmatch(const struct addrinfo *, const char *);
static int get_port(struct addrinfo *, const char *, int);
static const struct afd *find_afd(int);
-static int addrconfig(struct addrinfo *);
+static int addrconfig(int);
#ifdef INET6
static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
#endif
@@ -373,10 +387,20 @@ getaddrinfo(hostname, servname, hints, res)
struct addrinfo sentinel;
struct addrinfo *cur;
int error = 0;
- struct addrinfo ai;
- struct addrinfo ai0;
+ struct addrinfo ai, ai0, *afai;
struct addrinfo *pai;
+ const struct afd *afd;
const struct explore *ex;
+ struct addrinfo *afailist[sizeof(afdl)/sizeof(afdl[0])];
+ struct addrinfo *afai_unspec;
+ int found;
+ int numeric = 0;
+
+ /* ensure we return NULL on errors */
+ *res = NULL;
+
+ memset(afailist, 0, sizeof(afailist));
+ afai_unspec = NULL;
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
@@ -417,20 +441,27 @@ getaddrinfo(hostname, servname, hints, res)
*/
if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
for (ex = explore; ex->e_af >= 0; ex++) {
- if (pai->ai_family != ex->e_af)
+ if (!MATCH_FAMILY(pai->ai_family, ex->e_af,
+ WILD_AF(ex)))
continue;
- if (ex->e_socktype == ANY)
+ if (!MATCH(pai->ai_socktype, ex->e_socktype,
+ WILD_SOCKTYPE(ex)))
continue;
- if (ex->e_protocol == ANY)
+ if (!MATCH(pai->ai_protocol, ex->e_protocol,
+ WILD_PROTOCOL(ex)))
continue;
- if (pai->ai_socktype == ex->e_socktype &&
- pai->ai_protocol != ex->e_protocol) {
- ERR(EAI_BADHINTS);
- }
+
+ /* matched */
+ break;
+ }
+
+ if (ex->e_af < 0) {
+ ERR(EAI_BADHINTS);
}
}
}
+#if defined(AI_ALL) && defined(AI_V4MAPPED)
/*
* post-2553: AI_ALL and AI_V4MAPPED are effective only against
* AF_INET6 query. They need to be ignored if specified in other
@@ -451,6 +482,7 @@ getaddrinfo(hostname, servname, hints, res)
#endif
break;
}
+#endif
/*
* check for special cases. (1) numeric servname is disallowed if
@@ -459,7 +491,7 @@ getaddrinfo(hostname, servname, hints, res)
*/
if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
#ifdef PF_INET6
- || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
+ || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
#endif
) {
ai0 = *pai; /* backup *pai */
@@ -480,108 +512,182 @@ getaddrinfo(hostname, servname, hints, res)
ai0 = *pai;
- /* NULL hostname, or numeric hostname */
- for (ex = explore; ex->e_af >= 0; ex++) {
+ /*
+ * NULL hostname, or numeric hostname.
+ * If numreic representation of AF1 can be interpreted as FQDN
+ * representation of AF2, we need to think again about the code below.
+ */
+ found = 0;
+ for (afd = afdl; afd->a_af; afd++) {
*pai = ai0;
- /* PF_UNSPEC entries are prepared for DNS queries only */
- if (ex->e_af == PF_UNSPEC)
- continue;
-
- if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
- continue;
- if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
- continue;
- if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
+ if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
continue;
if (pai->ai_family == PF_UNSPEC)
- pai->ai_family = ex->e_af;
- if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
- pai->ai_socktype = ex->e_socktype;
- if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
- pai->ai_protocol = ex->e_protocol;
+ pai->ai_family = afd->a_af;
- if (hostname == NULL)
- error = explore_null(pai, servname, &cur->ai_next);
- else
- error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
-
- if (error)
- goto free;
+ if (hostname == NULL) {
+ /*
+ * filter out AFs that are not supported by the kernel
+ * XXX errno?
+ */
+ if (!addrconfig(pai->ai_family))
+ continue;
+ error = explore_null(pai, servname,
+ &afailist[afd - afdl]);
+ } else
+ error = explore_numeric_scope(pai, hostname, servname,
+ &afailist[afd - afdl]);
- while (cur && cur->ai_next)
- cur = cur->ai_next;
+ if (!error && afailist[afd - afdl])
+ found++;
+ }
+ if (found) {
+ numeric = 1;
+ goto globcopy;
}
-
- /*
- * XXX
- * If numreic representation of AF1 can be interpreted as FQDN
- * representation of AF2, we need to think again about the code below.
- */
- if (sentinel.ai_next)
- goto good;
if (hostname == NULL)
ERR(EAI_NONAME); /* used to be EAI_NODATA */
if (pai->ai_flags & AI_NUMERICHOST)
ERR(EAI_NONAME);
- if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0))
- ERR(EAI_FAIL);
-
/*
* hostname as alphabetical name.
- * we would like to prefer AF_INET6 than AF_INET, so we'll make a
- * outer loop by AFs.
+ * first, try to query DNS for all possible address families.
*/
+ /*
+ * the operating systems support PF_UNSPEC lookup in explore_fqdn().
+ */
+ *pai = ai0;
+ error = explore_fqdn(pai, hostname, servname, &afai_unspec);
+
+globcopy:
for (ex = explore; ex->e_af >= 0; ex++) {
*pai = ai0;
- /* require exact match for family field */
- if (pai->ai_family != ex->e_af)
+ if (pai->ai_family == PF_UNSPEC)
+ pai->ai_family = ex->e_af;
+
+ if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
+ continue;
+ if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
+ continue;
+ if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
continue;
- if (!MATCH(pai->ai_socktype, ex->e_socktype,
- WILD_SOCKTYPE(ex))) {
+#ifdef AI_ADDRCONFIG
+ /*
+ * If AI_ADDRCONFIG is specified, check if we are
+ * expected to return the address family or not.
+ */
+ if ((pai->ai_flags & AI_ADDRCONFIG) != 0 &&
+ !addrconfig(afd->a_af))
continue;
- }
- if (!MATCH(pai->ai_protocol, ex->e_protocol,
- WILD_PROTOCOL(ex))) {
+#endif
+
+ if ((pai->ai_flags & AI_PASSIVE) != 0 && WILD_PASSIVE(ex))
+ ;
+ else if ((pai->ai_flags & AI_PASSIVE) == 0 && WILD_ACTIVE(ex))
+ ;
+ else
continue;
- }
+ if (pai->ai_family == PF_UNSPEC)
+ pai->ai_family = ex->e_af;
if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
pai->ai_socktype = ex->e_socktype;
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
pai->ai_protocol = ex->e_protocol;
- error = explore_fqdn(pai, hostname, servname,
- &cur->ai_next);
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ continue;
+
+ if (afai_unspec)
+ afai = afai_unspec;
+ else {
+ if ((afd = find_afd(pai->ai_family)) == NULL)
+ continue;
+ /* XXX assumes that afd points inside afdl[] */
+ afai = afailist[afd - afdl];
+ }
+ if (!afai)
+ continue;
+
+ error = explore_copy(pai, afai, &cur->ai_next);
while (cur && cur->ai_next)
cur = cur->ai_next;
}
- /* XXX */
+ /* XXX inhibit errors if we have the result */
if (sentinel.ai_next)
error = 0;
- if (error)
- goto free;
+ /*
+ * ensure we return either:
+ * - error == 0, non-NULL *res
+ * - error != 0, NULL *res
+ */
if (error == 0) {
if (sentinel.ai_next) {
- good:
*res = sentinel.ai_next;
- return SUCCESS;
+ error = 0;
} else
error = EAI_FAIL;
}
- free:
- bad:
- if (sentinel.ai_next)
- freeaddrinfo(sentinel.ai_next);
- *res = NULL;
+
+bad:
+ if (afai_unspec)
+ freeaddrinfo(afai_unspec);
+ for (afd = afdl; afd->a_af; afd++) {
+ if (afailist[afd - afdl])
+ freeaddrinfo(afailist[afd - afdl]);
+ }
+ if (!*res)
+ if (sentinel.ai_next)
+ freeaddrinfo(sentinel.ai_next);
+ return error;
+}
+
+static int
+explore_copy(pai, src0, res)
+ const struct addrinfo *pai; /* seed */
+ const struct addrinfo *src0; /* source */
+ struct addrinfo **res;
+{
+ int error;
+ struct addrinfo sentinel, *cur;
+ const struct addrinfo *src;
+
+ error = 0;
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+
+ for (src = src0; src != NULL; src = src->ai_next) {
+ if (src->ai_family != pai->ai_family)
+ continue;
+
+ cur->ai_next = copy_ai(src);
+ if (!cur->ai_next) {
+ error = EAI_MEMORY;
+ goto fail;
+ }
+
+ cur->ai_next->ai_socktype = pai->ai_socktype;
+ cur->ai_next->ai_protocol = pai->ai_protocol;
+ cur = cur->ai_next;
+ }
+
+ *res = sentinel.ai_next;
+ return 0;
+
+fail:
+ freeaddrinfo(sentinel.ai_next);
return error;
}
@@ -596,7 +702,6 @@ explore_null(pai, servname, res)
const char *servname;
struct addrinfo **res;
{
- int s;
const struct afd *afd;
struct addrinfo *cur;
struct addrinfo sentinel;
@@ -607,17 +712,6 @@ explore_null(pai, servname, res)
cur = &sentinel;
/*
- * filter out AFs that are not supported by the kernel
- * XXX errno?
- */
- s = _socket(pai->ai_family, SOCK_DGRAM, 0);
- if (s < 0) {
- if (errno != EMFILE)
- return 0;
- } else
- _close(s);
-
- /*
* if the servname does not match socktype/protocol, ignore it.
*/
if (get_portmatch(pai, servname) != 0)
@@ -655,11 +749,12 @@ free:
* numeric hostname
*/
static int
-explore_numeric(pai, hostname, servname, res)
+explore_numeric(pai, hostname, servname, res, canonname)
const struct addrinfo *pai;
const char *hostname;
const char *servname;
struct addrinfo **res;
+ const char *canonname;
{
const struct afd *afd;
struct addrinfo *cur;
@@ -671,12 +766,6 @@ explore_numeric(pai, hostname, servname, res)
sentinel.ai_next = NULL;
cur = &sentinel;
- /*
- * if the servname does not match socktype/protocol, ignore it.
- */
- if (get_portmatch(pai, servname) != 0)
- return 0;
-
afd = find_afd(pai->ai_family);
if (afd == NULL)
return 0;
@@ -689,6 +778,14 @@ explore_numeric(pai, hostname, servname, res)
pai->ai_family == PF_UNSPEC /*?*/) {
GET_AI(cur->ai_next, afd, pton);
GET_PORT(cur->ai_next, servname);
+ if ((pai->ai_flags & AI_CANONNAME)) {
+ /*
+ * Set the numeric address itself as
+ * the canonical name, based on a
+ * clarification in rfc2553bis-03.
+ */
+ GET_CANONNAME(cur->ai_next, canonname);
+ }
while (cur && cur->ai_next)
cur = cur->ai_next;
} else
@@ -702,6 +799,14 @@ explore_numeric(pai, hostname, servname, res)
pai->ai_family == PF_UNSPEC /*?*/) {
GET_AI(cur->ai_next, afd, pton);
GET_PORT(cur->ai_next, servname);
+ if ((pai->ai_flags & AI_CANONNAME)) {
+ /*
+ * Set the numeric address itself as
+ * the canonical name, based on a
+ * clarification in rfc2553bis-03.
+ */
+ GET_CANONNAME(cur->ai_next, canonname);
+ }
while (cur && cur->ai_next)
cur = cur->ai_next;
} else
@@ -731,7 +836,7 @@ explore_numeric_scope(pai, hostname, servname, res)
struct addrinfo **res;
{
#if !defined(SCOPE_DELIMITER) || !defined(INET6)
- return explore_numeric(pai, hostname, servname, res);
+ return explore_numeric(pai, hostname, servname, res, hostname);
#else
const struct afd *afd;
struct addrinfo *cur;
@@ -739,22 +844,16 @@ explore_numeric_scope(pai, hostname, servname, res)
char *cp, *hostname2 = NULL, *scope, *addr;
struct sockaddr_in6 *sin6;
- /*
- * if the servname does not match socktype/protocol, ignore it.
- */
- if (get_portmatch(pai, servname) != 0)
- return 0;
-
afd = find_afd(pai->ai_family);
if (afd == NULL)
return 0;
if (!afd->a_scoped)
- return explore_numeric(pai, hostname, servname, res);
+ return explore_numeric(pai, hostname, servname, res, hostname);
cp = strchr(hostname, SCOPE_DELIMITER);
if (cp == NULL)
- return explore_numeric(pai, hostname, servname, res);
+ return explore_numeric(pai, hostname, servname, res, hostname);
/*
* Handle special case of <scoped_address><delimiter><scope id>
@@ -767,7 +866,7 @@ explore_numeric_scope(pai, hostname, servname, res)
addr = hostname2;
scope = cp + 1;
- error = explore_numeric(pai, addr, servname, res);
+ error = explore_numeric(pai, addr, servname, res, hostname);
if (error == 0) {
u_int32_t scopeid;
@@ -777,6 +876,8 @@ explore_numeric_scope(pai, hostname, servname, res)
sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
free(hostname2);
+ freeaddrinfo(*res);
+ *res = NULL;
return(EAI_NONAME); /* XXX: is return OK? */
}
sin6->sin6_scope_id = scopeid;
@@ -785,6 +886,10 @@ explore_numeric_scope(pai, hostname, servname, res)
free(hostname2);
+ if (error && *res) {
+ freeaddrinfo(*res);
+ *res = NULL;
+ }
return error;
#endif
}
@@ -796,10 +901,9 @@ get_canonname(pai, ai, str)
const char *str;
{
if ((pai->ai_flags & AI_CANONNAME) != 0) {
- ai->ai_canonname = (char *)malloc(strlen(str) + 1);
+ ai->ai_canonname = strdup(str);
if (ai->ai_canonname == NULL)
return EAI_MEMORY;
- strlcpy(ai->ai_canonname, str, strlen(str) + 1);
}
return 0;
}
@@ -875,6 +979,39 @@ get_ai(pai, afd, addr)
return ai;
}
+/* XXX need to malloc() the same way we do from other functions! */
+static struct addrinfo *
+copy_ai(pai)
+ const struct addrinfo *pai;
+{
+ struct addrinfo *ai;
+ size_t l;
+
+ l = sizeof(*ai) + pai->ai_addrlen;
+ if ((ai = (struct addrinfo *)malloc(l)) == NULL)
+ return NULL;
+ memset(ai, 0, l);
+ memcpy(ai, pai, sizeof(*ai));
+ ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
+ memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen);
+
+ if (pai->ai_canonname) {
+ l = strlen(pai->ai_canonname) + 1;
+ if ((ai->ai_canonname = malloc(l)) == NULL) {
+ free(ai);
+ return NULL;
+ }
+ strlcpy(ai->ai_canonname, pai->ai_canonname, l);
+ } else {
+ /* just to make sure */
+ ai->ai_canonname = NULL;
+ }
+
+ ai->ai_next = NULL;
+
+ return ai;
+}
+
static int
get_portmatch(ai, servname)
const struct addrinfo *ai;
@@ -914,6 +1051,7 @@ get_port(ai, servname, matchonly)
return EAI_SERVICE;
case SOCK_DGRAM:
case SOCK_STREAM:
+ case SOCK_SEQPACKET:
allownumeric = 1;
break;
case ANY:
@@ -931,11 +1069,11 @@ get_port(ai, servname, matchonly)
return EAI_SERVICE;
port = htons(port);
} else {
- switch (ai->ai_socktype) {
- case SOCK_DGRAM:
+ switch (ai->ai_protocol) {
+ case IPPROTO_UDP:
proto = "udp";
break;
- case SOCK_STREAM:
+ case IPPROTO_TCP:
proto = "tcp";
break;
default:
@@ -986,41 +1124,20 @@ find_afd(af)
* will take care of it.
* the semantics of AI_ADDRCONFIG is not defined well. we are not sure
* if the code is right or not.
- *
- * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with
- * _dns_getaddrinfo.
*/
static int
-addrconfig(pai)
- struct addrinfo *pai;
+addrconfig(af)
+ int af;
{
- int s, af;
+ int s;
- /*
- * TODO:
- * Note that implementation dependent test for address
- * configuration should be done everytime called
- * (or apropriate interval),
- * because addresses will be dynamically assigned or deleted.
- */
- af = pai->ai_family;
- if (af == AF_UNSPEC) {
- if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
- af = AF_INET;
- else {
- _close(s);
- if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- af = AF_INET6;
- else
- _close(s);
- }
- }
- if (af != AF_UNSPEC) {
- if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
+ /* XXX errno */
+ s = socket(af, SOCK_DGRAM, 0);
+ if (s < 0) {
+ if (errno != EMFILE)
return 0;
- _close(s);
- }
- pai->ai_family = af;
+ } else
+ close(s);
return 1;
}
@@ -1033,16 +1150,15 @@ ip6_str2scopeid(scope, sin6, scopeid)
u_int32_t *scopeid;
{
u_long lscopeid;
- struct in6_addr *a6;
+ struct in6_addr *a6 = &sin6->sin6_addr;
char *ep;
- a6 = &sin6->sin6_addr;
-
/* empty scopeid portion is invalid */
if (*scope == '\0')
return -1;
- if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
+ if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
+ IN6_IS_ADDR_MC_NODELOCAL(a6)) {
/*
* We currently assume a one-to-one mapping between links
* and interfaces, so we simply use interface indices for
@@ -1063,7 +1179,7 @@ ip6_str2scopeid(scope, sin6, scopeid)
goto trynumeric; /* global */
/* try to convert to a numeric id as a last resort */
- trynumeric:
+trynumeric:
errno = 0;
lscopeid = strtoul(scope, &ep, 10);
*scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
@@ -1699,9 +1815,13 @@ nextline:
*cp++ = '\0';
}
- hints = *pai;
+ /* we should not glob socktype/protocol here */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = pai->ai_family;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = 0;
hints.ai_flags = AI_NUMERICHOST;
- error = getaddrinfo(addr, NULL, &hints, &res0);
+ error = getaddrinfo(addr, "0", &hints, &res0);
if (error == 0) {
for (res = res0; res; res = res->ai_next) {
/* cover it up */
diff --git a/lib/libc/net/inet6_opt_init.3 b/lib/libc/net/inet6_opt_init.3
new file mode 100644
index 000000000000..65af709eaf8a
--- /dev/null
+++ b/lib/libc/net/inet6_opt_init.3
@@ -0,0 +1,291 @@
+.\" $KAME: inet6_opt_init.3,v 1.5 2002/10/17 14:13:47 jinmei Exp $
+.\"
+.\" Copyright (C) 2000 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 5, 2000
+.Dt INET6_OPT_INIT 3
+.Os
+.\"
+.Sh NAME
+.Nm inet6_opt_init ,
+.Nm inet6_opt_append ,
+.Nm inet6_opt_finish ,
+.Nm inet6_opt_set_val ,
+.Nm inet6_opt_next ,
+.Nm inet6_opt_find ,
+.Nm inet6_opt_get_val
+.Nd IPv6 Hop-by-Hop and Destination Options manipulation
+.\"
+.Sh SYNOPSIS
+.In netinet/in.h
+.Ft "int"
+.Fn inet6_opt_init "void *extbuf" "socklen_t extlen"
+.Ft "int"
+.Fn inet6_opt_append "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t type" "socklen_t len" "u_int8_t align" "void **databufp"
+.Ft "int"
+.Fn inet6_opt_finish "void *extbuf" "socklen_t extlen" "int offset"
+.Ft "int"
+.Fn inet6_opt_set_val "void *databuf" "int offset" "void *val" "socklen_t vallen"
+.Ft "int"
+.Fn inet6_opt_next "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t *typep" "socklen_t *lenp" "void **databufp"
+.Ft "int"
+.Fn inet6_opt_find "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t type" "socklen_t *lenp" "void **databufp"
+.Ft "int"
+.Fn inet6_opt_get_val "void *databuf" "socklen_t offset" "void *val" "socklen_t vallen"
+.\"
+.Sh DESCRIPTION
+Building and parsing the Hop-by-Hop and Destination options is
+complicated.
+The advanced API therefore defines a set
+of functions to help applications.
+These functions assume the
+formatting rules specified in Appendix B in RFC2460 i.e. that the
+largest field is placed last in the option.
+The function prototypes for
+these functions are all in the
+.Aq Li netinet/in.h
+header.
+.\"
+.Ss inet6_opt_init
+.Fn inet6_opt_init
+returns the number of bytes needed for the empty
+extension header i.e. without any options.
+If
+.Li extbuf
+is not NULL it also initializes the extension header to have the correct length
+field.
+In that case if the
+.Li extlen value is not a positive
+.Po
+i.e., non-zero
+.Pc
+multiple of 8 the function fails and returns -1.
+.\"
+.Ss inet6_opt_append
+.Fn inet6_opt_append
+returns the updated total length taking into account
+adding an option with length
+.Li len
+and alignment
+.Li align .
+.Li Offset
+should be the length returned by
+.Fn inet6_opt_init
+or a previous
+.Fn inet6_opt_append .
+If
+.Li extbuf
+is not NULL then, in addition to returning the length,
+the function inserts any needed pad option, initializes the option
+.Po
+setting the type and length fields
+.Pc
+and returns a pointer to the location for the option content in
+.Li databufp .
+.Pp
+.Li type
+is the 8-bit option type.
+.Li len
+is the length of the option data
+.Po
+i.e. excluding the option type and option length fields.
+.Pc
+.Pp
+Once
+.Fn inet6_opt_append
+has been called the application can use the
+databuf directly, or use
+.Fn inet6_opt_set_val
+to specify the content of the option.
+.Pp
+The option type must have a value from 2 to 255, inclusive.
+.Po
+0 and 1 are reserved for the Pad1 and PadN options, respectively.
+.Pc
+.Pp
+The option data length must have a value between 0 and 255,
+inclusive, and is the length of the option data that follows.
+.Pp
+The
+.Li align
+parameter must have a value of 1, 2, 4, or 8.
+The align value can not exceed the value of
+.Li len .
+.\"
+.Ss inet6_opt_finish
+.Fn inet6_opt_finish
+returns the updated total length
+taking into account the final padding of the extension header to make
+it a multiple of 8 bytes.
+.Li Offset
+should be the length returned by
+.Fn inet6_opt_init
+or
+.Fn inet6_opt_append .
+If
+.Li extbuf
+is not NULL the function also
+initializes the option by inserting a Pad1 or PadN option of the
+proper length.
+.Pp
+If the necessary pad does not fit in the extension header buffer the
+function returns -1.
+.\"
+.Ss inet6_opt_set_val
+.Fn inet6_opt_set_val
+inserts data items of various sizes in the data portion of the option.
+.Li Databuf
+should be a pointer returned by
+.Fn inet6_opt_append .
+.Li val
+should point to the data to be
+inserted.
+.Li Offset
+specifies where in the data portion of the option
+the value should be inserted; the first byte after the option type
+and length is accessed by specifying an offset of zero.
+.Pp
+The caller should ensure that each field is aligned on its natural
+boundaries as described in Appendix B of RFC2460, but the function
+must not rely on the caller's behavior.
+Even when the alignment requirement is not satisfied,
+the function should just copy the data as required.
+.Pp
+The function returns the offset for the next field
+.Po
+i.e.,
+.Li offset
++
+.Li vallen
+.Pc
+which can be used when composing option content with multiple fields.
+.\"
+.Ss inet6_opt_next
+.Fn inet6_opt_next
+parses received extension headers returning the next
+option.
+.Li Extbuf
+and
+.Li extlen
+specifies the extension header.
+.Li Offset
+should either be zero (for the first option) or the length returned
+by a previous call to
+.Fn inet6_opt_next
+or
+.Fn inet6_opt_find .
+It specifies the position where to continue scanning the extension
+buffer.
+The next option is returned by updating
+.Li typep ,
+.Li lenp ,
+and
+.Li databufp .
+This function returns the updated
+.Dq previous
+length
+computed by advancing past the option that was returned.
+This returned
+.Dq previous
+length can then be passed to subsequent calls to
+.Fn inet6_opt_next .
+This function does not return any PAD1 or PADN options.
+When there are no more options the return value is -1.
+.\"
+.Ss inet6_opt_get_val
+.Fn inet6_opt_get_val
+This function extracts data items of various sizes
+in the data portion of the option.
+.Li Databuf
+should be a pointer returned by
+.Fn inet6_opt_next
+or
+.Fn inet6_opt_find .
+.Li Val
+should point to the destination for the extracted data.
+.Li Offset
+specifies from where in the data portion of the option the value should be
+extracted; the first byte after the option type and length is
+accessed by specifying an offset of zero.
+.Pp
+It is expected that each field is aligned on its natural boundaries
+as described in Appendix B of RFC2460, but the function must not
+rely on the alignment.
+.Pp
+The function returns the offset for the next field
+.Po
+i.e.,
+.Li offset
++
+.Li vallen
+.Pc
+which can be used when extracting option content with
+multiple fields.
+Robust receivers might want to verify alignment before calling
+this function.
+.\"
+.Sh DIAGNOSTICS
+All the functions ruturn
+.Li -1
+on an error.
+.\"
+.Sh EXAMPLES
+draft-ietf-ipngwg-rfc2292bis-08.txt
+gives comprehensive examples in Section 23.
+.Pp
+KAME also provides examples in the advapitest directry of its kit.
+.\"
+.Sh SEE ALSO
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%A E. Nordmark
+.%A T. Jinmei
+.%T "Advanced Sockets API for IPv6"
+.%N draft-ietf-ipngwg-rfc2292bis-08
+.%D October 2002
+.Re
+.Rs
+.%A S. Deering
+.%A R. Hinden
+.%T "Internet Protocol, Version 6 (IPv6) Specification"
+.%N RFC2460
+.%D December 1998
+.Re
+.Sh HISTORY
+The implementation first appeared in KAME advanced networking kit.
+.Sh STANDARDS
+The functions
+are documented in
+.Dq Advanced Sockets API for IPv6
+.Pq draft-ietf-ipngwg-rfc2292bis-08.txt .
+.\"
+.Sh BUGS
+The text was shamelessly copied from internet-drafts for RFC2292bis.
diff --git a/lib/libc/net/inet6_rth_space.3 b/lib/libc/net/inet6_rth_space.3
new file mode 100644
index 000000000000..1289b11b3eef
--- /dev/null
+++ b/lib/libc/net/inet6_rth_space.3
@@ -0,0 +1,254 @@
+.\" $KAME: kame/kame/kame/libinet6/inet6_rth_space.3,v 1.4 2002/10/17 14:13:48 jinmei Exp $
+.\" $FreeBSD$
+.\"
+.\" Copyright (C) 2000 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 5, 2000
+.Dt INET6_RTH_SPACE 3
+.Os
+.\"
+.Sh NAME
+.Nm inet6_rth_space
+.Nm inet6_rth_init
+.Nm inet6_rth_add
+.Nm inet6_rth_reverse
+.Nm inet6_rth_segments
+.Nm inet6_rth_getaddr
+.Nd IPv6 Routing Header Options manipulation
+.\"
+.Sh SYNOPSIS
+.In netinet/in.h
+.Ft socklen_t
+.Fn inet6_rth_space "int" "int"
+.Ft "void *"
+.Fn inet6_rth_init "void *" "socklen_t" "int" "int"
+.Ft int
+.Fn inet6_rth_add "void *" "const struct in6_addr *"
+.Ft int
+.Fn inet6_rth_reverse "const void *" "void *"
+.Ft int
+.Fn inet6_rth_segments "const void *"
+.Ft "struct in6_addr *"
+.Fn inet6_rth_getaddr "const void *" "int"
+.\"
+.Sh DESCRIPTION
+The IPv6 advanced API defines six
+functions that the application calls to build and examine a Routing
+header, and the ability to use sticky options or ancillary data to
+communicate this information between the application and the kernel
+using the IPV6_RTHDR option.
+.Pp
+Three functions build a Routing header:
+.Bl -hang
+.It Fn inet6_rth_space
+returns #bytes required for Routing header
+.It Fn inet6_rth_init
+initializes buffer data for Routing header
+.It Fn inet6_rth_add
+adds one IPv6 address to the Routing header
+.El
+.Pp
+Three functions deal with a returned Routing header:
+.Bl -hang
+.It Fn inet6_rth_reverse
+reverses a Routing header
+.It Fn inet6_rth_segments
+returns #segments in a Routing header
+.It Fn inet6_rth_getaddr
+fetches one address from a Routing header
+.El
+.Pp
+The function prototypes for these functions are defined as a result
+of including the
+.Aq Li netinet/in.h
+header.
+.\"
+.Ss inet6_rth_space
+.Fn inet6_rth_space
+returns the number of bytes required to hold a Routing
+header of the specified type containing the specified number of
+.Li segments
+.Po addresses.
+.Pc
+For an IPv6 Type 0 Routing header, the number
+of
+.Li segments
+must be between 0 and 127, inclusive.
+The return value is just the space for the Routing header.
+When the application uses
+ancillary data it must pass the returned length to
+.Fn CMSG_LEN
+to determine how much memory is needed for the ancillary data object
+.Po
+including the cmsghdr structure.
+.Pc
+.Pp
+If the return value is 0, then either the type of the Routing header
+is not supported by this implementation or the number of segments is
+invalid for this type of Routing header.
+.Pp
+Note: This function returns the size but does not allocate the space
+required for the ancillary data.
+This allows an application to
+allocate a larger buffer, if other ancillary data objects are
+desired, since all the ancillary data objects must be specified to
+.Fn sendmsg
+as a single msg_control buffer.
+.Ss inet6_rth_init
+.Fn inet6_rth_init
+initializes the buffer pointed to by
+.Li bp
+to contain a
+Routing header of the specified type and sets ip6r_len based on the
+.Li segments
+parameter.
+.Li bp_len
+is only used to verify that the buffer is
+large enough.
+The ip6r_segleft field is set to zero;
+.Fn inet6_rth_add
+will increment it.
+.Pp
+When the application uses ancillary data the application must
+initialize any cmsghdr fields.
+.Pp
+The caller must allocate the buffer and its size can be determined by
+calling
+.Fn inet6_rth_space .
+.Pp
+Upon success the return value is the pointer to the buffer
+.Li bp ,
+and this is then used as the first argument to the next two functions.
+Upon an error the return value is NULL.
+.\"
+.Ss inet6_rth_add
+.Fn inet6_rth_add
+adds the IPv6 address pointed to by
+.Li addr
+to the end of the Routing header being constructed.
+.Pp
+If successful, the segleft member of the Routing Header is updated to
+account for the new address in the Routing header and the return
+value of the function is 0.
+Upon an error the return value of the function is -1.
+.\"
+.Ss inet6_rth_reverse
+.Fn inet6_rth_reverse
+takes a Routing header extension header
+.Po
+pointed to by the first argument
+.Li in
+.Pc
+and writes a new Routing header that sends
+datagrams along the reverse of that route.
+Both arguments are allowed to point to the same buffer
+.Po
+that is, the reversal can occur in place.
+.Pc
+.Pp
+The return value of the function is 0 on success, or -1 upon an error.
+.\"
+.Ss inet6_rth_segments
+.Fn inet6_rth_segments
+returns the number of segments
+.Po
+addresses
+.Pc
+contained in the Routing header described by
+.Li bp .
+On success the return value is
+zero or greater.
+The return value of the function is -1 upon an error.
+.\"
+.Ss inet6_rth_getaddr
+.Fn inet6_rth_getaddr
+returns a pointer to the IPv6 address specified by
+.Li index
+.Po
+which must have a value between 0 and one less than the value
+returned by
+.Fn inet6_rth_segments
+.Pc
+in the Routing header described by
+.Li bp .
+An application should first call
+.Fn inet6_rth_segments
+to obtain the number of segments in the Routing header.
+.Pp
+Upon an error the return value of the function is NULL.
+.\"
+.Sh DIAGNOSTICS
+.Fn inet6_rth_space
+and
+.FN inet6_rth_getaddr
+return 0 on errors.
+.Pp
+.Fn inet6_rthdr_init
+returns
+.Dv NULL
+on error.
+.Fn inet6_rth_add
+and
+.Fn inet6_rth_reverse
+return0 on success, or -1 upon an error.
+.\"
+.Sh EXAMPLES
+draft-ietf-ipngwg-rfc2292bis-08.txt
+gives comprehensive examples in Section 22.
+.Pp
+KAME also provides examples in the advapitest directry of its kit.
+.\"
+.Sh SEE ALSO
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%A E. Nordmark
+.%A E. Jinmei
+.%T "Advanced Sockets API for IPv6"
+.%N draft-ietf-ipngwg-rfc2292bis-08
+.%D October 2002
+.Re
+.Rs
+.%A S. Deering
+.%A R. Hinden
+.%T "Internet Protocol, Version 6 (IPv6) Specification"
+.%N RFC2460
+.%D December 1998
+.Re
+.Sh HISTORY
+The implementation first appeared in KAME advanced networking kit.
+.Sh STANDARDS
+The functions
+are documented in
+.Dq Advanced Sockets API for IPv6
+.Pq draft-ietf-ipngwg-rfc2292bis-08.txt .
+.\"
+.Sh BUGS
+The text was shamelessly copied from internet-drafts for RFC2292bis.
diff --git a/lib/libc/net/ip6opt.c b/lib/libc/net/ip6opt.c
index a26e45d3b83d..2f5491849b0d 100644
--- a/lib/libc/net/ip6opt.c
+++ b/lib/libc/net/ip6opt.c
@@ -1,3 +1,5 @@
+/* $KAME: ip6opt.c,v 1.13 2003/06/06 10:08:20 suz Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -111,6 +113,8 @@ inet6_option_append(cmsg, typep, multx, plusy)
return(-1);
if (plusy < 0 || plusy > 7)
return(-1);
+ if (typep[0] > 255)
+ return(-1);
/*
* If this is the first option, allocate space for the
@@ -127,6 +131,7 @@ inet6_option_append(cmsg, typep, multx, plusy)
padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
(off % multx);
padlen += plusy;
+ padlen %= multx; /* keep the pad as short as possible */
/* insert padding */
inet6_insert_padopt(bp, padlen);
cmsg->cmsg_len += padlen;
@@ -200,6 +205,7 @@ inet6_option_alloc(cmsg, datalen, multx, plusy)
padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
(off % multx);
padlen += plusy;
+ padlen %= multx; /* keep the pad as short as possible */
/* insert padding */
inet6_insert_padopt(bp, padlen);
cmsg->cmsg_len += padlen;
@@ -383,3 +389,224 @@ inet6_insert_padopt(u_char *p, int len)
return;
}
}
+
+/*
+ * The following functions are defined in a successor of RFC2292, aka
+ * rfc2292bis.
+ */
+
+int
+inet6_opt_init(void *extbuf, socklen_t extlen)
+{
+ struct ip6_ext *ext = (struct ip6_ext *)extbuf;
+
+ if (extlen < 0 || (extlen % 8))
+ return(-1);
+
+ if (ext) {
+ if (extlen == 0)
+ return(-1);
+ ext->ip6e_len = (extlen >> 3) - 1;
+ }
+
+ return(2); /* sizeof the next and the length fields */
+}
+
+int
+inet6_opt_append(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
+ socklen_t len, u_int8_t align, void **databufp)
+{
+ int currentlen = offset, padlen = 0;
+
+ /*
+ * The option type must have a value from 2 to 255, inclusive.
+ * (0 and 1 are reserved for the Pad1 and PadN options, respectively.)
+ */
+ if (type < 2 || type > 255)
+ return(-1);
+
+ /*
+ * The option data length must have a value between 0 and 255,
+ * inclusive, and is the length of the option data that follows.
+ */
+ if (len < 0 || len > 255)
+ return(-1);
+
+ /*
+ * The align parameter must have a value of 1, 2, 4, or 8.
+ * The align value can not exceed the value of len.
+ */
+ if (align != 1 && align != 2 && align != 4 && align != 8)
+ return(-1);
+ if (align > len)
+ return(-1);
+
+ /* Calculate the padding length. */
+ currentlen += 2 + len; /* 2 means "type + len" */
+ if (currentlen % align)
+ padlen = align - (currentlen % align);
+
+ /* The option must fit in the extension header buffer. */
+ currentlen += padlen;
+ if (extlen && /* XXX: right? */
+ currentlen > extlen)
+ return(-1);
+
+ if (extbuf) {
+ u_int8_t *optp = (u_int8_t *)extbuf + offset;
+
+ if (padlen == 1) {
+ /* insert a Pad1 option */
+ *optp = IP6OPT_PAD1;
+ optp++;
+ }
+ else if (padlen > 0) {
+ /* insert a PadN option for alignment */
+ *optp++ = IP6OPT_PADN;
+ *optp++ = padlen - 2;
+ memset(optp, 0, padlen - 2);
+ optp += (padlen - 2);
+ }
+
+ *optp++ = type;
+ *optp++ = len;
+
+ *databufp = optp;
+ }
+
+ return(currentlen);
+}
+
+int
+inet6_opt_finish(void *extbuf, socklen_t extlen, int offset)
+{
+ int updatelen = offset > 0 ? (1 + ((offset - 1) | 7)) : 0;;
+
+ if (extbuf) {
+ u_int8_t *padp;
+ int padlen = updatelen - offset;
+
+ if (updatelen > extlen)
+ return(-1);
+
+ padp = (u_int8_t *)extbuf + offset;
+ if (padlen == 1)
+ *padp = IP6OPT_PAD1;
+ else if (padlen > 0) {
+ *padp++ = IP6OPT_PADN;
+ *padp++ = (padlen - 2);
+ memset(padp, 0, padlen - 2);
+ }
+ }
+
+ return(updatelen);
+}
+
+int
+inet6_opt_set_val(void *databuf, int offset, void *val, socklen_t vallen)
+{
+
+ memcpy((u_int8_t *)databuf + offset, val, vallen);
+ return(offset + vallen);
+}
+
+int
+inet6_opt_next(void *extbuf, socklen_t extlen, int offset, u_int8_t *typep,
+ size_t *lenp, void **databufp)
+{
+ u_int8_t *optp, *lim;
+ int optlen;
+
+ /* Validate extlen. XXX: is the variable really necessary?? */
+ if (extlen == 0 || (extlen % 8))
+ return(-1);
+ lim = (u_int8_t *)extbuf + extlen;
+
+ /*
+ * If this is the first time this function called for this options
+ * header, simply return the 1st option.
+ * Otherwise, search the option list for the next option.
+ */
+ if (offset == 0) {
+ optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
+ }
+ else
+ optp = (u_int8_t *)extbuf + offset;
+
+ /* Find the next option skipping any padding options. */
+ while(optp < lim) {
+ switch(*optp) {
+ case IP6OPT_PAD1:
+ optp++;
+ break;
+ case IP6OPT_PADN:
+ if ((optlen = ip6optlen(optp, lim)) == 0)
+ goto optend;
+ optp += optlen;
+ break;
+ default: /* found */
+ if ((optlen = ip6optlen(optp, lim)) == 0)
+ goto optend;
+ *typep = *optp;
+ *lenp = optlen - 2;
+ *databufp = optp + 2;
+ return(optp + optlen - (u_int8_t *)extbuf);
+ }
+ }
+
+ optend:
+ *databufp = NULL; /* for safety */
+ return(-1);
+}
+
+int
+inet6_opt_find(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
+ socklen_t *lenp, void **databufp)
+{
+ u_int8_t *optp, *lim;
+ int optlen;
+
+ /* Validate extlen. XXX: is the variable really necessary?? */
+ if (extlen == 0 || (extlen % 8))
+ return(-1);
+ lim = (u_int8_t *)extbuf + extlen;
+
+ /*
+ * If this is the first time this function called for this options
+ * header, simply return the 1st option.
+ * Otherwise, search the option list for the next option.
+ */
+ if (offset == 0) {
+ optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
+ }
+ else
+ optp = (u_int8_t *)extbuf + offset;
+
+ /* Find the specified option */
+ while(optp < lim) {
+ if ((optlen = ip6optlen(optp, lim)) == 0)
+ goto optend;
+
+ if (*optp == type) { /* found */
+ *lenp = optlen - 2;
+ *databufp = optp + 2;
+ return(optp + optlen - (u_int8_t *)extbuf);
+ }
+
+ optp += optlen;
+ }
+
+ optend:
+ *databufp = NULL; /* for safety */
+ return(-1);
+}
+
+int
+inet6_opt_get_val(void *databuf, int offset, void *val, socklen_t vallen)
+{
+
+ /* we can't assume alignment here */
+ memcpy(val, (u_int8_t *)databuf + offset, vallen);
+
+ return(offset + vallen);
+}
diff --git a/lib/libc/net/rthdr.c b/lib/libc/net/rthdr.c
index abfe34a93ad8..d7b0077f606e 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;
- }
}
diff --git a/lib/libsdp/search.c b/lib/libsdp/search.c
index ab495e32115f..c739824abb4d 100644
--- a/lib/libsdp/search.c
+++ b/lib/libsdp/search.c
@@ -29,6 +29,7 @@
* $FreeBSD$
*/
+#include <sys/types.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>