]> git.saurik.com Git - apple/libinfo.git/blobdiff - gen.subproj/ip6opt.c
Libinfo-391.tar.gz
[apple/libinfo.git] / gen.subproj / ip6opt.c
index 0dd526477986f0524c9259eed2eedf32be66034f..10d36b19a1121480f739cb06f51cecc696be2ea7 100644 (file)
@@ -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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libc/net/ip6opt.c,v 1.1 1999/12/16 18:32:01 shin Exp $
+ * $FreeBSD: src/lib/libc/net/ip6opt.c,v 1.8.10.2.2.1 2010/06/14 02:09:06 kensmith Exp $
+ */
+
+/*
+ * These routines support RFC 3542
+ * __APPLE_USE_RFC_3542 selects the appropriate API in <netinet6/in6.h>
  */
+#define __APPLE_USE_RFC_3542
+
+#include <sys/cdefs.h>
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -52,8 +62,7 @@ static void inet6_insert_padopt(u_char *p, int len);
  * byte, the length byte, and the option data.
  */
 int
-inet6_option_space(nbytes)
-       int nbytes;
+inet6_option_space(int nbytes)
 {
        nbytes += 2;    /* we need space for nxt-hdr and length fields */
        return(CMSG_SPACE((nbytes + 7) & ~7));
@@ -65,12 +74,9 @@ inet6_option_space(nbytes)
  * success or -1 on an error.
  */
 int
-inet6_option_init(bp, cmsgp, type)
-       void *bp;
-       struct cmsghdr **cmsgp;
-       int type;
+inet6_option_init(void *bp, struct cmsghdr **cmsgp, int type)
 {
-       register struct cmsghdr *ch = (struct cmsghdr *)bp;
+       struct cmsghdr *ch = (struct cmsghdr *)bp;
 
        /* argument validation */
        if (type != IPV6_HOPOPTS && type != IPV6_DSTOPTS)
@@ -95,14 +101,11 @@ inet6_option_init(bp, cmsgp, type)
  * earlier.  It must have a value between 0 and 7, inclusive.
  */
 int
-inet6_option_append(cmsg, typep, multx, plusy)
-       struct cmsghdr *cmsg;
-       const u_int8_t *typep;
-       int multx;
-       int plusy;
+inet6_option_append(struct cmsghdr *cmsg, const u_int8_t *typep, int multx,
+    int plusy)
 {
        int padlen, optlen, off;
-       register u_char *bp = (u_char *)cmsg + cmsg->cmsg_len;
+       u_char *bp = (u_char *)cmsg + cmsg->cmsg_len;
        struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg);
 
        /* argument validation */
@@ -126,6 +129,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;
@@ -167,14 +171,10 @@ inet6_option_append(cmsg, typep, multx, plusy)
  * 
  */
 u_int8_t *
-inet6_option_alloc(cmsg, datalen, multx, plusy)
-       struct cmsghdr *cmsg;
-       int datalen;
-       int multx;
-       int plusy;
+inet6_option_alloc(struct cmsghdr *cmsg, int datalen, int multx, int plusy)
 {
        int padlen, off;
-       register u_int8_t *bp = (u_char *)cmsg + cmsg->cmsg_len;
+       u_int8_t *bp = (u_char *)cmsg + cmsg->cmsg_len;
        u_int8_t *retval;
        struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg);
 
@@ -199,6 +199,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;
@@ -233,9 +234,7 @@ inet6_option_alloc(cmsg, datalen, multx, plusy)
  * (RFC 2292, 6.3.5)
  */
 int
-inet6_option_next(cmsg, tptrp)
-       const struct cmsghdr *cmsg;
-       u_int8_t **tptrp;
+inet6_option_next(const struct cmsghdr *cmsg, u_int8_t **tptrp)
 {
        struct ip6_ext *ip6e;
        int hdrlen, optlen;
@@ -291,10 +290,7 @@ inet6_option_next(cmsg, tptrp)
  *       it's a typo. The variable should be type of u_int8_t **.
  */
 int
-inet6_option_find(cmsg, tptrp, type)
-       const struct cmsghdr *cmsg;
-       u_int8_t **tptrp;
-       int type;
+inet6_option_find(const struct cmsghdr *cmsg, u_int8_t **tptrp, int type)
 {
        struct ip6_ext *ip6e;
        int hdrlen, optlen;
@@ -347,8 +343,7 @@ inet6_option_find(cmsg, tptrp, type)
  * calculated length and the limitation of the buffer.
  */
 static int
-ip6optlen(opt, lim)
-       u_int8_t *opt, *lim;
+ip6optlen(u_int8_t *opt, u_int8_t *lim)
 {
        int optlen;
 
@@ -382,3 +377,219 @@ inet6_insert_padopt(u_char *p, int len)
                 return;
        }
 }
+
+/*
+ * The following functions are defined in RFC3542, which is a successor
+ * of RFC2292.
+ */
+
+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) {
+               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)
+               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 > 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, 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 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);
+}