about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rw-r--r--NEWS7
-rw-r--r--inet/Makefile4
-rw-r--r--inet/Versions6
-rw-r--r--inet/inet6_opt.c278
-rw-r--r--inet/inet6_rth.c192
-rw-r--r--inet/netinet/icmp6.h30
-rw-r--r--inet/netinet/in.h61
-rw-r--r--inet/netinet/ip6.h21
9 files changed, 580 insertions, 39 deletions
diff --git a/ChangeLog b/ChangeLog
index 9fc6dc445b..f0555f09e7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
 2006-05-24  Ulrich Drepper  <drepper@redhat.com>
 
+	[BZ #2693]
+	* inet/Makefile (routines): Add inet6_opt and inet6_rth.
+	* inet/Versions (libc, GLIBC_2.5): Add inet6_opt_init,
+	inet6_opt_append, inet6_opt_finish, inet6_opt_set_val, inet6_opt_next,
+	inet6_opt_find, inet6_opt_get_val, inet6_rth_space, inet6_rth_init,
+	inet6_rth_add, inet6_rth_reverse, inet6_rth_segments,
+	and inet6_rth_getaddr.
+	* inet/netinet/ip6.h (struct ip6_rthdr0): Make ip6r0_addr a flexible
+	array.
+	* inet/netinet/in.h (struct ip6_mtuinfo): Define.
+	Mark inet6_option_* interfaces as deprecated.
+	Declare inet6_opt_init, inet6_opt_append, inet6_opt_finish,
+	inet6_opt_set_val, inet6_opt_next, inet6_opt_find, inet6_opt_get_val,
+	inet6_rth_space, inet6_rth_init, inet6_rth_add, inet6_rth_reverse,
+	inet6_rth_segments, and inet6_rth_getaddr.
+	* inet/inet6_opt.c: New file.
+	* inet/inet6_rth.c: New file.
+
+	* inet/netinet/icmp6.h: Pretty printing.
+
 	[BZ #2683]
 	* elf/dl-addr.c (_dl_addr): Don't match undefined references.
 
diff --git a/NEWS b/NEWS
index 006aa2989f..edc576e096 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes.  2006-05-07
+GNU C Library NEWS -- history of user-visible changes.  2006-05-24
 Copyright (C) 1992-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
 See the end for copying conditions.
 
@@ -23,11 +23,14 @@ Version 2.5
   site might have problems with default behavior.
   Implemented by Ulrich Drepper.
 
-* Iterating over entire database in NIS and NIS+ can be slow.  With the
+* Iterating over entire database in NIS can be slow.  With the
   SETENT_BATCH_READ option in /etc/default/nss a system admin can decide
   to trade time for memory.  The entire database will be read at once.
   Implemented by Ulrich Drepper.
 
+* The interfaces introduced in RFC 3542 have been implemented by
+  Ulrich Drepper.
+
 
 Version 2.4
 
diff --git a/inet/Makefile b/inet/Makefile
index 0fdf9e33e4..075716fbeb 100644
--- a/inet/Makefile
+++ b/inet/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1991-2002, 2003, 2004 Free Software Foundation, Inc.
+# Copyright (C) 1991-2002, 2003, 2004, 2006 Free Software Foundation, Inc.
 # This file is part of the GNU C Library.
 
 # The GNU C Library is free software; you can redistribute it and/or
@@ -47,7 +47,7 @@ routines := htonl htons		\
 	    getaliasent_r getaliasent getaliasname getaliasname_r \
 	    in6_addr getnameinfo if_index ifaddrs inet6_option \
 	    getipv4sourcefilter setipv4sourcefilter \
-	    getsourcefilter setsourcefilter
+	    getsourcefilter setsourcefilter inet6_opt inet6_rth
 
 aux := check_pf ifreq
 
diff --git a/inet/Versions b/inet/Versions
index 2b7ec901ff..06507199a9 100644
--- a/inet/Versions
+++ b/inet/Versions
@@ -78,6 +78,12 @@ libc {
     getipv4sourcefilter; setipv4sourcefilter;
     getsourcefilter; setsourcefilter;
   }
+  GLIBC_2.5 {
+    inet6_opt_init; inet6_opt_append; inet6_opt_finish; inet6_opt_set_val;
+    inet6_opt_next; inet6_opt_find; inet6_opt_get_val;
+    inet6_rth_space; inet6_rth_init; inet6_rth_add; inet6_rth_reverse;
+    inet6_rth_segments; inet6_rth_getaddr;
+  }
   GLIBC_PRIVATE {
     # functions used in other libraries
     __internal_endnetgrent; __internal_getnetgrent_r;
diff --git a/inet/inet6_opt.c b/inet/inet6_opt.c
new file mode 100644
index 0000000000..bddb85182b
--- /dev/null
+++ b/inet/inet6_opt.c
@@ -0,0 +1,278 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2006.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+
+/* RFC 3542, 10.1
+
+   This function returns the number of bytes needed for the empty
+   extension header i.e., without any options.  If EXTBUF is not NULL it
+   also initializes the extension header to have the correct length
+   field.  In that case if the EXTLEN value is not a positive (i.e.,
+   non-zero) multiple of 8 the function fails and returns -1.  */
+int
+inet6_opt_init (void *extbuf, socklen_t extlen)
+{
+  if (extbuf != NULL)
+    {
+      if (extlen <= 0 || (extlen % 8) != 0)
+	return -1;
+
+      /* Fill in the length in units of 8 octets.  */
+      struct ip6_hbh *extp = (struct ip6_hbh *) extbuf;
+      extp->ip6h_len = extlen / 8;
+    }
+
+  return sizeof (struct ip6_hbh);
+}
+
+
+static void
+add_padding (uint8_t *extbuf, int offset, int npad)
+{
+  if (npad == 1)
+    extbuf[offset] = IP6OPT_PAD1;
+  else
+    {
+      struct ip6_opt *pad_opt = (struct ip6_opt *) (extbuf + offset);
+
+      pad_opt->ip6o_type = IP6OPT_PADN;
+      pad_opt->ip6o_len = npad - sizeof (struct ip6_opt);
+      /* Clear the memory used by the padding.  */
+      memset (pad_opt + 1, '\0', pad_opt->ip6o_len);
+    }
+}
+
+
+
+/* RFC 3542, 10.2
+
+   This function returns the updated total length taking into account
+   adding an option with length 'len' and alignment 'align'.  If
+   EXTBUF is not NULL then, in addition to returning the length, the
+   function inserts any needed pad option, initializes the option
+   (setting the type and length fields) and returns a pointer to the
+   location for the option content in databufp.  If the option does
+   not fit in the extension header buffer the function returns -1.  */
+int
+inet6_opt_append (void *extbuf, socklen_t extlen, int offset, uint8_t type,
+		  socklen_t len, uint8_t align, void **databufp)
+{
+  /* Check minimum offset.  */
+  if (offset < sizeof (struct ip6_hbh))
+    return -1;
+
+  /* One cannot add padding options.  */
+  if (type == IP6OPT_PAD1 || type == IP6OPT_PADN)
+    return -1;
+
+  /* The option length must fit in one octet.  */
+  if (len > 255)
+    return -1;
+
+  /* The alignment can only by 1, 2, 4, or 8 and must not exceed the
+     option length.  */
+  if (align == 0 || align > 8 || (align & (align - 1)) != 0 || align > len)
+    return -1;
+
+  /* Determine the needed padding for alignment.  Following the
+     current content of the buffer we have the is the IPv6 option type
+     and length, followed immediately by the data.  The data has the
+     alignment constraints.  Therefore padding must be inserted in the
+     form of padding options before the new option. */
+  int data_offset = offset + sizeof (struct ip6_opt);
+  int npad = (align - data_offset % align) & (align - 1);
+
+  /* Now we can check whether the buffer is large enough.  */
+  if (data_offset + npad + len > extlen)
+    return -1;
+
+  if (npad != 0)
+    {
+      if (extbuf != NULL)
+	add_padding (extbuf, offset, npad);
+
+      offset += npad;
+    }
+
+  /* Now prepare the option itself.  */
+  if (extbuf != NULL)
+    {
+      struct ip6_opt *opt = (struct ip6_opt *) ((uint8_t *) extbuf + offset);
+
+      opt->ip6o_type = type;
+      opt->ip6o_len = len;
+
+      *databufp = opt + 1;
+    }
+
+  return offset + sizeof (struct ip6_opt) + len;
+}
+
+
+/* RFC 3542, 10.3
+
+   This function returns the updated total length taking into account
+   the final padding of the extension header to make it a multiple of
+   8 bytes.  If EXTBUF is not NULL the function also initializes the
+   option by inserting a Pad1 or PadN option of the proper length.  */
+int
+inet6_opt_finish (void *extbuf, socklen_t extlen, int offset)
+{
+  /* Check minimum offset.  */
+  if (offset < sizeof (struct ip6_hbh))
+    return -1;
+
+  /* Required padding at the end.  */
+  int npad = (8 - (offset & 7)) & 7;
+
+  /* Make sure the buffer is large enough.  */
+  if (offset + npad > extlen)
+    return -1;
+
+  if (extbuf != NULL)
+    add_padding (extbuf, offset, npad);
+
+  return offset + npad;
+}
+
+
+/* RFC 3542, 10.4
+
+   This function inserts data items of various sizes in the data
+   portion of the option.  VAL should point to the data to be
+   inserted.  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.  */
+int
+inet6_opt_set_val (void *databuf, int offset, void *val, socklen_t vallen)
+{
+  memcpy ((uint8_t *) databuf + offset, val, vallen);
+
+  return offset + vallen;
+}
+
+
+/* RFC 3542, 10.5
+
+   This function parses received option extension headers returning
+   the next option.  EXTBUF and EXTLEN specifies the extension header.
+   OFFSET should either be zero (for the first option) or the length
+   returned by a previous call to 'inet6_opt_next' or
+   'inet6_opt_find'.  It specifies the position where to continue
+   scanning the extension buffer.  */
+int
+inet6_opt_next (void *extbuf, socklen_t extlen, int offset, uint8_t *typep,
+		socklen_t *lenp, void **databufp)
+{
+  if (offset == 0)
+    offset = sizeof (struct ip6_hbh);
+  else if (offset < sizeof (struct ip6_hbh))
+    return -1;
+
+  while (offset < extlen)
+    {
+      struct ip6_opt *opt = (struct ip6_opt *) ((uint8_t *) extbuf + offset);
+
+      if (opt->ip6o_type == IP6OPT_PAD1)
+	/* Single byte padding.  */
+	++offset;
+      else if (opt->ip6o_type == IP6OPT_PADN)
+	offset += sizeof (struct ip6_opt) + opt->ip6o_len;
+      else
+	{
+	  /* Check whether the option is valid.  */
+	  offset += sizeof (struct ip6_opt) + opt->ip6o_len;
+	  if (offset > extlen)
+	    return -1;
+
+	  *typep = opt->ip6o_type;
+	  *lenp = opt->ip6o_len;
+	  *databufp = opt + 1;
+	  return offset;
+	}
+    }
+
+  return -1;
+}
+
+
+/* RFC 3542, 10.6
+
+   This function is similar to the previously described
+   'inet6_opt_next' function, except this function lets the caller
+   specify the option type to be searched for, instead of always
+   returning the next option in the extension header.  */
+int
+inet6_opt_find (void *extbuf, socklen_t extlen, int offset, uint8_t type,
+		socklen_t *lenp, void **databufp)
+{
+  if (offset == 0)
+    offset = sizeof (struct ip6_hbh);
+  else if (offset < sizeof (struct ip6_hbh))
+    return -1;
+
+  while (offset < extlen)
+    {
+      struct ip6_opt *opt = (struct ip6_opt *) ((uint8_t *) extbuf + offset);
+
+      if (opt->ip6o_type == IP6OPT_PAD1)
+	{
+	  /* Single byte padding.  */
+	  ++offset;
+	  if (type == IP6OPT_PAD1)
+	    {
+	      *lenp = 0;
+	      *databufp = (uint8_t *) extbuf + offset;
+	      return offset;
+	    }
+	}
+      else if (opt->ip6o_type != type)
+	offset += sizeof (struct ip6_opt) + opt->ip6o_len;
+      else
+	{
+	  /* Check whether the option is valid.  */
+	  offset += sizeof (struct ip6_opt) + opt->ip6o_len;
+	  if (offset > extlen)
+	    return -1;
+
+	  *lenp = opt->ip6o_len;
+	  *databufp = opt + 1;
+	  return offset;
+	}
+    }
+
+  return -1;
+}
+
+
+/* RFC 3542, 10.7
+
+   This function extracts data items of various sizes in the data
+   portion of the option.  */
+int
+inet6_opt_get_val (void *databuf, int offset, void *val, socklen_t vallen)
+{
+  memcpy (val, (uint8_t *) databuf + offset, vallen);
+
+  return offset + vallen;
+}
diff --git a/inet/inet6_rth.c b/inet/inet6_rth.c
new file mode 100644
index 0000000000..15f8240909
--- /dev/null
+++ b/inet/inet6_rth.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2006.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+
+/* RFC 3542, 7.1
+
+   This function returns the number of bytes required to hold a
+   Routing header of the specified type containing the specified
+   number of segments (addresses).  For an IPv6 Type 0 Routing header,
+   the number of segments must be between 0 and 127, inclusive.  */
+socklen_t
+inet6_rth_space (int type, int segments)
+{
+  switch (type)
+    {
+    case IPV6_RTHDR_TYPE_0:
+      if (segments < 0 || segments > 127)
+	return 0;
+
+      return sizeof (struct ip6_rthdr0) + segments * sizeof (struct in6_addr);
+    }
+
+  return 0;
+}
+
+
+/* RFC 3542, 7.2
+
+   This function initializes the buffer pointed to by BP to contain a
+   Routing header of the specified type and sets ip6r_len based on the
+   segments parameter.  */
+void *
+inet6_rth_init (void *bp, socklen_t bp_len, int type, int segments)
+{
+  struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
+
+  switch (type)
+    {
+    case IPV6_RTHDR_TYPE_0:
+      /* Make sure the parameters are valid and the buffer is large enough.  */
+      if (segments < 0 || segments > 127)
+	break;
+
+      socklen_t len = (sizeof (struct ip6_rthdr0)
+		       + segments * sizeof (struct in6_addr));
+      if (len > bp_len)
+	break;
+
+      /* Some implementations seem to initialize the whole memory area.  */
+      memset (bp, '\0', len);
+
+      /* Length in units of 8 octets.  */
+      rthdr->ip6r_len = segments * sizeof (struct in6_addr) / 8;
+      rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
+      return bp;
+    }
+
+  return NULL;
+}
+
+
+/* RFC 3542, 7.3
+
+   This function adds the IPv6 address pointed to by addr to the end of
+   the Routing header being constructed.  */
+int
+inet6_rth_add (void *bp, const struct in6_addr *addr)
+{
+  struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
+
+  switch (rthdr->ip6r_type)
+    {
+      struct ip6_rthdr0 *rthdr0;
+    case IPV6_RTHDR_TYPE_0:
+      rthdr0 = (struct ip6_rthdr0 *) rthdr;
+
+      memcpy (&rthdr0->ip6r0_addr[rthdr0->ip6r0_segleft++],
+	      addr, sizeof (struct in6_addr));
+
+      return 0;
+    }
+
+  return -1;
+}
+
+
+/* RFC 3542, 7.4
+
+   This function takes a Routing header extension header (pointed to by
+   the first argument) and writes a new Routing header that sends
+   datagrams along the reverse of that route.  The function reverses the
+   order of the addresses and sets the segleft member in the new Routing
+   header to the number of segments.  */
+int
+inet6_rth_reverse (const void *in, void *out)
+{
+  struct ip6_rthdr *in_rthdr = (struct ip6_rthdr *) in;
+
+  switch (in_rthdr->ip6r_type)
+    {
+      struct ip6_rthdr0 *in_rthdr0;
+      struct ip6_rthdr0 *out_rthdr0;
+    case IPV6_RTHDR_TYPE_0:
+      in_rthdr0 = (struct ip6_rthdr0 *) in;
+      out_rthdr0 = (struct ip6_rthdr0 *) out;
+
+      /* Copy header, not the addresses.  The memory regions can overlap.  */
+      memmove (out_rthdr0, in_rthdr0, sizeof (struct ip6_rthdr0));
+
+      int total = in_rthdr0->ip6r0_segleft * 8 / sizeof (struct in6_addr);
+      for (int i = 0; i < total / 2; ++i)
+	{
+	  /* Remember, IN_RTHDR0 and OUT_RTHDR0 might overlap.  */
+	  struct in6_addr temp = in_rthdr0->ip6r0_addr[i];
+	  out_rthdr0->ip6r0_addr[i] = in_rthdr0->ip6r0_addr[total - 1 - i];
+	  out_rthdr0->ip6r0_addr[total - 1 - i] = temp;
+	}
+      if (total % 2 != 0 && in != out)
+	out_rthdr0->ip6r0_addr[total / 2] = in_rthdr0->ip6r0_addr[total / 2];
+
+      return 0;
+    }
+
+  return -1;
+}
+
+
+/* RFC 3542, 7.5
+
+   This function returns the number of segments (addresses) contained in
+   the Routing header described by BP.  */
+int
+inet6_rth_segments (const void *bp)
+{
+  struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
+
+  switch (rthdr->ip6r_type)
+    {
+    case IPV6_RTHDR_TYPE_0:
+
+      return rthdr->ip6r_len * 8 / sizeof (struct in6_addr);
+    }
+
+  return -1;
+}
+
+
+/* RFC 3542, 7.6
+
+   This function returns a pointer to the IPv6 address specified by
+   index (which must have a value between 0 and one less than the
+   value returned by 'inet6_rth_segments') in the Routing header
+   described by BP.  */
+struct in6_addr *
+inet6_rth_getaddr (const void *bp, int index)
+{
+  struct ip6_rthdr *rthdr = (struct ip6_rthdr *) bp;
+
+  switch (rthdr->ip6r_type)
+    {
+       struct ip6_rthdr0 *rthdr0;
+    case IPV6_RTHDR_TYPE_0:
+      rthdr0 = (struct ip6_rthdr0 *) rthdr;
+
+      if (index >= rthdr0->ip6r0_len * 8 / sizeof (struct in6_addr))
+	break;
+
+      return &rthdr0->ip6r0_addr[index];
+    }
+
+  return NULL;
+}
diff --git a/inet/netinet/icmp6.h b/inet/netinet/icmp6.h
index c5138a39c9..0cb1aa6a6c 100644
--- a/inet/netinet/icmp6.h
+++ b/inet/netinet/icmp6.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991,92,93,94,95,96,97,2000 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1997,2000,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -191,13 +191,13 @@ struct nd_opt_hdr             /* Neighbor discovery option header */
     /* followed by option specific data */
   };
 
-#define  ND_OPT_SOURCE_LINKADDR       1
-#define  ND_OPT_TARGET_LINKADDR       2
-#define  ND_OPT_PREFIX_INFORMATION    3
-#define  ND_OPT_REDIRECTED_HEADER     4
-#define  ND_OPT_MTU                   5
-#define  ND_OPT_RTR_ADV_INTERVAL      7
-#define  ND_OPT_HOME_AGENT_INFO       8
+#define ND_OPT_SOURCE_LINKADDR		1
+#define ND_OPT_TARGET_LINKADDR		2
+#define ND_OPT_PREFIX_INFORMATION	3
+#define ND_OPT_REDIRECTED_HEADER	4
+#define ND_OPT_MTU			5
+#define ND_OPT_RTR_ADV_INTERVAL		7
+#define ND_OPT_HOME_AGENT_INFO		8
 
 struct nd_opt_prefix_info     /* prefix information */
   {
@@ -211,9 +211,9 @@ struct nd_opt_prefix_info     /* prefix information */
     struct in6_addr  nd_opt_pi_prefix;
   };
 
-#define ND_OPT_PI_FLAG_ONLINK        0x80
-#define ND_OPT_PI_FLAG_AUTO          0x40
-#define ND_OPT_PI_FLAG_RADDR         0x20
+#define ND_OPT_PI_FLAG_ONLINK	0x80
+#define ND_OPT_PI_FLAG_AUTO	0x40
+#define ND_OPT_PI_FLAG_RADDR	0x20
 
 struct nd_opt_rd_hdr          /* redirected header */
   {
@@ -300,11 +300,11 @@ struct rr_pco_use      /* use prefix part */
 #define ICMP6_RR_PCOUSE_RAFLAGS_AUTO    0x10
 
 #if BYTE_ORDER == BIG_ENDIAN
-# define ICMP6_RR_PCOUSE_DECRVLTIME      0x80000000
-# define ICMP6_RR_PCOUSE_DECRPLTIME      0x40000000
+# define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80000000
+# define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40000000
 #elif BYTE_ORDER == LITTLE_ENDIAN
-# define ICMP6_RR_PCOUSE_DECRVLTIME      0x80
-# define ICMP6_RR_PCOUSE_DECRPLTIME      0x40
+# define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80
+# define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40
 #endif
 
 struct rr_result       /* router renumbering result message */
diff --git a/inet/netinet/in.h b/inet/netinet/in.h
index 8898be3664..4fdc0fadf1 100644
--- a/inet/netinet/in.h
+++ b/inet/netinet/in.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-2001, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2001, 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -455,25 +455,66 @@ extern int bindresvport6 (int __sockfd, struct sockaddr_in6 *__sock_in)
 /* IPv6 packet information.  */
 struct in6_pktinfo
   {
-    struct in6_addr	ipi6_addr;    /* src/dst IPv6 address */
-    unsigned int	ipi6_ifindex; /* send/recv interface index */
+    struct in6_addr ipi6_addr;	/* src/dst IPv6 address */
+    unsigned int ipi6_ifindex;	/* send/recv interface index */
+  };
+
+/* IPv6 MTU information.  */
+struct ip6_mtuinfo
+  {
+    struct sockaddr_in6 ip6m_addr; /* dst address including zone ID */
+    uint32_t ip6m_mtu;		   /* path MTU in host byte order */
   };
 
 
 #ifdef __USE_GNU
-/* Hop-by-Hop and Destination Options Processing.  */
-extern int inet6_option_space (int __nbytes) __THROW;
+/* Obsolete hop-by-hop and Destination Options Processing (RFC 2292).  */
+extern int inet6_option_space (int __nbytes)
+     __THROW __attribute_deprecated__;
 extern int inet6_option_init (void *__bp, struct cmsghdr **__cmsgp,
-			      int __type) __THROW;
+			      int __type) __THROW __attribute_deprecated__;
 extern int inet6_option_append (struct cmsghdr *__cmsg,
 				__const uint8_t *__typep, int __multx,
-				int __plusy) __THROW;
+				int __plusy) __THROW __attribute_deprecated__;
 extern uint8_t *inet6_option_alloc (struct cmsghdr *__cmsg, int __datalen,
-				    int __multx, int __plusy) __THROW;
+				    int __multx, int __plusy)
+     __THROW __attribute_deprecated__;
 extern int inet6_option_next (__const struct cmsghdr *__cmsg,
-			      uint8_t **__tptrp) __THROW;
+			      uint8_t **__tptrp)
+     __THROW __attribute_deprecated__;
 extern int inet6_option_find (__const struct cmsghdr *__cmsg,
-			      uint8_t **__tptrp, int __type) __THROW;
+			      uint8_t **__tptrp, int __type)
+     __THROW __attribute_deprecated__;
+
+
+/* Hop-by-Hop and Destination Options Processing (RFC 3542).  */
+extern int inet6_opt_init (void *__extbuf, socklen_t __extlen) __THROW;
+extern int inet6_opt_append (void *__extbuf, socklen_t __extlen, int __offset,
+			     uint8_t __type, socklen_t __len, uint8_t __align,
+			     void **__databufp) __THROW;
+extern int inet6_opt_finish (void *__extbuf, socklen_t __extlen, int __offset)
+     __THROW;
+extern int inet6_opt_set_val (void *__databuf, int __offset, void *__val,
+			      socklen_t __vallen) __THROW;
+extern int inet6_opt_next (void *__extbuf, socklen_t __extlen, int __offset,
+			   uint8_t *__typep, socklen_t *__lenp,
+			   void **__databufp) __THROW;
+extern int inet6_opt_find (void *__extbuf, socklen_t __extlen, int __offset,
+			   uint8_t __type, socklen_t *__lenp,
+			   void **__databufp) __THROW;
+extern int inet6_opt_get_val (void *__databuf, int __offset, void *__val,
+			      socklen_t __vallen) __THROW;
+
+
+/* Routing Header Option (RFC 3542).  */
+extern socklen_t inet6_rth_space (int __type, int __segments) __THROW;
+extern void *inet6_rth_init (void *__bp, socklen_t __bp_len, int __type,
+			     int __segments) __THROW;
+extern int inet6_rth_add (void *__bp, __const struct in6_addr *__addr) __THROW;
+extern int inet6_rth_reverse (__const void *__in, void *__out) __THROW;
+extern int inet6_rth_segments (__const void *__bp) __THROW;
+extern struct in6_addr *inet6_rth_getaddr (__const void *__bp, int __index)
+     __THROW;
 
 
 /* Multicast source filter support.  */
