Ripngd part of 6Wind patch.
diff --git a/ripngd/ripng_nexthop.c b/ripngd/ripng_nexthop.c
new file mode 100644
index 0000000..2c5d45c
--- /dev/null
+++ b/ripngd/ripng_nexthop.c
@@ -0,0 +1,216 @@
+/* RIPngd Zebra
+ * Copyright (C) 2002 6WIND <vincent.jardin@6wind.com>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+/* This file is required in order to support properly the RIPng nexthop
+ * feature.
+ */
+
+#include <zebra.h>
+
+/* For struct udphdr. */
+#include <netinet/udp.h>
+
+#include "linklist.h"
+#include "stream.h"
+#include "log.h"
+#include "memory.h"
+#include "vty.h"
+#include "if.h"
+#include "prefix.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_debug.h"
+#include "ripngd/ripng_nexthop.h"
+
+#define DEBUG 1
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+struct ripng_rte_data {
+  struct prefix_ipv6 *p;
+  struct ripng_info *rinfo;
+  struct ripng_aggregate *aggregate;
+};
+
+void _ripng_rte_del(struct ripng_rte_data *A);
+int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B);
+
+#define METRIC_OUT(a) \
+    (a->rinfo ?  a->rinfo->metric_out : a->aggregate->metric_out)
+#define NEXTHOP_OUT(a) \
+    (a->rinfo ?  a->rinfo->nexthop_out : a->aggregate->nexthop_out)
+#define TAG_OUT(a) \
+    (a->rinfo ?  a->rinfo->tag_out : a->aggregate->tag_out)
+
+struct list *
+ripng_rte_new(void) {
+  struct list *rte;
+
+  rte = list_new();
+  rte->cmp = (int (*)(void *, void *)) _ripng_rte_cmp;
+  rte->del = (void (*)(void *)) _ripng_rte_del;
+
+  return rte;
+}
+
+void
+ripng_rte_free(struct list *ripng_rte_list) {
+  list_delete(ripng_rte_list);
+}
+
+/* Delete RTE */
+void
+_ripng_rte_del(struct ripng_rte_data *A) {
+  XFREE(MTYPE_RIPNG_RTE_DATA, A);
+}
+
+/* Compare RTE:
+ *  return +  if A > B
+ *         0  if A = B
+ *         -  if A < B
+ */
+int
+_ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B) {
+  return addr6_cmp(&NEXTHOP_OUT(A), &NEXTHOP_OUT(B));
+}
+
+/* Add routing table entry */
+void
+ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p,
+              struct ripng_info *rinfo, struct ripng_aggregate *aggregate) {
+
+  struct ripng_rte_data *data;
+
+  /* At least one should not be null */
+  assert(!rinfo || !aggregate);
+
+  data = XMALLOC(MTYPE_RIPNG_RTE_DATA, sizeof(*data));
+  data->p     = p;
+  data->rinfo = rinfo;
+  data->aggregate = aggregate;
+
+  listnode_add_sort(ripng_rte_list, data);
+} 
+
+/* Send the RTE with the nexthop support
+ */
+void
+ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp,
+               struct sockaddr_in6 *to) {
+
+  struct ripng_rte_data *data;
+  struct listnode * nn;
+
+  struct in6_addr last_nexthop;
+  struct in6_addr myself_nexthop;
+
+  struct stream *s;
+  int num;
+  int mtu;
+  int rtemax;
+  int ret;
+
+  /* Most of the time, there is no nexthop */
+  memset(&last_nexthop, 0, sizeof(last_nexthop));
+
+  /* Use myself_nexthop if the nexthop is not a link-local address, because
+   * we remain a right path without beeing the optimal one.
+   */
+  memset(&myself_nexthop, 0, sizeof(myself_nexthop));
+
+  /* Output stream get from ripng structre.  XXX this should be
+     interface structure. */
+  s = ripng->obuf;
+
+  /* Reset stream and RTE counter. */
+  stream_reset (s);
+  num = 0;
+
+  mtu = ifp->mtu;
+  if (mtu < 0)
+    mtu = IFMINMTU;
+
+  rtemax = (min (mtu, RIPNG_MAX_PACKET_SIZE) -
+	    IPV6_HDRLEN - 
+	    sizeof (struct udphdr) -
+	    sizeof (struct ripng_packet) +
+	    sizeof (struct rte)) / sizeof (struct rte);
+
+  LIST_LOOP(ripng_rte_list, data, nn) {
+
+    /* (2.1) Next hop support */
+    if (!IPV6_ADDR_SAME(&last_nexthop, &NEXTHOP_OUT(data))) {
+
+      /* A nexthop entry should be at least followed by 1 RTE */
+      if (num == (rtemax-1)) {
+	ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
+				 to, ifp);
+
+        if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
+          ripng_packet_dump((struct ripng_packet *)STREAM_DATA (s),
+			    stream_get_endp(s), "SEND");
+        num = 0;
+        stream_reset (s);
+      }
+
+      /* Add the nexthop (2.1) */
+
+      /* If the received next hop address is not a link-local address,
+       * it should be treated as 0:0:0:0:0:0:0:0.
+       */
+      if (!IN6_IS_ADDR_LINKLOCAL(&NEXTHOP_OUT(data)))
+        last_nexthop = myself_nexthop;
+      else
+	last_nexthop = NEXTHOP_OUT(data);
+
+      num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP);
+    } else {
+      /* Rewrite the nexthop for each new packet */
+      if ((num == 0) && !IPV6_ADDR_SAME(&last_nexthop, &myself_nexthop))
+        num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP);
+    }
+    num = ripng_write_rte(num, s, data->p, NULL,
+			  TAG_OUT(data), METRIC_OUT(data));
+
+    if (num == rtemax) {
+      ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
+			       to, ifp);
+
+      if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
+        ripng_packet_dump((struct ripng_packet *)STREAM_DATA (s),
+			  stream_get_endp(s), "SEND");
+      num = 0;
+      stream_reset (s);
+    }
+  }
+
+  /* If unwritten RTE exist, flush it. */
+  if (num != 0) {
+    ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
+			     to, ifp);
+
+    if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
+      ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
+			 stream_get_endp (s), "SEND");
+    num = 0;
+    stream_reset (s);
+  }
+}