OK, here it is - irdp support. But don't expect me to fix any bugs in it.
diff --git a/configure.ac b/configure.ac
index 0387654..0ea64b9 100755
--- a/configure.ac
+++ b/configure.ac
@@ -5,7 +5,7 @@
 ##  Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
 ##  Portions Copyright (c) 2003 Paul Jakma <paul@dishone.st>
 ##
-## $Id: configure.ac,v 1.51 2004/05/11 10:49:35 paul Exp $
+## $Id: configure.ac,v 1.52 2004/06/12 14:33:05 hasso Exp $
 AC_PREREQ(2.53)
 
 AC_INIT(quagga, 0.96.5, [http://bugzilla.quagga.net])
@@ -125,6 +125,8 @@
 
 AC_ARG_ENABLE(rtadv,
 [  --disable-rtadv         disable IPV6 router advertisement feature])
+AC_ARG_ENABLE(irdp,
+[  --enable-irdp           enable IRDP server support in zebra])
 AC_ARG_ENABLE(capabilities,
 [  --disable-capabilities        disable using POSIX capabilities])
 
@@ -163,6 +165,10 @@
   AC_MSG_RESULT(no)
 fi
 
+if test "${enable_irdp}" = "yes"; then
+  AC_DEFINE(HAVE_IRDP,, IRDP )
+fi
+
 if test "${enable_user}" = "yes" || test x"${enable_user}" = x""; then
   enable_user="quagga"
 elif test "${enable_user}" = "no"; then
diff --git a/lib/memory.h b/lib/memory.h
index 96b5f6c..40081fe 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -38,6 +38,7 @@
   MTYPE_VTY_HIST,
   MTYPE_VTY_OUT_BUF,
   MTYPE_IF,
+  MTYPE_IF_IRDP,
   MTYPE_CONNECTED,
   MTYPE_AS_SEG,
   MTYPE_AS_STR,
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index 04619ae..da3210e 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,3 +1,7 @@
+2004-06-12 Robert Olsson <Robert.Olsson at data.slu.se>
+
+        * Added IRDP support.
+
 2004-05-18 Hasso Tepper <hasso@estpak.ee>
 
 	* rtadv.c: Removed "[no] ipv6 nd send-ra" command. Replaced "ipv6 nd
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
index 61fdaea..6b494e7 100644
--- a/zebra/Makefile.am
+++ b/zebra/Makefile.am
@@ -23,11 +23,12 @@
 
 zebra_SOURCES = \
 	zserv.c main.c interface.c connected.c zebra_rib.c \
-	redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c
+	redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \
+	irdp_main.c irdp_interface.c irdp_packet.c
 
 noinst_HEADERS = \
 	connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \
-	interface.h ipforward.h
+	interface.h ipforward.h irdp.h
 
 zebra_LDADD = ../lib/libzebra.a $(otherobj) $(LIBCAP) $(LIB_IPV6)
 
diff --git a/zebra/interface.c b/zebra/interface.c
index 748bf00..3a7a591 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -39,6 +39,7 @@
 #include "zebra/zserv.h"
 #include "zebra/redistribute.h"
 #include "zebra/debug.h"
+#include "zebra/irdp.h"
 
 /* Allocate a new internal interface index 
  * This works done from the top so that %d macros
@@ -1419,6 +1420,10 @@
       rtadv_config_write (vty, ifp);
 #endif /* RTADV */
 
+#ifdef HAVE_IRDP
+      irdp_config_write (vty, ifp);
+#endif /* IRDP */
+
       vty_out (vty, "!%s", VTY_NEWLINE);
     }
   return 0;
diff --git a/zebra/interface.h b/zebra/interface.h
index 3ab624f..c1f9f71 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -19,6 +19,10 @@
  * 02111-1307, USA.  
  */
 
+#ifdef HAVE_IRDP
+#include "zebra/irdp.h"
+#endif
+
 /* For interface multicast configuration. */
 #define IF_ZEBRA_MULTICAST_UNSPEC 0
 #define IF_ZEBRA_MULTICAST_ON     1
@@ -153,6 +157,11 @@
 #ifdef RTADV
   struct rtadvconf rtadv;
 #endif /* RTADV */
+
+#ifdef HAVE_IRDP
+  struct irdp_interface irdp;
+#endif
+
 };
 
 void if_delete_update (struct interface *ifp);
diff --git a/zebra/irdp.h b/zebra/irdp.h
index 0fad581..2bf17f0 100644
--- a/zebra/irdp.h
+++ b/zebra/irdp.h
@@ -19,6 +19,19 @@
  * 02111-1307, USA.  
  */
 
+/* 
+ * This file is modified and completed for the Zebra IRDP implementation
+ * by Robert Olsson, Swedish University of Agricultural Sciences
+ */
+
+#ifndef _IRDP_H
+#define _IRDP_H
+
+#include "lib/vty.h"
+
+#define TRUE 1
+#define FALSE 0
+
 /* ICMP Messages */
 #ifndef ICMP_ROUTERADVERT
 #define ICMP_ROUTERADVERT 9
@@ -30,17 +43,36 @@
 
 /* Multicast groups */
 #ifndef INADDR_ALLHOSTS_GROUP
-#define INADDR_ALLHOSTS_GROUP 0xe0000001    /* 224.0.0.1 */
+#define INADDR_ALLHOSTS_GROUP 0xe0000001U    /* 224.0.0.1 */
 #endif /* INADDR_ALLHOSTS_GROUP */
 
 #ifndef INADDR_ALLRTRS_GROUP
-#define INADDR_ALLRTRS_GROUP  0xe0000002    /* 224.0.0.2 */
+#define INADDR_ALLRTRS_GROUP  0xe0000002U    /* 224.0.0.2 */
 #endif /* INADDR_ALLRTRS_GROUP */
 
