[PATCH] Add implementations of the inet6_opt* and inet6_rth* functions (RFC3542)

Hasso Tepper hasso at estpak.ee
Thu May 24 23:21:57 PDT 2007


On Thursday 24 May 2007 Hasso Tepper wrote:
> On Thursday 24 May 2007 Simon 'corecode' Schubert wrote:
> > In the prospect of recnet RTH0 issues, does it make any sense to
> > support this?  It should be dropped by every implementation anyways. 
> 
> Yes, I thought about that. But thought also that it would make sense
> to wait clear consensus from IETF and KAME. Although I have see no way
> Routing Header Type 0 coming back. API itself should remain anyway,
> only IPV6_RTHDR_TYPE_0 handling should be removed. 

After fourth and fifth thought, there is updated patch.


-- 
Hasso Tepper
# HG changeset patch
# User Hasso Tepper <hasso at estpak.ee>
# Date 1180062764 -10800
# Node ID d2605333a3e3919c0cb85ab0b4451f078bf9015b
# Parent  a362d641c6d4dc87fc3bb121fe970825ae67ad4d
Add implementations of the inet6_opt* and inet6_rth* functions (RFC3542).

The patch brings in the part of the RFC3542 API we already have defined.
But implementations were missing which confuses third party apps. Note,
that this doesn't complete RFC3542 API, socket options are still missing.
I'm going to work on this probably unless someone stops me.

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

diff -r a362d641c6d4 -r d2605333a3e3 lib/libc/net/ip6opt.c
--- a/lib/libc/net/ip6opt.c	Wed May 23 21:42:13 2007 +0300
+++ b/lib/libc/net/ip6opt.c	Fri May 25 06:12:44 2007 +0300
@@ -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);
+}
diff -r a362d641c6d4 -r d2605333a3e3 lib/libc/net/rthdr.c
--- a/lib/libc/net/rthdr.c	Wed May 23 21:42:13 2007 +0300
+++ b/lib/libc/net/rthdr.c	Fri May 25 06:12:44 2007 +0300
@@ -296,3 +296,44 @@ inet6_rthdr_getflags(const struct cmsghd
 	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 */
+}
diff -r a362d641c6d4 -r d2605333a3e3 sys/netinet6/in6.h
--- a/sys/netinet6/in6.h	Wed May 23 21:42:13 2007 +0300
+++ b/sys/netinet6/in6.h	Fri May 25 06:12:44 2007 +0300
@@ -80,6 +80,11 @@
  */
 #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_next (const struct cmsg
 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);




More information about the Submit mailing list