Add implementations of the inet6_opt* and inet6_rth* functions (RFC3542).
authorHasso Tepper <hasso@dragonflybsd.org>
Tue, 29 May 2007 10:58:11 +0000 (10:58 +0000)
committerHasso Tepper <hasso@dragonflybsd.org>
Tue, 29 May 2007 10:58:11 +0000 (10:58 +0000)
The patch brings in the part of the RFC3542 API we already have declared
in the sys/netinet6/in6.h, but implementations were missing which confuses
third party apps.

As IPv6 Routing Header Type 0 is already in the way to deprecation (see
draft-ietf-ipv6-deprecate-rh0-00.txt for details), handling of these is
removed from inet6_rth* functions.

Obtained-from: KAME

lib/libc/net/ip6opt.c
lib/libc/net/rthdr.c
sys/netinet6/in6.h

index 5728b34..938c73f 100644 (file)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libc/net/ip6opt.c,v 1.1 1999/12/16 18:32:01 shin Exp $
- * $DragonFly: src/lib/libc/net/ip6opt.c,v 1.5 2006/07/08 01:04:28 swildner Exp $
+ * $DragonFly: src/lib/libc/net/ip6opt.c,v 1.6 2007/05/29 10:58:11 hasso Exp $
  */
 
 #include <sys/param.h>
@@ -366,3 +366,225 @@ 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) {
+               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 0 /* always false */
+       if (type < 2 || type > 255)
+#else
+       if (type < 2)
+#endif
+               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,
+              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);
+}
index 6760049..8e673e4 100644 (file)
@@ -29,7 +29,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libc/net/rthdr.c,v 1.2.2.1 2002/04/28 05:40:24 suz Exp $
- * $DragonFly: src/lib/libc/net/rthdr.c,v 1.4 2005/11/13 02:04:47 swildner Exp $
+ * $DragonFly: src/lib/libc/net/rthdr.c,v 1.5 2007/05/29 10:58:11 hasso Exp $
  */
 
 #include <sys/param.h>
@@ -296,3 +296,44 @@ inet6_rthdr_getflags(const struct cmsghdr *cmsg, int idx)
        return -1;
     }
 }
+
+/*
+ * RFC3542 (2292bis) API
+ */
+
+socklen_t
+inet6_rth_space(int type __unused, int segments __unused)
+{
+       return (0);     /* type not suppported */
+}
+
+void *
+inet6_rth_init(void *bp __unused, socklen_t bp_len __unused, int type __unused,
+              int segments __unused)
+{
+       return (NULL);  /* type not supported */
+}
+
+int
+inet6_rth_add(void *bp __unused, const struct in6_addr *addr __unused)
+{
+       return (-1);    /* type not supported */
+}
+
+int
+inet6_rth_reverse(const void *in __unused, void *out __unused)
+{
+       return (-1);    /* type not supported */
+}
+
+int
+inet6_rth_segments(const void *bp __unused)
+{
+       return (-1);    /* type not supported */
+}
+
+struct in6_addr *
+inet6_rth_getaddr(const void *bp __unused, int idx __unused)
+{
+       return (NULL);  /* type not supported */
+}
index 7c6d54f..618d3c1 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/in6.h,v 1.7.2.7 2002/08/01 19:38:50 ume Exp $        */
-/*     $DragonFly: src/sys/netinet6/in6.h,v 1.8 2006/11/03 00:54:55 hsu Exp $  */
+/*     $DragonFly: src/sys/netinet6/in6.h,v 1.9 2007/05/29 10:58:11 hasso Exp $        */
 /*     $KAME: in6.h,v 1.89 2001/05/27 13:28:35 itojun Exp $    */
 
 /*
 #define __KAME__
 #define __KAME_VERSION         "20010528/FreeBSD"
 
+#ifndef _SOCKLEN_T_DECLARED
+#define _SOCKLEN_T_DECLARED
+typedef __socklen_t    socklen_t;
+#endif
+
 /*
  * Local port number conventions:
  *
@@ -603,20 +608,20 @@ int inet6_option_init (void *, struct cmsghdr **, int);
 int inet6_option_next (const struct cmsghdr *, uint8_t **);
 int inet6_option_space (int);
 
-int inet6_opt_append (void *, size_t, int, uint8_t, size_t, uint8_t, void **);
-int inet6_opt_find (void *, size_t, int, uint8_t, size_t *, void **);
-int inet6_opt_finish (void *, size_t, int);
-int inet6_opt_get_val (void *, size_t, void *, int);
-int inet6_opt_init (void *, size_t);
-int inet6_opt_next (void *, size_t, int, uint8_t *, size_t *, void **);
-int inet6_opt_set_val (void *, size_t, void *, int);
+int inet6_opt_append (void *, socklen_t, int, uint8_t, size_t, uint8_t, void **);
+int inet6_opt_find (void *, socklen_t, int, uint8_t, size_t *, void **);
+int inet6_opt_finish (void *, socklen_t, int);
+int inet6_opt_get_val (void *, int, void *, socklen_t);
+int inet6_opt_init (void *, socklen_t);
+int inet6_opt_next (void *, socklen_t, int, uint8_t *, socklen_t *, void **);
+int inet6_opt_set_val (void *, int, void *, socklen_t);
 
 int             inet6_rth_add (void *, const struct in6_addr *);
 struct in6_addr *inet6_rth_getaddr (const void *, int);
-void           *inet6_rth_init (void *, int, int, int);
+void           *inet6_rth_init (void *, socklen_t, int, int);
 int             inet6_rth_reverse (const void *, void *);
 int             inet6_rth_segments (const void *);
-size_t          inet6_rth_space (int, int);
+socklen_t       inet6_rth_space (int, int);
 
 int             inet6_rthdr_add (struct cmsghdr *, const struct in6_addr *,
                                  unsigned int);