-/* Comments comes from RFC1256 ICMP Router Discovery Messages. */
-struct irdp_router_interface 
-{
-  /* The IP destination address to be used for multicast Router
+/* Default irdp packet interval */
+#define IRDP_DEFAULT_INTERVAL 300 
+
+/* Router constants from RFC1256 */
+#define MAX_INITIAL_ADVERT_INTERVAL 16
+#define MAX_INITIAL_ADVERTISEMENTS   3
+#define MAX_RESPONSE_DELAY           2
+
+#define IRDP_MAXADVERTINTERVAL 600
+#define IRDP_MINADVERTINTERVAL 450 /* 0.75*600 */
+#define IRDP_LIFETIME         1350 /* 3*450 */
+#define IRDP_PREFERENCE 0
+
+#define ICMP_MINLEN 8
+
+#define IRDP_LAST_ADVERT_MESSAGES 2 /* The last adverts with Holdtime 0 */
+
+#define IRDP_RX_BUF 1500
+
+/* 
+     Comments comes from RFC1256 ICMP Router Discovery Messages. 
+
+     The IP destination address to be used for multicast Router
      Advertisements sent from the interface.  The only permissible
      values are the all-systems multicast address, 224.0.0.1, or the
      limited-broadcast address, 255.255.255.255.  (The all-systems
@@ -48,101 +80,74 @@
      all listening hosts support IP multicast.)
 
      Default: 224.0.0.1 if the router supports IP multicast on the
-     interface, else 255.255.255.255 */
+     interface, else 255.255.255.255 
 
-  struct in_addr AdvertisementAddress;
-
-  /* The maximum time allowed between sending multicast Router
+     The maximum time allowed between sending multicast Router
      Advertisements from the interface, in seconds.  Must be no less
      than 4 seconds and no greater than 1800 seconds.
 
-     Default: 600 seconds */
+     Default: 600 seconds 
 
-  unsigned long MaxAdvertisementInterval;
-
-  /* The minimum time allowed between sending unsolicited multicast
+     The minimum time allowed between sending unsolicited multicast
      Router Advertisements from the interface, in seconds.  Must be no
      less than 3 seconds and no greater than MaxAdvertisementInterval.
 
-     Default: 0.75 * MaxAdvertisementInterval */
+     Default: 0.75 * MaxAdvertisementInterval 
 
-  unsigned long MinAdvertisementInterval;
-
-
-  /* The value to be placed in the Lifetime field of Router
+     The value to be placed in the Lifetime field of Router
      Advertisements sent from the interface, in seconds.  Must be no
      less than MaxAdvertisementInterval and no greater than 9000
      seconds.
 
-     Default: 3 * MaxAdvertisementInterval */
+     Default: 3 * MaxAdvertisementInterval 
 
-  unsigned long AdvertisementLifetime;
-
-  /* A flag indicating whether or not the address is to be advertised.
-
-     Default: TRUE */
-
-  int Advertise;
-
-
-  /* The preferability of the address as a default router address,
+     The preferability of the address as a default router address,
      relative to other router addresses on the same subnet.  A 32-bit,
      signed, twos-complement integer, with higher values meaning more
      preferable.  The minimum value (hex 80000000) is used to indicate
      that the address, even though it may be advertised, is not to be
      used by neighboring hosts as a default router address.
 
-     Default: 0 */
+     Default: 0 
+*/
 
-  unsigned long PreferenceLevel;
-};
-
-struct irdp_host_interface 
+struct irdp_interface 
 {
-  /* A flag indicating whether or not the host is to perform ICMP router
-     discovery on the interface. */
-  int PerformRouerDiscovery;
-  
-  /* The IP destination address to be used for sending Router
-     Solicitations from the interface.  The only permissible values
-     are the all-routers multicast address, 224.0.0.2, or the
-     limited-broadcast address, 255.255.255.255.  (The all-routers
-     address is preferred wherever possible, i.e., on any link where
-     all advertising routers support IP multicast.)  */
-  unsigned long SolicitationAddress;
+  unsigned long MaxAdvertInterval;
+  unsigned long MinAdvertInterval;
+  unsigned long Preference;
+
+  u_int32_t flags;
+
+#define IF_ACTIVE               (1<<0) /* ICMP Active */
+#define IF_BROADCAST            (1<<1) /* 255.255.255.255 */
+#define IF_SOLICIT              (1<<2) /* Solicit active */
+#define IF_DEBUG_MESSAGES       (1<<3) 
+#define IF_DEBUG_PACKET         (1<<4) 
+#define IF_DEBUG_MISC           (1<<5) 
+#define IF_SHUTDOWN             (1<<6) 
+
+  struct interface *ifp;
+  struct thread *t_advertise;
+  unsigned long irdp_sent;
+  u_int16_t Lifetime;
+
+ list AdvPrefList;
+
 };
 
-
-/* Route preference structure */
-struct irdp 
+struct Adv 
 {
-  struct in_addr prefix;
-  long pref;		/* preference level */
-  long timer;			/* lifetime timer */
-
-  struct irdp *next;		/* doubly linked list */
-  struct irdp *prev;		/* doubly linked list */
+  struct in_addr ip;
+  int pref;
 };
 
-/* Default irdp packet interval */
-#define IRDP_DEFAULT_INTERVAL 300
+void irdp_init();
+void irdp_finish();
+void irdp_config_write (struct vty *, struct interface *);
+#endif /* _IRDP_H */
 
-/* Router constants from RFC1256 */
-#define MAX_INITIAL_ADVERT_INTERVAL 16
-#define MAX_INITIAL_ADVERTISEMENTS   3
-#define MAX_RESPONSE_DELAY           2
 
-/* Host constants from RFC1256 */
-#define MAX_SOLICITATION_DELAY       1
-#define SOLICITATION_INTERVAL        3
-#define MAX_SOLICITATIONS            3
 
-enum
-{
-  IRDP_NONE,
-  IRDP_ROUTER,
-  IRDP_HOST,
-};
 
