summaryrefslogtreecommitdiffstats
path: root/lib/libc/net/ip6opt.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/net/ip6opt.c')
-rw-r--r--lib/libc/net/ip6opt.c227
1 files changed, 227 insertions, 0 deletions
diff --git a/lib/libc/net/ip6opt.c b/lib/libc/net/ip6opt.c
index a26e45d..2f54918 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);
+}
OpenPOWER on IntegriCloud