diff --git a/inet/netinet/ip6.h b/inet/netinet/ip6.h
index 0ad62f8980..bef2af2f5a 100644
--- a/inet/netinet/ip6.h
+++ b/inet/netinet/ip6.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-1997, 2001, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1997, 2001, 2003, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -89,7 +89,8 @@ struct ip6_rthdr0
     uint8_t  ip6r0_segleft;	/* segments left */
     uint8_t  ip6r0_reserved;	/* reserved field */
     uint8_t  ip6r0_slmap[3];	/* strict/loose bit map */
-    struct in6_addr  ip6r0_addr[1];  /* up to 23 addresses */
+    /* followed by up to 127 struct in6_addr */
+    struct in6_addr ip6r0_addr[0];
   };
 
 /* Fragment header */
@@ -101,14 +102,14 @@ struct ip6_frag
     uint32_t  ip6f_ident;	/* identification */
   };
 
-#if     BYTE_ORDER == BIG_ENDIAN
-#define IP6F_OFF_MASK       0xfff8  /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK  0x0006  /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG      0x0001  /* more-fragments flag */
+#if BYTE_ORDER == BIG_ENDIAN
+# define IP6F_OFF_MASK       0xfff8  /* mask out offset from _offlg */
+# define IP6F_RESERVED_MASK  0x0006  /* reserved bits in ip6f_offlg */
+# define IP6F_MORE_FRAG      0x0001  /* more-fragments flag */
 #else   /* BYTE_ORDER == LITTLE_ENDIAN */
-#define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
+# define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
+# define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
+# define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
 #endif
 
 /* IPv6 options */
@@ -175,7 +176,7 @@ struct ip6_opt_router
   };
 
 /* Router alert values (in network byte order) */
-#if     BYTE_ORDER == BIG_ENDIAN
+#if BYTE_ORDER == BIG_ENDIAN
 # define IP6_ALERT_MLD	0x0000
 # define IP6_ALERT_RSVP	0x0001
 # define IP6_ALERT_AN	0x0002