-/* default is host mode */
-extern int irdp_mode;
+
diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c
new file mode 100644
index 0000000..1e5ad0e
--- /dev/null
+++ b/zebra/irdp_interface.c
@@ -0,0 +1,784 @@
+/*
+ *
+ * Copyright (C) 2000  Robert Olsson.
+ * Swedish University of Agricultural Sciences
+ *
+ * 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 work includes work with the following copywrite:
+ *
+ * Copyright (C) 1997, 2000 Kunihiro Ishiguro
+ *
+ */
+
+/* 
+ * Thanks to Jens Låås at Swedish University of Agricultural Sciences
+ * for reviewing and tests.
+ */
+
+
+#include <zebra.h>
+
+#ifdef HAVE_IRDP 
+
+#include "if.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "command.h"
+#include "memory.h"
+#include "stream.h"
+#include "ioctl.h"
+#include "connected.h"
+#include "log.h"
+#include "zclient.h"
+#include "thread.h"
+#include "zebra/interface.h"
+#include "zebra/rtadv.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/irdp.h"
+#include <netinet/ip_icmp.h>
+#include "if.h"
+#include "sockunion.h"
+#include "log.h"
+
+
+/* Master of threads. */
+extern struct zebra_t zebrad;
+
+int in_cksum (void *ptr, int nbytes);
+extern int irdp_sock;
+int irdp_send_thread(struct thread *t_advert);
+char *inet_2a(u_int32_t a, char *b);
+void irdp_advert_off(struct interface *ifp);
+
+
+char b1[16], b2[16], b3[16], b4[16];  /* For inet_2a */
+
+struct prefix *irdp_get_prefix(struct interface *ifp)
+{
+  listnode node;
+  struct connected *ifc;
+  
+  if(ifp->connected) 
+    for (node = listhead (ifp->connected); node; nextnode (node)) {
+      ifc = getdata (node);
+      return ifc->address;
+    }
+  return NULL;
+}
+
+/* Join to the add/leave multicast group. */
+int if_group (struct interface *ifp, 
+	  int sock, 
+	  u_int32_t group, 
+	  int add_leave)
+{
+  struct zebra_if *zi;
+  struct ip_mreq m;
+  struct prefix *p;
+  int ret;
+
+  zi = ifp->info;
+
+  bzero (&m, sizeof (m));
+  m.imr_multiaddr.s_addr = htonl (group);
+  p = irdp_get_prefix(ifp);
+
+  if(!p) {
+        zlog_warn ("IRDP: can't get address for %s", ifp->name);
+	return 1;
+  }
+
+  m.imr_interface = p->u.prefix4;
+
+  ret = setsockopt (sock, IPPROTO_IP, add_leave,
+		    (char *) &m, sizeof (struct ip_mreq));
+  if (ret < 0)
+    zlog_warn ("IRDP: %s can't setsockopt %s: %s",
+	       add_leave == IP_ADD_MEMBERSHIP? "join group":"leave group", 
+               inet_2a(group, b1),
+               strerror (errno));
+
+  return ret;
+}
+
+int if_add_group (struct interface *ifp)
+{
+  struct zebra_if *zi= ifp->info;
+  struct irdp_interface *irdp = &zi->irdp;
+  int ret;
+
+  ret = if_group (ifp, irdp_sock, INADDR_ALLRTRS_GROUP, IP_ADD_MEMBERSHIP);
+  if (ret < 0) {
+    return ret;
+  }
+
+  if(irdp->flags & IF_DEBUG_MISC )
+    zlog_warn("IRDP: Adding group %s for %s\n", 
+	      inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1),
+	      ifp->name);
+  return 0;
+}
+int if_drop_group (struct interface *ifp)
+{
+  struct zebra_if *zi= ifp->info;
+  struct irdp_interface *irdp = &zi->irdp;
+  int ret;
+
+  ret = if_group (ifp, irdp_sock, INADDR_ALLRTRS_GROUP, IP_DROP_MEMBERSHIP);
+  if (ret < 0)
+    return ret;
+
+  if(irdp->flags & IF_DEBUG_MISC)
+    zlog_warn("IRDP: Leaving group %s for %s\n", 
+	      inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1),
+	      ifp->name);
+  return 0;
+}
+
+struct interface *get_iflist_ifp(int idx)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node)) {
+      ifp = getdata (node);
+      if(ifp->ifindex == idx) return ifp;
+    }
+  return NULL;
+}
+
+void
+if_set_defaults(struct interface *ifp)
+{
+  struct zebra_if *zi=ifp->info;
+  struct irdp_interface *irdp=&zi->irdp;
+
+  irdp->MaxAdvertInterval = IRDP_MAXADVERTINTERVAL;
+  irdp->MinAdvertInterval = IRDP_MINADVERTINTERVAL;
+  irdp->Preference = IRDP_PREFERENCE;
+  irdp->Lifetime = IRDP_LIFETIME;
+}
+
+
+struct Adv *Adv_new ()
+{
+  struct Adv *new;
+  new = XMALLOC (MTYPE_TMP, sizeof (struct Adv));
+  memset (new, 0, sizeof (struct Adv));
+  return new;
+}
+
+void Adv_free (struct Adv *adv)
+{
+  XFREE (MTYPE_TMP, adv);
+}
+
+void irdp_if_start(struct interface *ifp, int multicast, int set_defaults)
+{
+  struct zebra_if *zi= ifp->info;
+  struct irdp_interface *irdp = &zi->irdp;
+  listnode node;
+  u_int32_t timer, seed;
+
+  if (irdp->flags & IF_ACTIVE ) {
+    zlog_warn("IRDP: Interface is already active %s\n", ifp->name);
+    return;
+  }
+  irdp->flags |= IF_ACTIVE;
+
+  if(!multicast) 
+    irdp->flags |= IF_BROADCAST;
+
+  if_add_update(ifp);
+
+  if (! (ifp->flags & IFF_UP)) {
+    zlog_warn("IRDP: Interface is down %s\n", ifp->name);
+  }
+
+  /* Shall we cancel if_start if if_add_group fails? */
+
+  if( multicast) {
+    if_add_group(ifp);
+    
+    if (! (ifp->flags & (IFF_MULTICAST|IFF_ALLMULTI))) {
+      zlog_warn("IRDP: Interface not multicast enabled %s\n", ifp->name);
+    }
+  }
+
+  if(set_defaults) 
+    if_set_defaults(ifp);
+
+  irdp->irdp_sent = 0;
+
+  /* The spec suggests this for randomness */
+
+  seed = 0;
+  if( ifp->connected) 
+	  for (node = listhead (ifp->connected); node; nextnode (node)) 
+	  {
+		  struct connected *ifc = getdata (node);
+		  seed = ifc->address->u.prefix4.s_addr;
+	  }
+  
+  srandom(seed);
+  timer =  (random () % IRDP_DEFAULT_INTERVAL) + 1; 
+
+  irdp->AdvPrefList = list_new();
+  irdp->AdvPrefList->del =  (void *) Adv_free; /* Destructor */
+
+
+  /* And this for startup. Speed limit from 1991 :-). But it's OK*/
+
+  if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS &&
+     timer > MAX_INITIAL_ADVERT_INTERVAL ) 
+	  timer= MAX_INITIAL_ADVERT_INTERVAL;
+
+  
+  if(irdp->flags & IF_DEBUG_MISC)
+    zlog_warn("IRDP: Init timer for %s set to %u\n", 
+	      ifp->name, 
+	      timer);
+
+  irdp->t_advertise = thread_add_timer(zebrad.master, 
+				       irdp_send_thread, 
+				       ifp, 
+				       timer);
+}
+
+void irdp_if_stop(struct interface *ifp)
+{
+  struct zebra_if *zi=ifp->info;
+  struct irdp_interface *irdp=&zi->irdp;
+  
+  if (irdp == NULL) {
+    zlog_warn ("Interface %s structure is NULL", ifp->name);
+    return;
+  }
+
+  if (! (irdp->flags & IF_ACTIVE )) {
+    zlog_warn("Interface is not active %s\n", ifp->name);
+    return;
+  }
+
+  if(! (irdp->flags & IF_BROADCAST)) 
+    if_drop_group(ifp);
+
+  irdp_advert_off(ifp);
+
+  list_delete(irdp->AdvPrefList);
+  irdp->AdvPrefList=NULL;
+
+  irdp->flags = 0;
+}
+
+
+void irdp_if_shutdown(struct interface *ifp)
+{
+  struct zebra_if *zi= ifp->info;
+  struct irdp_interface *irdp = &zi->irdp;
+
+  if (irdp->flags & IF_SHUTDOWN ) {
+    zlog_warn("IRDP: Interface is already shutdown %s\n", ifp->name);
+    return;
+  }
+
+  irdp->flags |= IF_SHUTDOWN;
+  irdp->flags &= ~IF_ACTIVE;
+
+  if(! (irdp->flags & IF_BROADCAST)) 
+    if_drop_group(ifp);
+  
+  /* Tell the hosts we are out of service */
+  irdp_advert_off(ifp);
+}
+
+void irdp_if_no_shutdown(struct interface *ifp)
+{
+  struct zebra_if *zi= ifp->info;
+  struct irdp_interface *irdp = &zi->irdp;
+
+  if (! (irdp->flags & IF_SHUTDOWN )) {
+    zlog_warn("IRDP: Interface is not shutdown %s\n", ifp->name);
+    return;
+  }
+
+  irdp->flags &= ~IF_SHUTDOWN;
+
+  irdp_if_start(ifp, irdp->flags & IF_BROADCAST? FALSE : TRUE, FALSE); 
+
+}
+
+
+/* Write configuration to user */
+
+void irdp_config_write (struct vty *vty, struct interface *ifp)
+{
+  struct zebra_if *zi=ifp->info;
+  struct irdp_interface *irdp=&zi->irdp;
+  struct Adv *adv;
+  listnode node;
+
+  if(irdp->flags & IF_ACTIVE || irdp->flags & IF_SHUTDOWN) {
+
+    if( irdp->flags & IF_SHUTDOWN) 
+      vty_out (vty, " ip irdp shutdown %s",  VTY_NEWLINE);
+
+    if( irdp->flags & IF_BROADCAST) 
+      vty_out (vty, " ip irdp broadcast%s",  VTY_NEWLINE);
+    else 
+      vty_out (vty, " ip irdp multicast%s",  VTY_NEWLINE);
+
+    vty_out (vty, " ip irdp preference %ld%s",  
+	     irdp->Preference, VTY_NEWLINE);
+
+    for (node = listhead (irdp->AdvPrefList); node; nextnode (node)) {
+	    adv = getdata (node);
+	    vty_out (vty, " ip irdp address %s preference %d%s",
+		     inet_2a(adv->ip.s_addr, b1),
+		     adv->pref,
+		     VTY_NEWLINE);
+
+    }
+
+    vty_out (vty, " ip irdp holdtime %d%s",  
+	     irdp->Lifetime, VTY_NEWLINE);
+
+    vty_out (vty, " ip irdp minadvertinterval %ld%s",  
+	     irdp->MinAdvertInterval, VTY_NEWLINE);
+
+    vty_out (vty, " ip irdp maxadvertinterval %ld%s",  
+	     irdp->MaxAdvertInterval, VTY_NEWLINE);
+
+  }
+}
+
+
+DEFUN (ip_irdp_multicast,
+       ip_irdp_multicast_cmd,
+       "ip irdp multicast",
+       IP_STR
+       "ICMP Router discovery on this interface using multicast\n")
+{
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  irdp_if_start(ifp, TRUE, TRUE);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_broadcast,
+       ip_irdp_broadcast_cmd,
+       "ip irdp broadcast",
+       IP_STR
+       "ICMP Router discovery on this interface using broadcast\n")
+{
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  irdp_if_start(ifp, FALSE, TRUE);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_no,
+       ip_irdp_cmd_no,
+       "no ip irdp",
+       IP_STR
+       "Disable ICMP Router discovery on this interface\n")
+{
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  irdp_if_stop(ifp);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_shutdown,
+       ip_irdp_shutdown_cmd,
+       "ip irdp shutdown",
+       IP_STR
+       "ICMP Router discovery shutdown on this interface\n")
+{
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  irdp_if_shutdown(ifp);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_no_shutdown,
+       ip_irdp_no_shutdown_cmd,
+       "no ip irdp shutdown",
+       IP_STR
+       "ICMP Router discovery no shutdown on this interface\n")
+{
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  irdp_if_no_shutdown(ifp);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_holdtime,
+       ip_irdp_holdtime_cmd,
+       "ip irdp holdtime <0-9000>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set holdtime value\n"
+       "Holdtime value in seconds. Default is 1800 seconds\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  zi=ifp->info;
+  irdp=&zi->irdp;
+
+  irdp->Lifetime = atoi(argv[0]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_minadvertinterval,
+       ip_irdp_minadvertinterval_cmd,
+       "ip irdp minadvertinterval <3-1800>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set minimum time between advertisement\n"
+       "Minimum advertisement interval in seconds\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  zi=ifp->info;
+  irdp=&zi->irdp;
+
+  if( atoi(argv[0]) <= irdp->MaxAdvertInterval) {
+      irdp->MinAdvertInterval = atoi(argv[0]);
+
+      return CMD_SUCCESS;
+  }
+
+  vty_out (vty, "ICMP warning maxadvertinterval is greater or equal than minadvertinterval%s", 
+	     VTY_NEWLINE);
+
+  vty_out (vty, "Please correct!%s", 
+	     VTY_NEWLINE);
+  return CMD_WARNING;
+}
+
+DEFUN (ip_irdp_maxadvertinterval,
+       ip_irdp_maxadvertinterval_cmd,
+       "ip irdp maxadvertinterval <4-1800>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set maximum time between advertisement\n"
+       "Maximum advertisement interval in seconds\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  zi=ifp->info;
+  irdp=&zi->irdp;
+
+
+  if( irdp->MinAdvertInterval <= atoi(argv[0]) ) {
+    irdp->MaxAdvertInterval = atoi(argv[0]);
+
+      return CMD_SUCCESS;
+  }
+
+  vty_out (vty, "ICMP warning maxadvertinterval is greater or equal than minadvertinterval%s", 
+	     VTY_NEWLINE);
+
+  vty_out (vty, "Please correct!%s", 
+	     VTY_NEWLINE);
+  return CMD_WARNING;
+}
+
+DEFUN (ip_irdp_preference,
+       ip_irdp_preference_cmd,
+
+       /* DEFUN needs to be fixed for negative ranages...
+	  Be positive for now. :-)
+
+	  "ip irdp preference <-2147483648-2147483647>",
+	*/
+
+
+       "ip irdp preference <0-2147483647>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set default preference level for this interface\n"
+       "Preference level\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  zi=ifp->info;
+  irdp=&zi->irdp;
+
+  irdp->Preference = atoi(argv[0]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_address_preference,
+       ip_irdp_address_preference_cmd,
+       "ip irdp address A.B.C.D preference <0-2147483647>",
+       IP_STR
+       "Alter ICMP Router discovery preference this interface\n"
+       "Specify IRDP non-default preference to advertise\n"
+       "Set IRDP address for advertise\n"
+       "Preference level\n")
+{
+  listnode node;
+  struct in_addr ip; 
+  int pref;
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+  struct Adv *adv;
+
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  zi=ifp->info;
+  irdp=&zi->irdp;
+
+  ret = inet_aton(argv[0], &ip);
+  if(!ret) return CMD_WARNING;
+
+  pref = atoi(argv[1]);
+
+  for (node = listhead (irdp->AdvPrefList); node; nextnode (node)) {
+	  adv = getdata (node);
+      if(adv->ip.s_addr == ip.s_addr) return CMD_SUCCESS;
+  }
+
+  adv = Adv_new();
+  adv->ip = ip;
+  adv->pref = pref;
+  listnode_add(irdp->AdvPrefList, adv);
+
+  return CMD_SUCCESS;
+
+}
+
+DEFUN (ip_irdp_address_preference_no,
+       ip_irdp_address_preference_cmd_no,
+       "no ip irdp address A.B.C.D preference <0-2147483647>",
+       IP_STR
+       "Alter ICMP Router discovery preference this interface\n"
+       "Removes IRDP non-default preference\n"
+       "Select IRDP address\n"
+       "Old preference level\n")
+{
+  listnode node;
+  struct in_addr ip; 
+  int pref;
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+  struct Adv *adv;
+
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  zi=ifp->info;
+  irdp=&zi->irdp;
+
+  ret = inet_aton(argv[0], &ip);
+  if(!ret) return CMD_WARNING;
+
+  pref = atoi(argv[1]);
+
+  for (node = listhead (irdp->AdvPrefList); node; nextnode (node)) {
+	  adv = getdata (node);
+	  if(adv->ip.s_addr == ip.s_addr ) {
+		  listnode_delete(irdp->AdvPrefList, adv);
+		  break;
+	  }
+  }
+
+  return CMD_SUCCESS;
+
+
+}
+
+DEFUN (ip_irdp_debug_messages,
+       ip_irdp_debug_messages_cmd,
+       "ip irdp debug messages",
+       IP_STR
+       "ICMP Router discovery debug Averts. and Solicits (short)\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  zi=ifp->info;
+  irdp=&zi->irdp;
+
+  irdp->flags |= IF_DEBUG_MESSAGES;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_debug_misc,
+       ip_irdp_debug_misc_cmd,
+       "ip irdp debug misc",
+       IP_STR
+       "ICMP Router discovery debug Averts. and Solicits (short)\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  zi=ifp->info;
+  irdp=&zi->irdp;
+
+  irdp->flags |= IF_DEBUG_MISC;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_debug_packet,
+       ip_irdp_debug_packet_cmd,
+       "ip irdp debug packet",
+       IP_STR
+       "ICMP Router discovery debug Averts. and Solicits (short)\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  zi=ifp->info;
+  irdp=&zi->irdp;
+
+  irdp->flags |= IF_DEBUG_PACKET;
+
+  return CMD_SUCCESS;
+}
+
+
+DEFUN (ip_irdp_debug_disable,
+       ip_irdp_debug_disable_cmd,
+       "ip irdp debug disable",
+       IP_STR
+       "ICMP Router discovery debug Averts. and Solicits (short)\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+  ifp = (struct interface *) vty->index;
+  if(!ifp) {
+	  return CMD_WARNING;
+  }
+
+  zi=ifp->info;
+  irdp=&zi->irdp;
+
+  irdp->flags &= ~IF_DEBUG_PACKET;
+  irdp->flags &= ~IF_DEBUG_MESSAGES;
+  irdp->flags &= ~IF_DEBUG_MISC;
+
+  return CMD_SUCCESS;
+}
+
+void
+irdp_if_init ()
+{
+  install_element (INTERFACE_NODE, &ip_irdp_broadcast_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_cmd_no);
+  install_element (INTERFACE_NODE, &ip_irdp_shutdown_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_no_shutdown_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_preference_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd_no);
+
+  install_element (INTERFACE_NODE, &ip_irdp_debug_messages_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_debug_misc_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_debug_packet_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_debug_disable_cmd);
+}
+
+#endif /* HAVE_IRDP */
diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c
new file mode 100644
index 0000000..dac6aea
--- /dev/null
+++ b/zebra/irdp_main.c
@@ -0,0 +1,347 @@
+/*
+ *
+ * Copyright (C) 2000  Robert Olsson.
+ * Swedish University of Agricultural Sciences
+ *
+ * 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 work includes work with the following copywrite:
+ *
+ * Copyright (C) 1997, 2000 Kunihiro Ishiguro
+ *
+ */
+
+/* 
+ * Thanks to Jens Låås at Swedish University of Agricultural Sciences
+ * for reviewing and tests.
+ */
+
+
+#include <zebra.h>
+
+#ifdef HAVE_IRDP
+
+#include "if.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "command.h"
+#include "memory.h"
+#include "stream.h"
+#include "ioctl.h"
+#include "connected.h"
+#include "log.h"
+#include "zclient.h"
+#include "thread.h"
+#include "zebra/interface.h"
+#include "zebra/rtadv.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/irdp.h"
+#include <netinet/ip_icmp.h>
+
+#include "if.h"
+#include "sockunion.h"
+#include "log.h"
+
+/* GLOBAL VARS */
+
+/* Master of threads. */
+extern struct zebra_t zebrad;
+struct thread *t_irdp_raw;
+
+/* Timer interval of irdp. */
+int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
+
+int irdp_read_raw(struct thread *r);
+int in_cksum (void *ptr, int nbytes);
+extern int irdp_sock;
+void send_packet(struct interface *ifp, 
+		 struct stream *s,
+		 u_int32_t dst,
+		 struct prefix *p,
+		 u_int32_t ttl);
+
+void irdp_if_init ();
+
+char *
+inet_2a(u_int32_t a, char *b)
+{
+  sprintf(b, "%u.%u.%u.%u", 
+          (a    ) & 0xFF,
+          (a>> 8) & 0xFF, 
+          (a>>16) & 0xFF, 
+          (a>>24) & 0xFF);
+  return  b;
+}
+
+int
+irdp_sock_init (void)
+{
+  int ret, i;
+
+  irdp_sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
+  if (irdp_sock < 0) {
+    zlog_warn ("IRDP: can't create irdp socket %s", strerror(errno));
+    return irdp_sock;
+  };
+  
+  i = 1;
+  ret = setsockopt (irdp_sock, IPPROTO_IP, IP_TTL, 
+                        (void *) &i, sizeof (i));
+  if (ret < 0) {
+    zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno));
+    return ret;
+  };
+  
+  i = 1;
+  ret = setsockopt (irdp_sock, IPPROTO_IP, IP_PKTINFO, 
+                        (void *) &i, sizeof (i));
+  if (ret < 0) {
+    zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno));
+    return ret;
+  };
+
+  t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock); 
+
+  return irdp_sock;
+}
+
+
+int get_pref(struct irdp_interface *irdp, struct prefix *p)
+{
+  listnode node;
+  struct Adv *adv;
+
+  /* Use default preference or use the override pref */
+  
+  if( irdp->AdvPrefList == NULL ) return irdp->Preference;
+  
+  for (node = listhead (irdp->AdvPrefList); node; nextnode (node)) {
+    adv = getdata (node);
+    if( p->u.prefix4.s_addr == adv->ip.s_addr )
+      return adv->pref;
+  }
+  return irdp->Preference;
+}
+
+/* Make ICMP Router Advertisement Message. */
+int make_advertisement_packet (struct interface *ifp, 
+			       struct prefix *p,
+			       struct stream *s)
+{
+  struct zebra_if *zi=ifp->info;
+  struct irdp_interface *irdp=&zi->irdp;
+  int size;
+  int pref;
+  u_int16_t checksum;
+
+  pref =  get_pref(irdp, p);
+
+  stream_putc (s, ICMP_ROUTERADVERT); /* Type. */
+  stream_putc (s, 0);		/* Code. */
+  stream_putw (s, 0);		/* Checksum. */
+  stream_putc (s, 1);		/* Num address. */
+  stream_putc (s, 2);		/* Address Entry Size. */
+
+  if(irdp->flags & IF_SHUTDOWN)  
+    stream_putw (s, 0);
+  else 
+    stream_putw (s, irdp->Lifetime);
+
+  stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */
+  stream_putl (s, pref);
+
+  /* in_cksum return network byte order value */
+  size = 16;
+  checksum = in_cksum (s->data, size);
+  stream_putw_at (s, 2, htons(checksum));
+
+  return size;
+}
+
+void irdp_send(struct interface *ifp, 
+	       struct prefix *p, 
+	       struct stream *s)
+{
+  struct zebra_if *zi=ifp->info;
+  struct irdp_interface *irdp=&zi->irdp;
+  u_int32_t dst;
+  u_int32_t ttl=1;
+
+  if (! (ifp->flags & IFF_UP)) return; 
+
+  if (irdp->flags & IF_BROADCAST) 
+    dst =INADDR_BROADCAST ;
+  else 
+    dst = htonl(INADDR_ALLHOSTS_GROUP);
+
+  if(irdp->flags & IF_DEBUG_MESSAGES) 
+    zlog_warn("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d", 
+	      ifp->name,
+	      inet_ntoa(p->u.prefix4), 
+	      p->prefixlen,
+	      irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
+	      get_pref(irdp, p));
+
+  send_packet (ifp, s, dst, p, ttl);
+}
+
+void irdp_advertisement (struct interface *ifp, 
+		   struct prefix *p)
+{
+  struct stream *s;
+  s = stream_new (128);
+  make_advertisement_packet (ifp, p, s);
+  irdp_send(ifp, p, s); 
+}
+
+int irdp_send_thread(struct thread *t_advert)
+{
+  u_int32_t timer, tmp;
+  struct interface *ifp = THREAD_ARG (t_advert);
+  struct zebra_if *zi=ifp->info;
+  struct irdp_interface *irdp=&zi->irdp;
+  struct prefix *p;
+  listnode node;
+  struct connected *ifc;
+
+  irdp->flags &= ~IF_SOLICIT;
+
+  if(ifp->connected) 
+    for (node = listhead (ifp->connected); node; nextnode (node)) {
+      ifc = getdata (node);
+
+      p = ifc->address;
+
+      irdp_advertisement(ifp, p);
+      irdp->irdp_sent++;
+
+    }
+
+  tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
+  timer =  (random () % tmp ) + 1;
+  timer = irdp->MinAdvertInterval + timer;
+
+  if(irdp->irdp_sent <  MAX_INITIAL_ADVERTISEMENTS &&
+     timer > MAX_INITIAL_ADVERT_INTERVAL ) 
+	  timer= MAX_INITIAL_ADVERT_INTERVAL;
+
+  if(irdp->flags & IF_DEBUG_MISC)
+    zlog_warn("IRDP: New timer for %s set to %u\n", ifp->name, timer);
+
+  irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
+  return 0;
+}
+
+void irdp_advert_off(struct interface *ifp)
+{
+  struct zebra_if *zi=ifp->info;
+  struct irdp_interface *irdp=&zi->irdp;
+  listnode node;
+  int i;
+  struct connected *ifc;
+  struct prefix *p;
+
+  if(irdp->t_advertise)  thread_cancel(irdp->t_advertise);
+  irdp->t_advertise = NULL;
+  
+  if(ifp->connected) 
+    for (node = listhead (ifp->connected); node; nextnode (node)) {
+      ifc = getdata (node);
+
+      p = ifc->address;
+
+      /* Output some packets with Lifetime 0 
+	 we should add a wait...
+      */
+
+      for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++) {
+
+	irdp->irdp_sent++;
+	irdp_advertisement(ifp, p);
+      }
+    }
+}
+
+
+void process_solicit (struct interface *ifp)
+{
+  struct zebra_if *zi=ifp->info;
+  struct irdp_interface *irdp=&zi->irdp;
+  u_int32_t timer;
+
+  /* When SOLICIT is active we reject further incoming solicits 
+     this keeps down the answering rate so we don't have think
+     about DoS attacks here. */
+
+  if( irdp->flags & IF_SOLICIT) return;
+
+  irdp->flags |= IF_SOLICIT;
+  if(irdp->t_advertise)  thread_cancel(irdp->t_advertise);
+  irdp->t_advertise = NULL;
+
+  timer =  (random () % MAX_RESPONSE_DELAY) + 1;
+
+  irdp->t_advertise = thread_add_timer(zebrad.master, 
+				       irdp_send_thread, 
+				       ifp, 
+				       timer);
+}
+
+void irdp_finish()
+{
+
+  listnode node;
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+
+  zlog_warn("IRDP: Received shutdown notification.");
+  
+  for (node = listhead (iflist); node; node = nextnode (node))
+    {
+      ifp = getdata(node);
+      zi= ifp->info;
+      if(! zi) continue;
+      irdp = &zi->irdp;
+      if(!irdp) continue;
+
+      if(irdp->flags & IF_ACTIVE ) {
+	irdp->flags |= IF_SHUTDOWN;
+	irdp_advert_off(ifp);
+      }
+    }
+}
+
+void irdp_init()
+{
+  irdp_sock_init();
+  irdp_if_init ();
+}
+
+
+
+#endif /* HAVE_IRDP */
+
+
+
+
diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c
new file mode 100644
index 0000000..147d597
--- /dev/null
+++ b/zebra/irdp_packet.c
@@ -0,0 +1,364 @@
+/*
+ *
+ * Copyright (C) 2000  Robert Olsson.
+ * Swedish University of Agricultural Sciences
+ *
+ * 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 work includes work with the following copywrite:
+ *
+ * Copyright (C) 1997, 2000 Kunihiro Ishiguro
+ *
+ */
+
+/* 
+ * Thanks to Jens Låås at Swedish University of Agricultural Sciences
+ * for reviewing and tests.
+ */
+
+
+#include <zebra.h>
+
+
+#ifdef HAVE_IRDP
+
+#include "if.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "command.h"
+#include "memory.h"
+#include "stream.h"
+#include "ioctl.h"
+#include "connected.h"
+#include "log.h"
+#include "zclient.h"
+#include "thread.h"
+#include "zebra/interface.h"
+#include "zebra/rtadv.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/irdp.h"
+#include <netinet/ip_icmp.h>
+#include "if.h"
+#include "sockunion.h"
+#include "log.h"
+
+
+
+/* GLOBAL VARS */
+
+int irdp_sock;
+char b1[16], b2[16], b3[16], b4[16];  /* For inet_2a */
+
+extern struct zebra_t zebrad;
+extern struct thread *t_irdp_raw;
+extern struct interface *get_iflist_ifp(int idx);
+int in_cksum (void *ptr, int nbytes);
+void process_solicit (struct interface *ifp);
+
+void parse_irdp_packet(char *p, 
+		  int len, 
+		  struct interface *ifp)
+{
+  struct ip *ip = (struct ip *)p ;
+  struct icmphdr *icmp;
+  struct in_addr src;
+  int ip_hlen, ip_len;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+
+  zi = ifp->info;
+  if(!zi) return;
+
+  irdp = &zi->irdp;
+  if(!irdp) return;
+
+  ip_hlen = ip->ip_hl*4; 
+  ip_len = ntohs(ip->ip_len);
+  len = len - ip_hlen;
+  src = ip->ip_src;
+
+  if(ip_len < ICMP_MINLEN) {
+    zlog_err ("IRDP: RX ICMP packet too short from %s\n",
+	      inet_ntoa (src));
+    return;
+  }
+
+  /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen +
+   len of IP-header) 14+20 */
+
+  if(ip_len > IRDP_RX_BUF-34) {
+    zlog_err ("IRDP: RX ICMP packet too long from %s\n",
+	      inet_ntoa (src));
+    return;
+  }
+
+
+  if (in_cksum (ip, ip_len)) {
+    zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
+	       inet_ntoa (src));
+    return;
+  }
+
+  icmp = (struct icmphdr *) (p+ip_hlen);
+
+
+  /* Handle just only IRDP */
+
+  if( icmp->type == ICMP_ROUTERADVERT);
+  else if( icmp->type == ICMP_ROUTERSOLICIT);
+  else return;
+
+ 
+  if (icmp->code != 0) {
+    zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code, silently ignored",
+	       icmp->type,
+	       inet_ntoa (src));
+    return;
+  }
+
+  if(ip->ip_dst.s_addr == INADDR_BROADCAST && 
+     irdp->flags & IF_BROADCAST);
+
+  else if ( ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP && 
+	    ! (irdp->flags &  IF_BROADCAST));
+
+  else { /* ERROR */
+
+    zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n",
+	       inet_ntoa (src), 
+	       ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP? 
+	       "multicast" : inet_ntoa(ip->ip_dst),
+	       ifp->name,
+	       irdp->flags &  IF_BROADCAST? 
+	       "broadcast" : "multicast");
+
+    zlog_warn ("IRDP: Please correct settings\n");
+    return;
+  }
+
+  switch (icmp->type) 
+    {
+    case ICMP_ROUTERADVERT:
+      break;
+
+    case ICMP_ROUTERSOLICIT:
+
+      if(irdp->flags & IF_DEBUG_MESSAGES) 
+	zlog_warn ("IRDP: RX Solicit on %s from %s\n",
+		   ifp->name,
+		   inet_ntoa (src));
+
+      process_solicit(ifp);
+      break;
+
+    default:
+      zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
+		 icmp->type,
+		 inet_ntoa (src));
+    }
+}
+
+int irdp_recvmsg (int sock, 
+	      u_char *buf, 
+	      int size, 
+	      int *ifindex)
+{
+  struct msghdr msg;
+  struct iovec iov;
+  struct cmsghdr *ptr;
+  char adata[1024];
+  int ret;
+
+  msg.msg_name = (void *)0;
+  msg.msg_namelen = 0;
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = (void *) adata;
+  msg.msg_controllen = sizeof adata;
+
+  iov.iov_base = buf;
+  iov.iov_len = size;
+
+  ret = recvmsg (sock, &msg, 0);
+  if (ret < 0) {
+    zlog_warn("IRDP: recvmsg: read error %s", strerror(errno));
+    return ret;
+  }
+
+  if (msg.msg_flags & MSG_TRUNC) {
+    zlog_warn("IRDP: recvmsg: truncated message");
+    return ret;
+  }
+  if (msg.msg_flags & MSG_CTRUNC) {
+    zlog_warn("IRDP: recvmsg: truncated control message");
+    return ret;
+  }
+
+  for (ptr = CMSG_FIRSTHDR(&msg); ptr ; ptr = CMSG_NXTHDR(&msg, ptr))
+    if (ptr->cmsg_level == SOL_IP && ptr->cmsg_type == IP_PKTINFO) 
+      {
+        struct in_pktinfo *pktinfo;
+           pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
+        *ifindex = pktinfo->ipi_ifindex;
+      }
+  return ret;
+}
+
+int irdp_read_raw(struct thread *r)
+{
+  struct interface *ifp;
+  struct zebra_if *zi;
+  struct irdp_interface *irdp;
+  char buf[IRDP_RX_BUF];
+  int ret, ifindex;
+  
+  int irdp_sock = THREAD_FD (r);
+  t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
+  
+  ret = irdp_recvmsg (irdp_sock, buf, IRDP_RX_BUF,  &ifindex);
+ 
+  if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret);
+
+  ifp = get_iflist_ifp(ifindex);
+  if(! ifp ) return ret;
+
+  zi= ifp->info;
+  if(! zi ) return ret;
+
+  irdp = &zi->irdp;
+  if(! irdp ) return ret;
+
+  if(! (irdp->flags & IF_ACTIVE)) {
+
+    if(irdp->flags & IF_DEBUG_MISC) 
+      zlog_warn("IRDP: RX ICMP for disabled interface %s\n",
+		ifp->name);
+    return 0;
+  }
+
+  if(irdp->flags & IF_DEBUG_PACKET) {
+    int i;
+    zlog_warn("IRDP: RX (idx %d) ", ifindex);
+    for(i=0; i < ret; i++) zlog_warn( "IRDP: RX %x ", buf[i]&0xFF);
+  }
+
+  parse_irdp_packet(buf, ret, ifp);
+  return ret;
+}
+
+void send_packet(struct interface *ifp, 
+	    struct stream *s,
+	    u_int32_t dst,
+	    struct prefix *p,
+	    u_int32_t ttl)
+{
+  static struct sockaddr_in sockdst = {AF_INET};
+  struct ip *ip;
+  struct icmphdr *icmp;
+  struct msghdr *msg;
+  struct cmsghdr *cmsg;
+  struct iovec iovector;
+  char msgbuf[256];
+  char buf[256];
+  struct in_pktinfo *pktinfo;
+  u_long src;
+  int on;
+ 
+  if (! (ifp->flags & IFF_UP)) return;
+
+  if(!p) src = ntohl(p->u.prefix4.s_addr);
+  else src = 0; /* Is filled in */
+  
+  ip = (struct ip *) buf;
+  ip->ip_hl = sizeof(struct ip) >> 2;
+  ip->ip_v = IPVERSION;
+  ip->ip_tos = 0xC0;
+  ip->ip_off = 0L;
+  ip->ip_p = 1;       /* IP_ICMP */
+  ip->ip_ttl = ttl;
+  ip->ip_src.s_addr = src;
+  ip->ip_dst.s_addr = dst;
+  icmp = (struct icmphdr *) (buf + 20);
+
+  /* Merge IP header with icmp packet */
+
+  stream_get(icmp, s, s->putp);
+
+  /* icmp->checksum is already calculated */
+  ip->ip_len  = sizeof(struct ip) + s->putp;
+  stream_free(s); 
+
+  on = 1;
+  if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL,
+		 (char *) &on, sizeof(on)) < 0)
+    zlog_warn("sendto %s", strerror (errno));
+
+
+  if(dst == INADDR_BROADCAST ) {
+    on = 1;
+    if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST,
+		   (char *) &on, sizeof(on)) < 0)
+      zlog_warn("sendto %s", strerror (errno));
+  }
+
+  if(dst !=  INADDR_BROADCAST) {
+      on = 0; 
+      if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP, 
+		     (char *)&on,sizeof(on)) < 0)
+	zlog_warn("sendto %s", strerror (errno));
+  }
+
+  bzero(&sockdst,sizeof(sockdst));
+  sockdst.sin_family=AF_INET;
+  sockdst.sin_addr.s_addr = dst;
+
+  cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr));
+  cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
+  cmsg->cmsg_level = SOL_IP;
+  cmsg->cmsg_type = IP_PKTINFO;
+  pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg);
+  pktinfo->ipi_ifindex = ifp->ifindex;
+  pktinfo->ipi_spec_dst.s_addr = src;
+  pktinfo->ipi_addr.s_addr = src;
+ 
+  iovector.iov_base = (void *) buf;
+  iovector.iov_len = ip->ip_len; 
+  msg = (struct msghdr *) msgbuf;
+  msg->msg_name = &sockdst;
+  msg->msg_namelen = sizeof(sockdst);
+  msg->msg_iov = &iovector;
+  msg->msg_iovlen = 1;
+  msg->msg_control = cmsg;
+  msg->msg_controllen = cmsg->cmsg_len;
+ 
+  if (sendmsg(irdp_sock, msg, 0) < 0) {
+    zlog_warn("sendto %s", strerror (errno));
+  }
+  /*   printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
+}
+
+
+#endif /* HAVE_IRDP */
+
+
+
diff --git a/zebra/main.c b/zebra/main.c
index efc9564..3384d7d 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -36,6 +36,7 @@
 #include "zebra/zserv.h"
 #include "zebra/debug.h"
 #include "zebra/rib.h"
+#include "zebra/irdp.h"
 
 /* Zebra instance */
 struct zebra_t zebrad =
@@ -151,6 +152,9 @@
 
   if (!retain_mode)
     rib_close ();
+#ifdef HAVE_IRDP
+  irdp_finish();
+#endif
 
   exit (0);
 }
@@ -289,6 +293,9 @@
   zebra_vty_init ();
   access_list_init ();
   rtadv_init ();
+#ifdef HAVE_IRDP
+  irdp_init();
+#endif
 
   /* For debug purpose. */
   /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */