[OpenWrt-Devel] [PATCH] Quagga 0.99.23 CISCO EIGRP support

Lucian Cristian luci at createc.ro
Sun Nov 8 21:28:37 EST 2015


On 04.11.2015 22:35, Lucian Cristian wrote:
>
> based on git: https://github.com/janovic/Quagga-EIGRP
> tested with opennhrp (gre tunnels, no ipsec) and seems to work "as is 
> per developer's readme"
> the git is based on 0.99.23 should I try to backport it to the current 
> openwrt quagga version ?
>
> Regards
>
> Lucian
>
>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel at lists.openwrt.org
> https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
backported to 0.99.22.4

Regards
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/openwrt-devel/attachments/20151109/35ffe0c8/attachment.htm>
-------------- next part --------------
commit 93eb988b0753c3d825bf64065431af0b66a9bc53
Author: Lucian Cristian <lucian.cristian at gmail.com>
Date:   Mon Nov 9 03:27:50 2015 +0200

    Signed-off-by: Lucian Cristian <lucian.cristian at gmail.com>

diff --git a/quagga/Makefile b/quagga/Makefile
index 67eedd6..6100a01 100644
--- a/quagga/Makefile
+++ b/quagga/Makefile
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=quagga
 PKG_VERSION:=0.99.22.4
-PKG_RELEASE:=2
+PKG_RELEASE:=3
 PKG_MD5SUM:=03ef24a448be47beba80efa2152f8a28
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
@@ -20,6 +20,8 @@ PKG_CONFIG_DEPENDS:= \
 	CONFIG_PACKAGE_quagga-zebra \
 	CONFIG_PACKAGE_quagga-libzebra \
 	CONFIG_PACKAGE_quagga-libospf \
+	CONFIG_PACKAGE_quagga-libeigrp \
+	CONFIG_PACKAGE_quagga-eigrpd \
 	CONFIG_PACKAGE_quagga-bgpd \
 	CONFIG_PACKAGE_quagga-isisd \
 	CONFIG_PACKAGE_quagga-ospf6d \
@@ -80,6 +82,17 @@ define Package/quagga-libospf
   TITLE:=OSPF library
 endef
 
+define Package/quagga-libeigrp
+  $(call Package/quagga/Default)
+  TITLE:=EIGRP library
+endef
+
+define Package/quagga-eigrpd
+  $(call Package/quagga/Default)
+  DEPENDS+=+quagga-libeigrp +quagga-libzebra
+  TITLE:=CISCO EIGRP routing engine
+endef
+
 define Package/quagga-bgpd
   $(call Package/quagga/Default)
   DEPENDS+=+quagga-libzebra
@@ -136,6 +149,10 @@ define Package/quagga-bgpd/conffiles
 /etc/quagga/bgpd.conf
 endef
 
+define Package/quagga-eigrpd/conffiles
+/etc/quagga/eigrp.conf
+endef
+
 define Package/quagga-isisd/conffiles
 /etc/quagga/isisd.conf
 endef
@@ -163,9 +180,11 @@ endef
 ifneq ($(SDK),)
 CONFIG_PACKAGE_quagga-libzebra:=m
 CONFIG_PACKAGE_quagga-libospf:=m
+CONFIG_PACKAGE_quagga-libeigrp:=m
 CONFIG_PACKAGE_quagga-watchquagga:=m
 CONFIG_PACKAGE_quagga-zebra:=m
 CONFIG_PACKAGE_quagga-bgpd:=m
+CONFIG_PACKAGE_quagga-eigrpd:=m
 CONFIG_PACKAGE_quagga-isisd:=m
 CONFIG_PACKAGE_quagga-ospf6d:=m
 CONFIG_PACKAGE_quagga-ripd:=m
@@ -190,6 +209,7 @@ CONFIGURE_ARGS+= \
 	$(call autoconf_bool,CONFIG_PACKAGE_quagga-libospf,ospfd) \
 	$(call autoconf_bool,CONFIG_PACKAGE_quagga-bgpd,bgpd) \
 	$(call autoconf_bool,CONFIG_PACKAGE_quagga-isisd,isisd) \
+	$(call autoconf_bool,CONFIG_PACKAGE_quagga-libeigrp,eigrpd) \
 	$(call autoconf_bool,CONFIG_PACKAGE_quagga-ospf6d,ospf6d) \
 	$(call autoconf_bool,CONFIG_PACKAGE_quagga-ripd,ripd) \
 	$(call autoconf_bool,CONFIG_PACKAGE_quagga-ripngd,ripngd) \
@@ -243,6 +263,14 @@ define Package/quagga-ospfd/install
 	$(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/ospfd.conf
 endef
 
+define Package/quagga-eigrpd/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/eigrpd $(1)/usr/sbin/
+	$(INSTALL_DIR) $(1)/etc/quagga
+	chmod 0750 $(1)/etc/quagga
+	$(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/eigrpd.conf
+endef
+
 define Package/quagga-ospf6d/install
 	$(INSTALL_DIR) $(1)/usr/sbin
 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ospf6d $(1)/usr/sbin/
@@ -285,6 +313,11 @@ define Package/quagga-libospf/install
 	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libospf.so.* $(1)/usr/lib/
 endef
 
+define Package/quagga-libeigrp/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libeigrp.so.* $(1)/usr/lib/
+endef
+
 define Package/quagga-libzebra/install
 	$(INSTALL_DIR) $(1)/usr/lib
 	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libzebra.so.* $(1)/usr/lib/
@@ -293,9 +326,11 @@ endef
 $(eval $(call BuildPackage,quagga))
 $(eval $(call BuildPackage,quagga-libzebra))
 $(eval $(call BuildPackage,quagga-libospf))
+$(eval $(call BuildPackage,quagga-libeigrp))
 $(eval $(call BuildPackage,quagga-watchquagga))
 $(eval $(call BuildPackage,quagga-zebra))
 $(eval $(call BuildPackage,quagga-bgpd))
+$(eval $(call BuildPackage,quagga-eigrpd))
 $(eval $(call BuildPackage,quagga-isisd))
 $(eval $(call BuildPackage,quagga-ospfd))
 $(eval $(call BuildPackage,quagga-ospf6d))
diff --git a/quagga/files/quagga b/quagga/files/quagga
index b172090..80839d2 100644
--- a/quagga/files/quagga
+++ b/quagga/files/quagga
@@ -29,7 +29,7 @@ CONFDIR=/etc/quagga
 STATEDIR=/var/run/quagga
 RUNUSER=network
 RUNGROUP=$RUNUSER
-DAEMONS="zebra ripd ripngd ospfd ospf6d bgpd"
+DAEMONS="zebra ripd ripngd ospfd ospf6d bgpd eigrpd"
 DAEMON_FLAGS=-d
 WATCHQUAGGA_FLAGS="-d -z -T 60 -R"
 WATCHQUAGGA_CMD="$0 watchrestart"
diff --git a/quagga/patches/190-eigrp.patch b/quagga/patches/190-eigrp.patch
new file mode 100644
index 0000000..15fe714
--- /dev/null
+++ b/quagga/patches/190-eigrp.patch
@@ -0,0 +1,569 @@
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2,11 +2,11 @@
+ 
+ SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @BABELD@ \
+          @ISISD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \
+-         redhat @SOLARIS@ @BUILD_TESTS@
++         redhat @SOLARIS@ @BUILD_TESTS@ eigrpd
+ 
+ DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d babeld \
+ 	  isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \
+-	  solaris
++	  solaris eigrpd
+ 
+ EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \
+ 	update-autotools \
+--- a/configure.ac
++++ b/configure.ac
+@@ -214,6 +214,8 @@
+ [  --disable-ripngd        do not build ripngd])
+ AC_ARG_ENABLE(ospfd,
+ [  --disable-ospfd         do not build ospfd])
++AC_ARG_ENABLE(eigrpd,
++[  --disable-eigrpd         do not build eigrpd])
+ AC_ARG_ENABLE(ospf6d,
+ [  --disable-ospf6d        do not build ospf6d])
+ AC_ARG_ENABLE(babeld,
+@@ -1306,6 +1308,13 @@
+ fi
+ AM_CONDITIONAL(OSPFD, test "x$OSPFD" = "xospfd")
+ 
++if test "${enable_eigrpd}" = "no";then
++  EIGRPD=""
++else
++  EIGRPD="eigrpd"
++fi
++AM_CONDITIONAL(EIGRPD, test "x$EIGRPD" = "xeigrpd")
++
+ if test "${enable_babeld}" = "no";then
+   BABELD=""
+ else
+@@ -1655,6 +1664,7 @@
+ AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$quagga_statedir/bgpd.pid",bgpd PID)
+ AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$quagga_statedir/ospfd.pid",ospfd PID)
+ AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$quagga_statedir/ospf6d.pid",ospf6d PID)
++AC_DEFINE_UNQUOTED(PATH_EIGRPD_PID, "$quagga_statedir/eigrpd.pid",eigrpd PID)
+ AC_DEFINE_UNQUOTED(PATH_BABELD_PID, "$quagga_statedir/babeld.pid",babeld PID)
+ AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$quagga_statedir/isisd.pid",isisd PID)
+ AC_DEFINE_UNQUOTED(PATH_WATCHQUAGGA_PID, "$quagga_statedir/watchquagga.pid",watchquagga PID)
+@@ -1665,6 +1675,7 @@
+ AC_DEFINE_UNQUOTED(BGP_VTYSH_PATH, "$quagga_statedir/bgpd.vty",bgpd vty socket)
+ AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$quagga_statedir/ospfd.vty",ospfd vty socket)
+ AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$quagga_statedir/ospf6d.vty",ospf6d vty socket)
++AC_DEFINE_UNQUOTED(EIGRP_VTYSH_PATH, "$quagga_statedir/eigrpd.vty",eigrpd vty socket)
+ AC_DEFINE_UNQUOTED(BABEL_VTYSH_PATH, "$quagga_statedir/babeld.vty",babeld vty socket)
+ AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socket)
+ AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory)
+@@ -1692,6 +1703,7 @@
+ 	  ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile
+ 	  ospf6d/Makefile isisd/Makefile babeld/Makefile vtysh/Makefile
+           doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile
++	  eigrpd/Makefile
+           redhat/Makefile
+ 	  pkgsrc/Makefile
+ 	  redhat/quagga.spec 
+@@ -1699,7 +1711,8 @@
+ 	  doc/defines.texi
+ 	  isisd/topology/Makefile
+ 	  pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh
+-	  pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh])
++	  pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
++	  pkgsrc/eigrpd.sh])
+ AC_CONFIG_FILES([solaris/Makefile])
+ 
+ AC_CONFIG_FILES([vtysh/extract.pl],[chmod +x vtysh/extract.pl])
+
+--- a/lib/command.c
++++ b/lib/command.c
+@@ -156,6 +156,7 @@
+ {
+   printf ("%s version %s\n", progname, QUAGGA_VERSION);
+   printf ("%s\n", QUAGGA_COPYRIGHT);
++  printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS);
+ }
+ 
+ ^L
+@@ -2329,6 +2330,7 @@
+     case BABEL_NODE:
+     case OSPF_NODE:
+     case OSPF6_NODE:
++    case EIGRP_NODE:
+     case ISIS_NODE:
+     case KEYCHAIN_NODE:
+     case MASC_NODE:
+@@ -2386,6 +2388,7 @@
+     case RMAP_NODE:
+     case OSPF_NODE:
+     case OSPF6_NODE:
++    case EIGRP_NODE:
+     case ISIS_NODE:
+     case KEYCHAIN_NODE:
+     case KEYCHAIN_KEY_NODE:
+@@ -2410,6 +2413,8 @@
+   vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
+ 	   VTY_NEWLINE);
+   vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
++  vty_out (vty, "configured with:%s    %s%s", VTY_NEWLINE,
++	   QUAGGA_CONFIG_ARGS, VTY_NEWLINE);
+ 
+   return CMD_SUCCESS;
+ }
+
+--- a/lib/Makefile.am
++++ b/lib/Makefile.am
+@@ -12,7 +12,7 @@
+ 	sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
+ 	filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
+ 	zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \
+-	sigevent.c pqueue.c jhash.c memtypes.c workqueue.c
++	sigevent.c pqueue.c jhash.c memtypes.c workqueue.c sha256.c
+ 
+ BUILT_SOURCES = memtypes.h route_types.h gitversion.h
+
+@@ -27,7 +27,7 @@
+ 	str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
+ 	plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \
+ 	privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
+-	workqueue.h route_types.h
++	workqueue.h route_types.h sha256.h
+ 
+ EXTRA_DIST = \
+        regex.c regex-gnu.h \
+
+--- a/lib/command.h
++++ b/lib/command.h
+@@ -87,6 +87,7 @@
+   BGP_IPV6M_NODE,		/* BGP IPv6 multicast address family. */
+   OSPF_NODE,			/* OSPF protocol mode */
+   OSPF6_NODE,			/* OSPF protocol for IPv6 mode */
++  EIGRP_NODE,			/* EIGRP protocol mode */
+   ISIS_NODE,			/* ISIS protocol mode */
+   MASC_NODE,			/* MASC for multicast.  */
+   IRDP_NODE,			/* ICMP Router Discovery Protocol mode. */ 
+@@ -280,6 +281,7 @@
+ #define RIP_STR "RIP information\n"
+ #define BGP_STR "BGP information\n"
+ #define OSPF_STR "OSPF information\n"
++#define EIGRP_STR "EIGRP information\n"
+ #define NEIGHBOR_STR "Specify neighbor router\n"
+ #define DEBUG_STR "Debugging functions (see also 'undebug')\n"
+ #define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
+
+--- a/lib/distribute.c
++++ b/lib/distribute.c
+@@ -778,5 +778,14 @@
+     install_element (node, &no_ipv6_distribute_list_prefix_all_cmd);
+     install_element (node, &ipv6_distribute_list_prefix_cmd);
+     install_element (node, &no_ipv6_distribute_list_prefix_cmd);
++  } else if(node==EIGRP_NODE) {
++    install_element (node, &distribute_list_all_cmd);
++    install_element (node, &no_distribute_list_all_cmd);
++    install_element (node, &distribute_list_cmd);
++    install_element (node, &no_distribute_list_cmd);
++    install_element (node, &distribute_list_prefix_all_cmd);
++    install_element (node, &no_distribute_list_prefix_all_cmd);
++    install_element (node, &distribute_list_prefix_cmd);
++    install_element (node, &no_distribute_list_prefix_cmd);
+   }
+ }
+--- a/lib/log.c
++++ b/lib/log.c
+@@ -52,6 +52,7 @@
+   "OSPF6",
+   "ISIS",
+   "MASC",
++  "EIGRP",
+   NULL,
+ };
+ 
+@@ -927,6 +928,8 @@
+        return ZEBRA_ROUTE_RIP;
+       else if (strncmp (s, "os", 2) == 0)
+ 	return ZEBRA_ROUTE_OSPF;
++      else if (strncmp (s, "e", 1) == 0)
++	return ZEBRA_ROUTE_EIGRP;
+       else if (strncmp (s, "i", 1) == 0)
+ 	return ZEBRA_ROUTE_ISIS;
+       else if (strncmp (s, "bg", 2) == 0)
+--- a/lib/log.h
++++ b/lib/log.h
+@@ -53,7 +53,8 @@
+   ZLOG_BABEL,
+   ZLOG_OSPF6,
+   ZLOG_ISIS,
+-  ZLOG_MASC
++  ZLOG_MASC,
++  ZLOG_EIGRP
+ } zlog_proto_t;
+
+ /* If maxlvl is set to ZLOG_DISABLED, then no messages will be sent
+--- a/lib/memtypes.c
++++ b/lib/memtypes.c
+@@ -255,6 +255,27 @@
+   { -1, NULL },
+ };
+
++struct memory_list memory_list_eigrp[] =
++{
++  { MTYPE_EIGRP_TOP,             "EIGRP top"			},
++  { MTYPE_EIGRP_IF_INFO,         "EIGRP if info"		},
++  { MTYPE_EIGRP_IF_PARAMS,       "EIGRP if params"		},
++  { MTYPE_EIGRP_IF,              "EIGRP interface"		},
++  { MTYPE_EIGRP_FIFO,            "EIGRP FIFO queue"		},
++  { MTYPE_EIGRP_HEADER_FIFO,     "EIGRP Header FIFO queue"	},
++  { MTYPE_EIGRP_TOPOLOGY,        "EIGRP Topology table"	},
++  { MTYPE_EIGRP_PREFIX_ENTRY,    "EIGRP Topology table prefix"	},
++  { MTYPE_EIGRP_NEIGHBOR_ENTRY,  "EIGRP Topology table entry"	},
++  { MTYPE_EIGRP_PACKET,          "EIGRP packet structure"	},
++  { MTYPE_EIGRP_NEIGHBOR,        "EIGRP neighbor structure"	},
++  { MTYPE_EIGRP_IPV4_INT_TLV,    "EIGRP Internal IPv4 TLV "	},
++  { MTYPE_EIGRP_AUTH_TLV,        "EIGRP Authentication MD5 TLV"},
++  { MTYPE_EIGRP_AUTH_SHA256_TLV, "EIGRP Authentication SHA256 TLV"},
++  { MTYPE_EIGRP_SEQ_TLV,         "EIGRP Sequence TLV "		},
++  { MTYPE_EIGRP_FSM_MSG,         "EIGRP FSM action message"	},
++  { -1, NULL },
++};
++
+ struct memory_list memory_list_vtysh[] =
+ {
+   { MTYPE_VTYSH_CONFIG,		"Vtysh configuration",		},
+@@ -271,5 +292,6 @@
+   { memory_list_ospf6,	"OSPF6"	},
+   { memory_list_isis,	"ISIS"	},
+   { memory_list_bgp,	"BGP"	},
++  { memory_list_eigrp,	"EIGRP"	},
+   { NULL, NULL},
+ };
+--- a/lib/route_types.txt
++++ b/lib/route_types.txt
+@@ -49,6 +49,7 @@
+ ZEBRA_ROUTE_RIPNG,      ripng,     ripngd, 'R', 0, 1, "RIPng"
+ ZEBRA_ROUTE_OSPF,       ospf,      ospfd,  'O', 1, 0, "OSPF"
+ ZEBRA_ROUTE_OSPF6,      ospf6,     ospf6d, 'O', 0, 1, "OSPFv6"
++ZEBRA_ROUTE_EIGRP,      eigrp,     eigrpd, 'D', 1, 0, "EIGRP"
+ ZEBRA_ROUTE_ISIS,       isis,      isisd,  'I', 1, 1, "IS-IS"
+ ZEBRA_ROUTE_BGP,        bgp,       bgpd,   'B', 1, 1, "BGP"
+ ZEBRA_ROUTE_HSLS,       hsls,      hslsd,  'H', 1, 1, "HSLS"
+@@ -65,6 +66,7 @@
+ ZEBRA_ROUTE_RIPNG,  "Routing Information Protocol next-generation (IPv6) (RIPng)"
+ ZEBRA_ROUTE_OSPF,   "Open Shortest Path First (OSPFv2)"
+ ZEBRA_ROUTE_OSPF6,  "Open Shortest Path First (IPv6) (OSPFv3)"
++ZEBRA_ROUTE_EIGRP,  "Enhanced Interior Gateway Routing Protocol"
+ ZEBRA_ROUTE_ISIS,   "Intermediate System to Intermediate System (IS-IS)"
+ ZEBRA_ROUTE_BGP,    "Border Gateway Protocol (BGP)"
+ ZEBRA_ROUTE_HSLS,   "Hazy-Sighted Link State Protocol (HSLS)"
+--- a/lib/version.h.in
++++ b/lib/version.h.in
+@@ -45,6 +45,8 @@
+
+ #define QUAGGA_COPYRIGHT "Copyright 1996-2005 Kunihiro Ishiguro, et al."
+
++#define QUAGGA_CONFIG_ARGS "@CONFIG_ARGS@"
++
+ pid_t pid_output (const char *);
+
+ #ifndef HAVE_DAEMON
+--- a/vtysh/Makefile.am
++++ b/vtysh/Makefile.am
+@@ -25,6 +25,7 @@
+ 		  $(top_srcdir)/ospfd/*.c $(top_srcdir)/ospf6d/*.c \
+ 		  $(top_srcdir)/ripd/*.c $(top_srcdir)/ripngd/*.c \
+ 		  $(top_srcdir)/babeld/*.c \
++		  $(top_srcdir)/eigrpd/*.c \
+ 		  $(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \
+ 		  $(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \
+ 		  $(top_srcdir)/lib/distribute.c $(top_srcdir)/lib/if_rmap.c \
+--- a/ripd/rip_zebra.c
++++ b/ripd/rip_zebra.c
+@@ -207,6 +207,7 @@
+   {ZEBRA_ROUTE_CONNECT, 1, "connected"},
+   {ZEBRA_ROUTE_STATIC,  1, "static"},
+   {ZEBRA_ROUTE_OSPF,    2, "ospf"},
++  {ZEBRA_ROUTE_EIGRP,   1, "eigrp"},
+   {ZEBRA_ROUTE_BGP,     2, "bgp"},
+   {ZEBRA_ROUTE_HSLS,    1, "hsls"},
+   {ZEBRA_ROUTE_OLSR,    2, "olsr"},
+--- a/vtysh/extract.pl
++++ b/vtysh/extract.pl
+@@ -41,6 +41,8 @@
+ $ignore{'"router bgp " "<1-4294967295>"'} = "ignore";
+ $ignore{'"router bgp " "<1-4294967295>" " view WORD"'} = "ignore";
+ $ignore{'"router isis WORD"'} = "ignore";
++$ignore{'"router eigrp"'} = "ignore";
++$ignore{'"router eigrp " "<1-65535>"'} = "ignore";
+ $ignore{'"router zebra"'} = "ignore";
+ $ignore{'"address-family ipv4"'} = "ignore";
+ $ignore{'"address-family ipv4 (unicast|multicast)"'} = "ignore";
+@@ -91,10 +93,10 @@
+
+         # $protocol is VTYSH_PROTO format for redirection of user input
+         if ($file =~ /lib\/keychain\.c$/) {
+-            $protocol = "VTYSH_RIPD";
++            $protocol = "VTYSH_RIPD|VTYSH_EIGRPD";
+         }
+         elsif ($file =~ /lib\/routemap\.c$/) {
+-            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
++            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_EIGRPD";
+         }
+         elsif ($file =~ /lib\/filter\.c$/) {
+             $protocol = "VTYSH_ALL";
+@@ -103,21 +105,21 @@
+             if ($defun_array[1] =~ m/ipv6/) {
+                 $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
+             } else {
+-                $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA";
++                $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_EIGRPD";
+             }
+         }
+         elsif ($file =~ /lib\/distribute\.c$/) {
+             if ($defun_array[1] =~ m/ipv6/) {
+                 $protocol = "VTYSH_RIPNGD";
+             } else {
+-                $protocol = "VTYSH_RIPD";
++                $protocol = "VTYSH_RIPD|VTYSH_EIGRPD";
+             }
+         }
+         elsif ($file =~ /lib\/if_rmap\.c$/) {
+             if ($defun_array[1] =~ m/ipv6/) {
+                 $protocol = "VTYSH_RIPNGD";
+             } else {
+-                $protocol = "VTYSH_RIPD";
++                $protocol = "VTYSH_RIPD|VTYSH_EIGRPD";
+             }
+         }
+         elsif ($file =~ /lib\/vty\.c$/) {
+--- a/vtysh/extract.pl.in
++++ b/vtysh/extract.pl.in
+@@ -41,6 +41,8 @@
+ $ignore{'"router bgp " "<1-4294967295>"'} = "ignore";
+ $ignore{'"router bgp " "<1-4294967295>" " view WORD"'} = "ignore";
+ $ignore{'"router isis WORD"'} = "ignore";
++$ignore{'"router eigrp"'} = "ignore";
++$ignore{'"router eigrp " "<1-65535>"'} = "ignore";
+ $ignore{'"router zebra"'} = "ignore";
+ $ignore{'"address-family ipv4"'} = "ignore";
+ $ignore{'"address-family ipv4 (unicast|multicast)"'} = "ignore";
+@@ -91,10 +93,10 @@
+
+         # $protocol is VTYSH_PROTO format for redirection of user input
+         if ($file =~ /lib\/keychain\.c$/) {
+-            $protocol = "VTYSH_RIPD";
++            $protocol = "VTYSH_RIPD|VTYSH_EIGRPD";
+         }
+         elsif ($file =~ /lib\/routemap\.c$/) {
+-            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
++            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_EIGRPD";
+         }
+         elsif ($file =~ /lib\/filter\.c$/) {
+             $protocol = "VTYSH_ALL";
+@@ -103,21 +105,21 @@
+             if ($defun_array[1] =~ m/ipv6/) {
+                 $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
+             } else {
+-                $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA";
++                $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_EIGRPD";
+             }
+         }
+         elsif ($file =~ /lib\/distribute\.c$/) {
+             if ($defun_array[1] =~ m/ipv6/) {
+                 $protocol = "VTYSH_RIPNGD";
+             } else {
+-                $protocol = "VTYSH_RIPD";
++                $protocol = "VTYSH_RIPD|VTYSH_EIGRPD";
+             }
+         }
+         elsif ($file =~ /lib\/if_rmap\.c$/) {
+             if ($defun_array[1] =~ m/ipv6/) {
+                 $protocol = "VTYSH_RIPNGD";
+             } else {
+-                $protocol = "VTYSH_RIPD";
++                $protocol = "VTYSH_RIPD|VTYSH_EIGRPD";
+             }
+         }
+         elsif ($file =~ /lib\/vty\.c$/) {
+--- a/vtysh/vtysh.c
++++ b/vtysh/vtysh.c
+@@ -59,6 +59,7 @@
+   { .fd = -1, .name = "bgpd", .flag = VTYSH_BGPD, .path = BGP_VTYSH_PATH},
+   { .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .path = ISIS_VTYSH_PATH},
+   { .fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .path = BABEL_VTYSH_PATH},
++  { .fd = -1, .name = "eigrpd", .flag = VTYSH_EIGRPD, .path = EIGRP_VTYSH_PATH},
+ };
+ 
+ 
+@@ -785,6 +786,12 @@
+   "%s(config-router)# "
+ };
+ 
++static struct cmd_node eigrp_node =
++{
++  EIGRP_NODE,
++  "%s(config-router)# "
++};
++
+ static struct cmd_node ripng_node =
+ {
+   RIPNG_NODE,
+@@ -1004,6 +1011,17 @@
+   return CMD_SUCCESS;
+ }
+ 
++DEFUNSH (VTYSH_EIGRPD,
++	 router_eigrp,
++	 router_eigrp_cmd,
++	 "router eigrp",
++	 "Enable a routing process\n"
++	 "Start EIGRP configuration\n")
++{
++  vty->node = EIGRP_NODE;
++  return CMD_SUCCESS;
++}
++
+ DEFUNSH (VTYSH_OSPF6D,
+ 	 router_ospf6,
+ 	 router_ospf6_cmd,
+@@ -1114,6 +1132,7 @@
+     case RIPNG_NODE:
+     case OSPF_NODE:
+     case OSPF6_NODE:
++    case EIGRP_NODE:
+     case BABEL_NODE:
+     case ISIS_NODE:
+     case MASC_NODE:
+@@ -1253,6 +1272,20 @@
+        "quit",
+        "Exit current mode and down to previous mode\n")
+ 
++DEFUNSH (VTYSH_EIGRPD,
++	 vtysh_exit_eigrpd,
++	 vtysh_exit_eigrpd_cmd,
++	 "exit",
++	 "Exit current mode and down to previous mode\n")
++{
++  return vtysh_exit (vty);
++}
++
++ALIAS (vtysh_exit_eigrpd,
++       vtysh_quit_eigrpd_cmd,
++       "quit",
++       "Exit current mode and down to previous mode\n")
++
+ DEFUNSH (VTYSH_OSPF6D,
+ 	 vtysh_exit_ospf6d,
+ 	 vtysh_exit_ospf6d_cmd,
+@@ -1307,7 +1340,7 @@
+ }
+ 
+ /* TODO Implement "no interface command in isisd. */
+-DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D,
++DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_EIGRPD,
+        vtysh_no_interface_cmd,
+        "no interface IFNAME",
+        NO_STR
+@@ -1316,13 +1349,13 @@
+ 
+ /* TODO Implement interface description commands in ripngd, ospf6d
+  * and isisd. */
+-DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD,
++DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_EIGRPD,
+        interface_desc_cmd,
+        "description .LINE",
+        "Interface specific description\n"
+        "Characters describing this interface\n")
+        
+-DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD,
++DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_EIGRPD,
+        no_interface_desc_cmd,
+        "no description",
+        NO_STR
+@@ -2266,6 +2299,7 @@
+   install_node (&bgp_ipv6m_node, NULL);
+ /* #endif */
+   install_node (&ospf_node, NULL);
++  install_node (&eigrp_node, NULL);
+ /* #ifdef HAVE_IPV6 */
+   install_node (&ripng_node, NULL);
+   install_node (&ospf6_node, NULL);
+@@ -2290,6 +2324,7 @@
+   vtysh_install_default (BGP_IPV6_NODE);
+   vtysh_install_default (BGP_IPV6M_NODE);
+   vtysh_install_default (OSPF_NODE);
++  vtysh_install_default (EIGRP_NODE);
+   vtysh_install_default (RIPNG_NODE);
+   vtysh_install_default (OSPF6_NODE);
+   vtysh_install_default (BABEL_NODE);
+@@ -2315,6 +2350,8 @@
+   install_element (RIPNG_NODE, &vtysh_quit_ripngd_cmd);
+   install_element (OSPF_NODE, &vtysh_exit_ospfd_cmd);
+   install_element (OSPF_NODE, &vtysh_quit_ospfd_cmd);
++  install_element (EIGRP_NODE, &vtysh_exit_eigrpd_cmd);
++  install_element (EIGRP_NODE, &vtysh_quit_eigrpd_cmd);
+   install_element (OSPF6_NODE, &vtysh_exit_ospf6d_cmd);
+   install_element (OSPF6_NODE, &vtysh_quit_ospf6d_cmd);
+   install_element (BGP_NODE, &vtysh_exit_bgpd_cmd);
+
+--- a/vtysh/vtysh.h
++++ b/vtysh/vtysh.h
+@@ -30,9 +30,10 @@
+ #define VTYSH_BGPD   0x20
+ #define VTYSH_ISISD  0x40
+ #define VTYSH_BABELD  0x80
+-#define VTYSH_ALL	  VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_BABELD
+-#define VTYSH_RMAP	  VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_BABELD
+-#define VTYSH_INTERFACE	  VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_BABELD
++#define VTYSH_EIGRPD   0x200
++#define VTYSH_ALL	  VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_BABELD|VTYSH_EIGRPD
++#define VTYSH_RMAP	  VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_BABELD|VTYSH_EIGRPD
++#define VTYSH_INTERFACE	  VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_BABELD|VTYSH_EIGRPD
+
+ /* vtysh local configuration file. */
+ #define VTYSH_DEFAULT_CONFIG "vtysh.conf"
+--- a/vtysh/vtysh_config.c
++++ b/vtysh/vtysh_config.c
+@@ -202,6 +202,8 @@
+ 	config = config_get (BABEL_NODE, line);
+       else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
+ 	config = config_get (BGP_NODE, line);
++      else if (strncmp (line, "router eigrp", strlen ("router eigrp")) == 0)
++	config = config_get (EIGRP_NODE, line);
+       else if (strncmp (line, "router isis", strlen ("router isis")) == 0)
+   	config = config_get (ISIS_NODE, line);
+       else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
+
+--- a/zebra/zebra_vty.c
++++ b/zebra/zebra_vty.c
+@@ -556,6 +556,7 @@
+ #define ONE_WEEK_SECOND 60*60*24*7
+       if (rib->type == ZEBRA_ROUTE_RIP
+ 	  || rib->type == ZEBRA_ROUTE_OSPF
++	  || rib->type == ZEBRA_ROUTE_EIGRP
+ 	  || rib->type == ZEBRA_ROUTE_BABEL
+ 	  || rib->type == ZEBRA_ROUTE_ISIS
+ 	  || rib->type == ZEBRA_ROUTE_BGP
+@@ -785,6 +786,7 @@
+ 
+       if (rib->type == ZEBRA_ROUTE_RIP
+ 	  || rib->type == ZEBRA_ROUTE_OSPF
++	  || rib->type == ZEBRA_ROUTE_EIGRP
+ 	  || rib->type == ZEBRA_ROUTE_BABEL
+ 	  || rib->type == ZEBRA_ROUTE_ISIS
+ 	  || rib->type == ZEBRA_ROUTE_BGP
+--- a/zebra/zebra_rib.c
++++ b/zebra/zebra_rib.c
+@@ -66,6 +66,7 @@
+   [ZEBRA_ROUTE_RIPNG]   = {ZEBRA_ROUTE_RIPNG,   120},
+   [ZEBRA_ROUTE_OSPF]    = {ZEBRA_ROUTE_OSPF,    110},
+   [ZEBRA_ROUTE_OSPF6]   = {ZEBRA_ROUTE_OSPF6,   110},
++  [ZEBRA_ROUTE_EIGRP]   = {ZEBRA_ROUTE_EIGRP,    90},
+   [ZEBRA_ROUTE_ISIS]    = {ZEBRA_ROUTE_ISIS,    115},
+   [ZEBRA_ROUTE_BGP]     = {ZEBRA_ROUTE_BGP,      20  /* IBGP is 200. */},
+   [ZEBRA_ROUTE_HSLS]    = {ZEBRA_ROUTE_HSLS,      0},
+@@ -1400,6 +1401,7 @@
+   [ZEBRA_ROUTE_RIPNG]   = 2,
+   [ZEBRA_ROUTE_OSPF]    = 2,
+   [ZEBRA_ROUTE_OSPF6]   = 2,
++  [ZEBRA_ROUTE_EIGRP]   = 2,
+   [ZEBRA_ROUTE_ISIS]    = 2,
+   [ZEBRA_ROUTE_BGP]     = 3,
+   [ZEBRA_ROUTE_HSLS]    = 4,
diff --git a/quagga/patches/200-actual-eigrp-files.patch b/quagga/patches/200-actual-eigrp-files.patch
new file mode 100644
index 0000000..b016763
--- /dev/null
+++ b/quagga/patches/200-actual-eigrp-files.patch
@@ -0,0 +1,14590 @@
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_const.h eigrp/eigrpd/eigrp_const.h
+--- a/eigrpd/eigrp_const.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_const.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,427 @@
++/*
++ * EIGRP Definition of Constants.
++ * Copyright (C) 2013-2015
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *   Frantisek Gazo
++ *   Tomas Hvorkovy
++ *   Martin Kontsek
++ *   Lukas Koribsky
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRP_CONST_H_
++#define _ZEBRA_EIGRP_CONST_H_
++
++#define FALSE 0
++
++#define EIGRP_NEIGHBOR_DOWN           0
++#define EIGRP_NEIGHBOR_PENDING        1
++#define EIGRP_NEIGHBOR_UP             2
++#define EIGRP_NEIGHBOR_STATE_MAX      3
++
++/*Packet requiring ack will be retransmitted again after this time*/
++#define EIGRP_PACKET_RETRANS_TIME        2 /* in seconds */
++#define EIGRP_PACKET_RETRANS_MAX         16 /* number of retrans attempts */
++#define PLAINTEXT_LENGTH                 81
++
++/*Metric variance multiplier*/
++#define EIGRP_VARIANCE_DEFAULT  1
++#define EIGRP_MAX_PATHS_DEFAULT 4
++
++
++/* Return values of functions involved in packet verification */
++#define MSG_OK    0
++#define MSG_NG    1
++
++#define EIGRP_HEADER_VERSION            2
++
++/* Default protocol, port number. */
++#ifndef IPPROTO_EIGRPIGP
++#define IPPROTO_EIGRPIGP         88
++#endif /* IPPROTO_EIGRPIGP */
++
++#define EIGRP_AUTH_MD5_TLV_SIZE          40
++#define EIGRP_AUTH_SHA256_TLV_SIZE          56
++
++/*Cisco routers use only first 44 bytes of basic hello for their MD5 calculations*/
++#define EIGRP_MD5_BASIC_COMPUTE       44
++#define EIGRP_MD5_UPDATE_INIT_COMPUTE       40
++
++
++
++#define EIGRP_AUTH_BASIC_HELLO_FLAG       0x01
++#define EIGRP_AUTH_TID_HELLO_FLAG       0x02
++#define EIGRP_AUTH_UPDATE_INIT_FLAG       0x04
++#define EIGRP_AUTH_UPDATE_FLAG            0x08
++#define EIGRP_AUTH_EXTRA_SALT_FLAG        0x10
++
++#define EIGRP_NEXT_SEQUENCE_TLV_SIZE     8
++
++/* IP TTL for EIGRP protocol. */
++#define EIGRP_IP_TTL             1
++
++/* VTY port number. */
++#define EIGRP_VTY_PORT          2609
++
++/* Default configuration file name for eigrp. */
++#define EIGRP_DEFAULT_CONFIG   "eigrpd.conf"
++
++#define EIGRP_HELLO_INTERVAL_DEFAULT        5
++#define EIGRP_HOLD_INTERVAL_DEFAULT         15
++#define EIGRP_BANDWIDTH_DEFAULT             10000000
++#define EIGRP_DELAY_DEFAULT                 1000
++#define EIGRP_RELIABILITY_DEFAULT           255
++#define EIGRP_LOAD_DEFAULT                  1
++
++#define EIGRP_MULTICAST_ADDRESS            0xe000000A /*224.0.0.10*/
++
++#define EIGRP_MAX_METRIC                   0xffffffffU    /*4294967295*/
++
++#define DEFAULT_ROUTE               ZEBRA_ROUTE_MAX
++#define DEFAULT_ROUTE_TYPE(T) ((T) == DEFAULT_ROUTE)
++
++#define INTERFACE_DOWN_BY_ZEBRA       1
++#define INTERFACE_DOWN_BY_VTY         2
++
++#define EIGRP_HELLO_NORMAL                    0x00
++#define EIGRP_HELLO_GRACEFUL_SHUTDOWN         0x01
++#define EIGRP_HELLO_ADD_SEQUENCE              0x02
++
++    /* EIGRP Network Type. */
++ #define EIGRP_IFTYPE_NONE                0
++ #define EIGRP_IFTYPE_POINTOPOINT         1
++ #define EIGRP_IFTYPE_BROADCAST           2
++ #define EIGRP_IFTYPE_NBMA                3
++ #define EIGRP_IFTYPE_POINTOMULTIPOINT    4
++ #define EIGRP_IFTYPE_LOOPBACK            5
++ #define EIGRP_IFTYPE_MAX                 6
++
++#define EIGRP_IF_ACTIVE                  0
++#define EIGRP_IF_PASSIVE                 1
++
++/* EIGRP TT destination type */
++#define EIGRP_TOPOLOGY_TYPE_CONNECTED           0 // Connected network
++#define EIGRP_TOPOLOGY_TYPE_REMOTE              1 // Remote internal network
++#define EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL     2 // Remote external network
++
++/*EIGRP TT entry flags*/
++#define EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG     1
++#define EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG    2
++#define EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG		4
++#define EIGRP_NEIGHBOR_ENTRY_EXTERNAL_FLAG		8
++
++/*EIGRP FSM state count, event count*/
++#define EIGRP_FSM_STATE_MAX                  5
++#define EIGRP_FSM_EVENT_MAX                  16
++
++/*EGRP FSM states*/
++#define EIGRP_FSM_STATE_PASSIVE              0
++#define EIGRP_FSM_STATE_ACTIVE_0             1
++#define EIGRP_FSM_STATE_ACTIVE_1             2
++#define EIGRP_FSM_STATE_ACTIVE_2             3
++#define EIGRP_FSM_STATE_ACTIVE_3             4
++
++/*EIGRP FSM events return values*/
++#define EIGRP_FSM_NEED_UPDATE				1
++#define EIGRP_FSM_NEED_QUERY				2
++
++/*EIGRP FSM events*/
++#define EIGRP_FSM_EVENT_NQ_FCN                  0 /*input event other than query from succ, FC not satisfied*/
++#define EIGRP_FSM_EVENT_LR                      1 /*last reply, FD is reset*/
++#define EIGRP_FSM_EVENT_Q_FCN                   2 /*query from succ, FC not satisfied*/
++#define EIGRP_FSM_EVENT_LR_FCS                  3 /*last reply, FC satisfied with current value of FDij*/
++#define EIGRP_FSM_EVENT_DINC                    4 /*distance increase while in active state*/
++#define EIGRP_FSM_EVENT_QACT                    5 /*query from succ while in active state*/
++#define EIGRP_FSM_EVENT_LR_FCN                  6 /*last reply, FC not satisfied with current value of FDij*/
++#define EIGRP_FSM_KEEP_STATE                    7 /*state not changed, usually by receiving not last reply */
++
++#define INT_TYPES_CMD_STR						 \
++	"detail|fastethernet|loopback|static"
++
++#define INT_TYPES_DESC							\
++	"Virtual Ethernet interface\n"				\
++	"FastEthernet IEEE 802.3\n"					\
++	"Loopback interface\n"						\
++	"Show static peer information\n"
++
++/**
++ * External routes originate from some other protocol - these are them
++ */
++#define NULL_PROTID		0		/*!< unknown protocol */
++#define IGRP_PROTID		1		/*!< IGRP.. whos your daddy! */
++#define EIGRP_PROTID		2		/*!< EIGRP - Just flat out the best */
++#define STATIC_PROTID		3		/*!< Staticly configured source */
++#define RIP_PROTID		4		/*!< Routing Information Protocol */
++#define HELLO_PROTID		5		/*!< Hello? RFC-891 you there? */
++#define OSPF_PROTID		6		/*!< OSPF - Open Shortest Path First */
++#define ISIS_PROTID		7		/*!< Intermediate System To Intermediate System */
++#define EGP_PROTID		8		/*!< Exterior Gateway Protocol */
++#define BGP_PROTID		9		/*!< Border Gateway Protocol */
++#define IDRP_PROTID		10		/*!< InterDomain Routing Protocol */
++#define CONN_PROTID		11		/*!< Connected source */
++
++/* 
++ * metric k-value defaults
++ */
++#define EIGRP_K1_DEFAULT	1		//!< unweighed inverse bandwidth
++#define EIGRP_K2_DEFAULT	0		//!< no loading term
++#define EIGRP_K3_DEFAULT	1		//!< unweighted delay
++#define EIGRP_K4_DEFAULT	0		//!< no reliability term
++#define EIGRP_K5_DEFAULT	0		//!< no reliability term
++#define EIGRP_K6_DEFAULT	0		//!< do not add in extended metrics
++
++
++/*
++ * EIGRP Fixed header
++ */
++#define EIGRP_HEADER_LEN        20U
++#define EIGRP_PACKET_MAX_LEN    65535U   /* includes IP Header size. */
++
++
++#define EIGRP_TLV_HDR_LENGTH    4
++
++/**
++ * EIGRP Packet Opcodes
++ */
++#define EIGRP_OPC_UPDATE        1       /*!< packet containing routing information */
++#define EIGRP_OPC_REQUEST       2       /*!< sent to request one or more routes */
++#define EIGRP_OPC_QUERY         3       /*!< sent when a routing is in active start */
++#define EIGRP_OPC_REPLY         4       /*!< sent in response to a query */
++#define EIGRP_OPC_HELLO         5       /*!< sent to maintain a peering session */
++#define EIGRP_OPC_IPXSAP        6       /*!< IPX SAP information */
++#define EIGRP_OPC_PROBE         7       /*!< for test purposes   */
++#define EIGRP_OPC_ACK           8       /*!< acknowledge         */
++#define EIGRP_OPC_SIAQUERY      10      /*!< QUERY - with relaxed restrictions */
++#define EIGRP_OPC_SIAREPLY      11      /*!< REPLY - may contain old routing information */
++
++/**
++ * EIGRP TLV Range definitions
++ *      PDM             TLV Range
++ *      General         0x0000
++ *      IPv4            0x0100                  ** TLVs for one and all
++ *      ATALK           0x0200                  ** legacy
++ *      IPX             0x0300                  ** discontinued
++ *      IPv6            0x0400                  ** legacy
++ *      Multiprotocol   0x0600                  ** wide metrics
++ *      MultiTopology   0x00f0                  ** deprecated
++ */
++#define EIGRP_TLV_RANGEMASK     0xfff0          /*!< should be 0xff00 - opps */
++#define EIGRP_TLV_GENERAL       0x0000
++
++/**
++ * 1.2 TLV Definitions  ** legacy
++ * These are considered legacyu and are only used for backward compability with
++ * older Cisco Routers.  They should not be your first choice for packet codings
++ */
++#define EIGRP_TLV_IPv4          0x0100          /*!< Classic IPv4 TLV encoding */
++#define EIGRP_TLV_ATALK         0x0200          /*!< Classic Appletalk TLV encoding*/
++#define EIGRP_TLV_IPX           0x0300          /*!< Classic IPX TLV encoding */
++#define EIGRP_TLV_IPv6          0x0400          /*!< Classic IPv6 TLV encoding */
++
++/**
++ * 2.0 Multi-Protocol TLV Definitions
++ * These are the current packet formats and should be used for packets
++ */
++#define EIGRP_TLV_MP            0x0600          /*!< Non-PDM specific encoding */
++
++/**
++ * TLV type definitions.  Generic (protocol-independent) TLV types are
++ * defined here.  Protocol-specific ones are defined elsewhere.
++ */
++#define EIGRP_TLV_PARAMETER             (EIGRP_TLV_GENERAL | 0x0001)    /*!< eigrp parameters */
++#define EIGRP_TLV_PARAMETER_LEN         (12U)
++#define EIGRP_TLV_AUTH                  (EIGRP_TLV_GENERAL | 0x0002)    /*!< authentication */
++#define EIGRP_TLV_SEQ                   (EIGRP_TLV_GENERAL | 0x0003)    /*!< sequenced packet */
++#define EIGRP_TLV_SEQ_BASE_LEN          (5U)
++#define EIGRP_TLV_SW_VERSION            (EIGRP_TLV_GENERAL | 0x0004)    /*!< software version */
++#define EIGRP_TLV_SW_VERSION_LEN        (8U)
++#define EIGRP_TLV_NEXT_MCAST_SEQ        (EIGRP_TLV_GENERAL | 0x0005)    /*!< sequence number */
++#define EIGRP_TLV_PEER_TERMINATION      (EIGRP_TLV_GENERAL | 0x0007)    /*!< peer termination */
++#define EIGRP_TLV_PEER_TIDLIST          (EIGRP_TLV_GENERAL | 0x0008)    /*!< peer sub-topology list */
++
++/* Older cisco routers send TIDLIST value wrong, adding for backwards compatabily */
++#define EIGRP_TLV_PEER_MTRLIST          (EIGRP_TLV_GENERAL | 0x00f5)
++
++/**
++ * Route Based TLVs
++ */
++#define EIGRP_TLV_REQUEST               0x0001
++#define EIGRP_TLV_INTERNAL              0x0002
++#define EIGRP_TLV_EXTERNAL              0x0003
++#define EIGRP_TLV_COMMUNITY             0x0004
++#define EIGRP_TLV_TYPEMASK              0x000f
++
++#define EIGRP_TLV_IPv4_REQ              (EIGRP_TLV_IPv4 | EIGRP_TLV_REQUEST)
++#define EIGRP_TLV_IPv4_INT              (EIGRP_TLV_IPv4 | EIGRP_TLV_INTERNAL)
++#define EIGRP_TLV_IPv4_EXT              (EIGRP_TLV_IPv4 | EIGRP_TLV_EXTERNAL)
++#define EIGRP_TLV_IPv4_COM              (EIGRP_TLV_IPv4 | EIGRP_TLV_COMMUNITY)
++
++/**
++ *
++ * extdata flag field definitions
++ */
++#define EIGRP_OPAQUE_EXT        0x01    /*!< Route is external */
++#define EIGRP_OPAQUE_CD         0x02    /*!< Candidate default route */
++
++/**
++ * Address-Family types are taken from:
++ *       http://www.iana.org/assignments/address-family-numbers
++ * to provide a standards based exchange of AFI information between
++ * EIGRP routers.
++ */
++#define EIGRP_AF_IPv4           1       /*!< IPv4 (IP version 4) */
++#define EIGRP_AF_IPv6           2       /*!< IPv6 (IP version 6) */
++#define EIGRP_AF_IPX            11      /*!< IPX */
++#define EIGRP_AF_ATALK          12      /*!< Appletalk */
++#define EIGRP_SF_COMMON         16384   /*!< Cisco Service Family */
++#define EIGRP_SF_IPv4           16385   /*!< Cisco IPv4 Service Family */
++#define EIGRP_SF_IPv6           16386   /*!< Cisco IPv6 Service Family */
++
++/**
++ * Authentication types supported by EIGRP
++ */
++#define EIGRP_AUTH_TYPE_NONE            0
++#define EIGRP_AUTH_TYPE_TEXT            1
++#define EIGRP_AUTH_TYPE_MD5             2
++#define EIGRP_AUTH_TYPE_MD5_LEN         16
++#define EIGRP_AUTH_TYPE_SHA256          3
++#define EIGRP_AUTH_TYPE_SHA256_LEN      32
++
++/**
++ * opaque flag field definitions
++ */
++#define EIGRP_OPAQUE_SRCWD      0x01    /*!< Route Source Withdraw */
++#define EIGRP_OPAQUE_ACTIVE     0x04    /*!< Route is currently in active state */
++#define EIGRP_OPAQUE_REPL       0x08    /*!< Route is replicated from different tableid */
++
++/**
++ * pak flag bit field definitions - 0 (none)-7 source priority
++ */
++#define EIGRP_PRIV_DEFAULT      0x00    /* 0 (none)-7 source priority */
++#define EIGRP_PRIV_LOW          0x01
++#define EIGRP_PRIV_MEDIUM       0x04
++#define EIGRP_PRIV_HIGH         0x07
++
++/*
++ * Init bit definition. First unicast transmitted Update has this
++ * bit set in the flags field of the fixed header. It tells the neighbor
++ * to down-load his topology table.
++ */
++#define EIGRP_INIT_FLAG 0x01
++
++/*
++ * CR bit (Conditionally Received) definition in flags field on header. Any
++ * packets with the CR-bit set can be accepted by an EIGRP speaker if and
++ * only if a previous Hello was received with the SEQUENCE_TYPE TLV present.
++ *
++ * This allows multicasts to be transmitted in order and reliably at the
++ * same time as unicasts are transmitted.
++ */
++#define EIGRP_CR_FLAG 0x02
++
++/*
++ * RS bit.  The Restart flag is set in the hello and the init
++ * update packets during the nsf signaling period.  A nsf-aware
++ * router looks at the RS flag to detect if a peer is restarting
++ * and maintain the adjacency. A restarting router looks at
++ * this flag to determine if the peer is helping out with the restart.
++ */
++#define EIGRP_RS_FLAG 0x04
++
++/*
++ * EOT bit.  The End-of-Table flag marks the end of the start-up updates
++ * sent to a new peer.  A nsf restarting router looks at this flag to
++ * determine if it has finished receiving the start-up updates from all
++ * peers.  A nsf-aware router waits for this flag before cleaning up
++ * the stale routes from the restarting peer.
++ */
++#define EIGRP_EOT_FLAG 0x08
++
++/**
++ * EIGRP Virtual Router ID
++ *
++ * Define values to deal with EIGRP virtual router ids.  Virtual
++ * router IDs are stored in the upper short of the EIGRP fixed packet
++ * header.  The lower short of the packet header continues to be used
++ * as asystem number.
++ *
++ * Virtual Router IDs are PDM-independent.  All PDMs will use
++ * VRID_BASE to indicate the 'base' or 'legacy' EIGRP instance.
++ * All PDMs need to initialize their vrid to VRID_BASE for compatibility
++ * with legacy routers.
++ * Once IPv6 supports 'MTR Multicast', it will use the same VRID as
++ * IPv4.  No current plans to support VRIDs on IPX. :)
++ * Initial usage of VRID is to signal usage of Multicast topology for
++ * MTR.
++ *
++ * VRID_MCAST is a well known constant, other VRIDs will be determined
++ * programmatic...
++ *
++ * With the addition of SAF the VRID space has been divided into two
++ * segments 0x0000-0x7fff is for EIGRP and vNets, 0x8000-0xffff is
++ * for saf and its associated vNets.
++ */
++#define EIGRP_VRID_MASK         0x8001
++#define EIGRP_VRID_AF_BASE      0x0000
++#define EIGRP_VRID_MCAST_BASE   0x0001
++#define EIGRP_VRID_SF_BASE      0x8000
++
++/* Extended Attributes for a destination */
++#define EIGRP_ATTR_HDRLEN (2)
++#define EIGRP_ATTR_MAXDATA (512)
++
++#define EIGRP_ATTR_NOOP         0       /*!< No-Op used as offset padding */
++#define EIGRP_ATTR_SCALED       1       /*!< Scaled metric values */
++#define EIGRP_ATTR_TAG          2       /*!< Tag assigned by Admin for dest */
++#define EIGRP_ATTR_COMM         3       /*!< Community attribute for dest */
++#define EIGRP_ATTR_JITTER       4       /*!< Variation in path delay */
++#define EIGRP_ATTR_QENERGY      5       /*!< Non-Active energy usage along path */
++#define EIGRP_ATTR_ENERGY       6       /*!< Active energy usage along path */
++
++/*
++ * Begin EIGRP-BGP interoperability communities
++ */
++#define EIGRP_EXTCOMM_SOO_ASFMT         0x0003 /* Site-of-Origin, BGP AS format */
++#define EIGRP_EXTCOMM_SOO_ADRFMT        0x0103 /* Site-of-Origin, BGP/EIGRP addr format */
++
++/*
++ * EIGRP Specific communities
++ */
++#define EIGRP_EXTCOMM_EIGRP             0x8800 /* EIGRP route information appended*/
++#define EIGRP_EXTCOMM_DAD               0x8801 /* EIGRP AS + Delay           */
++#define EIGRP_EXTCOMM_VRHB              0x8802 /* EIGRP Vector: Reliability + Hop + BW */
++#define EIGRP_EXTCOMM_SRLM              0x8803 /* EIGRP System: Reserve +Load + MTU   */
++#define EIGRP_EXTCOMM_SAR               0x8804 /* EIGRP System: Remote AS + Remote ID  */
++#define EIGRP_EXTCOMM_RPM               0x8805 /* EIGRP Remote: Protocol + Metric    */
++#define EIGRP_EXTCOMM_VRR               0x8806 /* EIGRP Vecmet: Rsvd + (internal) Routerid */
++
++
++/*
++ * EIGRP Filter constants
++ */
++#define EIGRP_FILTER_IN  0
++#define EIGRP_FILTER_OUT 1
++#define EIGRP_FILTER_MAX 2
++
++#endif /* _ZEBRA_EIGRP_CONST_H_ */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrpd.c eigrp/eigrpd/eigrpd.c
+--- a/eigrpd/eigrpd.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrpd.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,295 @@
++/*
++ * EIGRP Daemon Program.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "thread.h"
++#include "vty.h"
++#include "command.h"
++#include "linklist.h"
++#include "prefix.h"
++#include "table.h"
++#include "if.h"
++#include "memory.h"
++#include "stream.h"
++#include "log.h"
++#include "sockunion.h"          /* for inet_aton () */
++#include "zclient.h"
++#include "plist.h"
++#include "sockopt.h"
++#include "keychain.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_network.h"
++#include "eigrpd/eigrp_topology.h"
++
++
++static struct eigrp_master eigrp_master;
++
++struct eigrp_master *eigrp_om;
++
++static void eigrp_finish_final(struct eigrp *);
++static void eigrp_delete(struct eigrp *);
++static struct eigrp *eigrp_new(const char *);
++static void eigrp_add(struct eigrp *);
++
++extern struct zclient *zclient;
++extern struct in_addr router_id_zebra;
++
++
++/*
++ * void eigrp_router_id_update(struct eigrp *eigrp)
++ *
++ * Description:
++ * update routerid associated with this instance of EIGRP.
++ * If the id changes, then call if_update for each interface
++ * to resync the topology database with all neighbors
++ *
++ * Select the router ID based on these priorities:
++ *   1. Statically assigned router ID is always the first choice.
++ *   2. If there is no statically assigned router ID, then try to stick
++ *      with the most recent value, since changing router ID's is very
++ *      disruptive.
++ *   3. Last choice: just go with whatever the zebra daemon recommends.
++ *
++ * Note:
++ * router id for EIGRP is really just a 32 bit number. Cisco historically
++ * displays it in dotted decimal notation, and will pickup an IP address
++ * from an interface so it can be 'auto-configed" to a uniqe value
++ *
++ * This does not work for IPv6, and to make the code simpler, its
++ * stored and processed internerall as a 32bit number
++ */
++void
++eigrp_router_id_update (struct eigrp *eigrp)
++{
++  struct interface *ifp;
++  struct listnode *node;
++  u_int32_t router_id, router_id_old;
++
++  router_id_old = eigrp->router_id;
++
++  if (eigrp->router_id_static != 0)
++    router_id = eigrp->router_id_static;
++
++  else if (eigrp->router_id != 0)
++    router_id = eigrp->router_id;
++
++  else
++    router_id = router_id_zebra.s_addr;
++
++  eigrp->router_id = router_id;
++  if (router_id_old != router_id)
++    {
++//      if (IS_DEBUG_EIGRP_EVENT)
++//        zlog_debug("Router-ID[NEW:%s]: Update", inet_ntoa(eigrp->router_id));
++
++      /* update eigrp_interface's */
++      for (ALL_LIST_ELEMENTS_RO(eigrp_om->iflist, node, ifp))
++        eigrp_if_update(ifp);
++    }
++}
++
++void
++eigrp_master_init ()
++{
++  memset(&eigrp_master, 0, sizeof(struct eigrp_master));
++
++  eigrp_om = &eigrp_master;
++  eigrp_om->eigrp = list_new();
++  eigrp_om->master = thread_master_create();
++  eigrp_om->start_time = quagga_time(NULL);
++}
++
++
++/* Allocate new eigrp structure. */
++static struct eigrp *
++eigrp_new (const char *AS)
++{
++  struct eigrp *new = XCALLOC(MTYPE_EIGRP_TOP, sizeof (struct eigrp));
++  int eigrp_socket;
++
++  /* init information relevant to peers */
++  new->vrid = 0;
++  new->AS = atoi(AS);
++  new->router_id = 0L;
++  new->router_id_static = 0L;
++  new->sequence_number = 1;
++
++  /*Configure default K Values for EIGRP Process*/
++  new->k_values[0] = EIGRP_K1_DEFAULT;
++  new->k_values[1] = EIGRP_K2_DEFAULT;
++  new->k_values[2] = EIGRP_K3_DEFAULT;
++  new->k_values[3] = EIGRP_K4_DEFAULT;
++  new->k_values[4] = EIGRP_K5_DEFAULT;
++  new->k_values[5] = EIGRP_K6_DEFAULT;
++
++  /* init internal data structures */
++  new->eiflist = list_new();
++  new->passive_interface_default = EIGRP_IF_ACTIVE;
++  new->networks = route_table_init();
++
++  if ((eigrp_socket = eigrp_sock_init()) < 0)
++    {
++      zlog_err("eigrp_new: fatal error: eigrp_sock_init was unable to open "
++               "a socket");
++      exit (1);
++    }
++
++  new->fd = eigrp_socket;
++  new->maxsndbuflen = getsockopt_so_sendbuf(new->fd);
++
++  if ((new->ibuf = stream_new(EIGRP_PACKET_MAX_LEN+1)) == NULL)
++    {
++      zlog_err("eigrp_new: fatal error: stream_new (%u) failed allocating ibuf",
++               EIGRP_PACKET_MAX_LEN+1);
++      exit(1);
++    }
++
++  new->t_read = thread_add_read(master, eigrp_read, new, new->fd);
++  new->oi_write_q = list_new();
++
++  new->topology_table = eigrp_topology_new();
++
++  new->neighbor_self = eigrp_nbr_new(NULL);
++  inet_aton("127.0.0.1", &new->neighbor_self->src);
++
++  new->variance = EIGRP_VARIANCE_DEFAULT;
++  new->max_paths = EIGRP_MAX_PATHS_DEFAULT;
++
++  new->serno = 0;
++  new->serno_last_update = 0;
++  new->topology_changes_externalIPV4 = list_new ();
++  new->topology_changes_internalIPV4 = list_new ();
++
++  return new;
++}
++
++static void
++eigrp_add (struct eigrp *eigrp)
++{
++  listnode_add(eigrp_om->eigrp, eigrp);
++}
++
++static void
++eigrp_delete (struct eigrp *eigrp)
++{
++  listnode_delete(eigrp_om->eigrp, eigrp);
++}
++
++struct eigrp *
++eigrp_get (const char *AS)
++{
++  struct eigrp *eigrp;
++
++  eigrp = eigrp_lookup();
++  if (eigrp == NULL)
++    {
++      eigrp = eigrp_new(AS);
++      eigrp_add(eigrp);
++    }
++
++  return eigrp;
++}
++
++/* Shut down the entire process */
++void
++eigrp_terminate (void)
++{
++  struct eigrp *eigrp;
++  struct listnode *node, *nnode;
++
++  /* shutdown already in progress */
++    if (CHECK_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN))
++      return;
++
++    SET_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN);
++
++  /* exit immediately if EIGRP not actually running */
++  if (listcount(eigrp_om->eigrp) == 0)
++    exit(0);
++
++  for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp))
++    eigrp_finish(eigrp);
++}
++
++void
++eigrp_finish (struct eigrp *eigrp)
++{
++
++  eigrp_finish_final(eigrp);
++
++  /* eigrp being shut-down? If so, was this the last eigrp instance? */
++    if (CHECK_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN)
++        && (listcount(eigrp_om->eigrp) == 0))
++      exit(0);
++
++  return;
++}
++
++/* Final cleanup of eigrp instance */
++static void
++eigrp_finish_final (struct eigrp *eigrp)
++{
++
++  close(eigrp->fd);
++
++  if (zclient)
++    zclient_free(zclient);
++
++  list_delete(eigrp->eiflist);
++  list_delete(eigrp->oi_write_q);
++  list_delete(eigrp->topology_changes_externalIPV4);
++  list_delete(eigrp->topology_changes_internalIPV4);
++
++  eigrp_topology_cleanup(eigrp->topology_table);
++  eigrp_topology_free(eigrp->topology_table);
++
++  eigrp_nbr_delete(eigrp->neighbor_self);
++
++  eigrp_delete(eigrp);
++
++  XFREE(MTYPE_EIGRP_TOP,eigrp);
++
++}
++
++/*Look for existing eigrp process*/
++struct eigrp *
++eigrp_lookup (void)
++{
++  if (listcount(eigrp_om->eigrp) == 0)
++    return NULL;
++
++  return listgetdata(listhead(eigrp_om->eigrp));
++}
+diff -Nur quagga-0.99.22.4/eigrpd/eigrpd.conf.sample eigrp/eigrpd/eigrpd.conf.sample
+--- a/eigrpd/eigrpd.conf.sample	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrpd.conf.sample	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,13 @@
++! -*- eigrpd -*-
++!
++! EIGRPDd sample configuration file
++!
++!
++hostname eigrpd
++password zebra
++!enable password please-set-at-here
++!
++!router eigrp 4453
++!  network 192.168.1.0/24
++!
++log stdout
+diff -Nur quagga-0.99.22.4/eigrpd/eigrpd.h eigrp/eigrpd/eigrpd.h
+--- a/eigrpd/eigrpd.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrpd.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,54 @@
++/*
++ * EIGRP main header.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRPD_H
++#define _ZEBRA_EIGRPD_H
++
++#include <zebra.h>
++
++#include "filter.h"
++#include "log.h"
++
++/* Set EIGRP version is "classic" - wide metrics comes next */
++#define EIGRP_MAJOR_VERSION     1
++#define EIGRP_MINOR_VERSION	2
++
++/* Extern variables. */
++extern struct zclient *zclient;
++extern struct thread_master *master;
++extern struct eigrp_master *eigrp_om;
++
++/* Prototypes */
++ extern void eigrp_master_init (void);
++ extern void eigrp_terminate (void);
++ extern void eigrp_finish (struct eigrp *);
++ extern struct eigrp *eigrp_get (const char *);
++ extern struct eigrp *eigrp_lookup (void);
++ extern void eigrp_router_id_update (struct eigrp *);
++
++#endif /* _ZEBRA_EIGRPD_H */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_dump.c eigrp/eigrpd/eigrp_dump.c
+--- a/eigrpd/eigrp_dump.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_dump.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,924 @@
++/*
++ * EIGRP Dump Functions and Debugging.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "linklist.h"
++#include "thread.h"
++#include "prefix.h"
++#include "command.h"
++#include "stream.h"
++#include "log.h"
++#include "sockopt.h"
++#include "table.h"
++#include "keychain.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_network.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_topology.h"
++
++/* Enable debug option variables -- valid only session. */
++unsigned long term_debug_eigrp = 0;
++unsigned long term_debug_eigrp_nei = 0;
++unsigned long term_debug_eigrp_packet[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
++unsigned long term_debug_eigrp_zebra = 0;
++unsigned long term_debug_eigrp_transmit = 0;
++
++/* Configuration debug option variables. */
++unsigned long conf_debug_eigrp = 0;
++unsigned long conf_debug_eigrp_nei = 0;
++unsigned long conf_debug_eigrp_packet[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
++unsigned long conf_debug_eigrp_zebra = 0;
++unsigned long conf_debug_eigrp_transmit = 0;
++
++
++static int
++config_write_debug (struct vty *vty)
++{
++  int write = 0;
++  int i;
++
++  const char *type_str[] = {"update", "request", "query", "reply", "hello", "", "probe", "ack", "",
++  	  	  	  	  	  	  	"SIA query", "SIA reply", "stub", "all"};
++  const char *detail_str[] = {"", " send", " recv", "", " detail",
++							  " send detail", " recv detail", " detail"};
++
++
++  /* debug eigrp event. */
++//  if (IS_CONF_DEBUG_EIGRP (event, EVENT) == EIGRP_DEBUG_EVENT)
++//  {
++//      vty_out (vty, "debug eigrp event%s", VTY_NEWLINE);
++//      write = 1;
++//  }
++
++  /* debug eigrp packet all detail. */
++//  r = EIGRP_DEBUG_SEND_RECV|EIGRP_DEBUG_DETAIL;
++//  for (i = 0; i < 11; i++)
++//      r &= conf_debug_eigrp_packet[i] & (EIGRP_DEBUG_SEND_RECV|EIGRP_DEBUG_DETAIL);
++//  if (r == (EIGRP_DEBUG_SEND_RECV|EIGRP_DEBUG_DETAIL))
++//  {
++//      vty_out (vty, "debug eigrp packet all detail%s", VTY_NEWLINE);
++////      return 1;
++//  }
++//
++//  /* debug eigrp packet all. */
++//  r = EIGRP_DEBUG_SEND_RECV;
++//  for (i = 0; i < 11; i++)
++//      r &= conf_debug_eigrp_packet[i] & EIGRP_DEBUG_SEND_RECV;
++//  if (r == EIGRP_DEBUG_SEND_RECV)
++//  {
++//      vty_out (vty, "debug eigrp packet all%s", VTY_NEWLINE);
++//      for (i = 0; i < 11; i++)
++//    	  if (conf_debug_eigrp_packet[i] & EIGRP_DEBUG_DETAIL)
++//    	  vty_out (vty, "debug eigrp packet %s detail%s",
++//		  type_str[i],
++//		  VTY_NEWLINE);
++////      return 1;
++//  }
++
++  /* debug eigrp packet */
++  for (i = 0; i < 11; i++)
++  {
++      if (conf_debug_eigrp_packet[i] == 0 && term_debug_eigrp_packet[i] == 0 )
++    	  continue;
++
++      	  vty_out (vty, "debug eigrp packet %s%s%s",
++	      type_str[i], detail_str[conf_debug_eigrp_packet[i]],
++	      VTY_NEWLINE);
++      write = 1;
++  }
++
++	//  int write = 0;
++	//  int i, r;
++	//
++	//  const char *type_str[] = {"hello", "dd", "ls-request", "ls-update", "ls-ack"};
++	//  const char *detail_str[] = {"", " send", " recv", "", " detail",
++	//			" send detail", " recv detail", " detail"};
++	//
++	//  /* debug ospf ism (status|events|timers). */
++	//  if (IS_CONF_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM)
++	//    vty_out (vty, "debug ospf ism%s", VTY_NEWLINE);
++	//  else
++	//    {
++	//      if (IS_CONF_DEBUG_OSPF (ism, ISM_STATUS))
++	//	vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE);
++	//      if (IS_CONF_DEBUG_OSPF (ism, ISM_EVENTS))
++	//	vty_out (vty, "debug ospf ism event%s", VTY_NEWLINE);
++	//      if (IS_CONF_DEBUG_OSPF (ism, ISM_TIMERS))
++	//	vty_out (vty, "debug ospf ism timer%s", VTY_NEWLINE);
++	//    }
++	//
++	//  /* debug ospf nsm (status|events|timers). */
++	//  if (IS_CONF_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM)
++	//    vty_out (vty, "debug ospf nsm%s", VTY_NEWLINE);
++	//  else
++	//    {
++	//      if (IS_CONF_DEBUG_OSPF (nsm, NSM_STATUS))
++	//	vty_out (vty, "debug ospf nsm status%s", VTY_NEWLINE);
++	//      if (IS_CONF_DEBUG_OSPF (nsm, NSM_EVENTS))
++	//	vty_out (vty, "debug ospf nsm event%s", VTY_NEWLINE);
++	//      if (IS_CONF_DEBUG_OSPF (nsm, NSM_TIMERS))
++	//	vty_out (vty, "debug ospf nsm timer%s", VTY_NEWLINE);
++	//    }
++	//
++	//  /* debug ospf lsa (generate|flooding|install|refresh). */
++	//  if (IS_CONF_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA)
++	//    vty_out (vty, "debug ospf lsa%s", VTY_NEWLINE);
++	//  else
++	//    {
++	//      if (IS_CONF_DEBUG_OSPF (lsa, LSA_GENERATE))
++	//	vty_out (vty, "debug ospf lsa generate%s", VTY_NEWLINE);
++	//      if (IS_CONF_DEBUG_OSPF (lsa, LSA_FLOODING))
++	//	vty_out (vty, "debug ospf lsa flooding%s", VTY_NEWLINE);
++	//      if (IS_CONF_DEBUG_OSPF (lsa, LSA_INSTALL))
++	//	vty_out (vty, "debug ospf lsa install%s", VTY_NEWLINE);
++	//      if (IS_CONF_DEBUG_OSPF (lsa, LSA_REFRESH))
++	//	vty_out (vty, "debug ospf lsa refresh%s", VTY_NEWLINE);
++	//
++	//      write = 1;
++	//    }
++	//
++	//  /* debug ospf zebra (interface|redistribute). */
++	//  if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA)
++	//    vty_out (vty, "debug ospf zebra%s", VTY_NEWLINE);
++	//  else
++	//    {
++	//      if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
++	//	vty_out (vty, "debug ospf zebra interface%s", VTY_NEWLINE);
++	//      if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
++	//	vty_out (vty, "debug ospf zebra redistribute%s", VTY_NEWLINE);
++	//
++	//      write = 1;
++	//    }
++	//
++	//  /* debug ospf event. */
++	//  if (IS_CONF_DEBUG_OSPF (event, EVENT) == OSPF_DEBUG_EVENT)
++	//    {
++	//      vty_out (vty, "debug ospf event%s", VTY_NEWLINE);
++	//      write = 1;
++	//    }
++	//
++	//  /* debug ospf nssa. */
++	//  if (IS_CONF_DEBUG_OSPF (nssa, NSSA) == OSPF_DEBUG_NSSA)
++	//    {
++	//      vty_out (vty, "debug ospf nssa%s", VTY_NEWLINE);
++	//      write = 1;
++	//    }
++	//
++	//  /* debug ospf packet all detail. */
++	//  r = OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL;
++	//  for (i = 0; i < 5; i++)
++	//    r &= conf_debug_ospf_packet[i] & (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL);
++	//  if (r == (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL))
++	//    {
++	//      vty_out (vty, "debug ospf packet all detail%s", VTY_NEWLINE);
++	//      return 1;
++	//    }
++	//
++	//  /* debug ospf packet all. */
++	//  r = OSPF_DEBUG_SEND_RECV;
++	//  for (i = 0; i < 5; i++)
++	//    r &= conf_debug_ospf_packet[i] & OSPF_DEBUG_SEND_RECV;
++	//  if (r == OSPF_DEBUG_SEND_RECV)
++	//    {
++	//      vty_out (vty, "debug ospf packet all%s", VTY_NEWLINE);
++	//      for (i = 0; i < 5; i++)
++	//	if (conf_debug_ospf_packet[i] & OSPF_DEBUG_DETAIL)
++	//	  vty_out (vty, "debug ospf packet %s detail%s",
++	//		   type_str[i],
++	//		   VTY_NEWLINE);
++	//      return 1;
++	//    }
++	//
++	//  /* debug ospf packet (hello|dd|ls-request|ls-update|ls-ack)
++	//     (send|recv) (detail). */
++	//  for (i = 0; i < 5; i++)
++	//    {
++	//      if (conf_debug_ospf_packet[i] == 0)
++	//	continue;
++	//
++	//      vty_out (vty, "debug ospf packet %s%s%s",
++	//	       type_str[i], detail_str[conf_debug_ospf_packet[i]],
++	//	       VTY_NEWLINE);
++	//      write = 1;
++	//    }
++
++  return write;
++}
++
++
++static int
++eigrp_neighbor_packet_queue_sum (struct eigrp_interface *ei)
++{
++  struct eigrp_neighbor *nbr;
++  struct listnode *node, *nnode;
++  int sum;
++  sum = 0;
++
++  for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
++    {
++      sum += nbr->retrans_queue->count;
++    }
++
++  return sum;
++}
++
++/*
++ * Expects header to be in host order
++ */
++void
++eigrp_ip_header_dump (struct ip *iph)
++{
++  /* IP Header dump. */
++  zlog_debug ("ip_v %u", iph->ip_v);
++  zlog_debug ("ip_hl %u", iph->ip_hl);
++  zlog_debug ("ip_tos %u", iph->ip_tos);
++  zlog_debug ("ip_len %u", iph->ip_len);
++  zlog_debug ("ip_id %u", (u_int32_t) iph->ip_id);
++  zlog_debug ("ip_off %u", (u_int32_t) iph->ip_off);
++  zlog_debug ("ip_ttl %u", iph->ip_ttl);
++  zlog_debug ("ip_p %u", iph->ip_p);
++  zlog_debug ("ip_sum 0x%x", (u_int32_t) iph->ip_sum);
++  zlog_debug ("ip_src %s",  inet_ntoa (iph->ip_src));
++  zlog_debug ("ip_dst %s", inet_ntoa (iph->ip_dst));
++}
++
++/*
++ * Expects header to be in host order
++ */
++void
++eigrp_header_dump (struct eigrp_header *eigrph)
++{
++  /* EIGRP Header dump. */
++  zlog_debug ("eigrp_version %u",	eigrph->version);
++  zlog_debug ("eigrp_opcode %u",	eigrph->opcode);
++  zlog_debug ("eigrp_checksum 0x%x",	ntohs(eigrph->checksum));
++  zlog_debug ("eigrp_flags 0x%x",	ntohl(eigrph->flags));
++  zlog_debug ("eigrp_sequence %u",	ntohl(eigrph->sequence));
++  zlog_debug ("eigrp_ack %u",		ntohl(eigrph->ack));
++  zlog_debug ("eigrp_vrid %u"	,	ntohs(eigrph->vrid));
++  zlog_debug ("eigrp_AS %u",		ntohs(eigrph->ASNumber));
++}
++
++const char *
++eigrp_if_name_string (struct eigrp_interface *ei)
++{
++  static char buf[EIGRP_IF_STRING_MAXLEN] = "";
++
++  if (!ei)
++    return "inactive";
++
++  snprintf (buf, EIGRP_IF_STRING_MAXLEN,
++            "%s", ei->ifp->name);
++  return buf;
++}
++
++const char *
++eigrp_topology_ip_string (struct eigrp_prefix_entry *tn)
++{
++  static char buf[EIGRP_IF_STRING_MAXLEN] = "";
++  u_int32_t ifaddr;
++
++  ifaddr = ntohl (tn->destination_ipv4->prefix.s_addr);
++  snprintf (buf, EIGRP_IF_STRING_MAXLEN,
++            "%u.%u.%u.%u",
++            (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff,
++            (ifaddr >> 8) & 0xff, ifaddr & 0xff);
++  return buf;
++}
++
++
++const char *
++eigrp_if_ip_string (struct eigrp_interface *ei)
++{
++  static char buf[EIGRP_IF_STRING_MAXLEN] = "";
++  u_int32_t ifaddr;
++
++  if (!ei)
++    return "inactive";
++
++  ifaddr = ntohl (ei->address->u.prefix4.s_addr);
++  snprintf (buf, EIGRP_IF_STRING_MAXLEN,
++            "%u.%u.%u.%u",
++            (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff,
++            (ifaddr >> 8) & 0xff, ifaddr & 0xff);
++
++  return buf;
++}
++
++const char *
++eigrp_neigh_ip_string (struct eigrp_neighbor *nbr)
++{
++  static char buf[EIGRP_IF_STRING_MAXLEN] = "";
++  u_int32_t ifaddr;
++
++  ifaddr = ntohl (nbr->src.s_addr);
++  snprintf (buf, EIGRP_IF_STRING_MAXLEN,
++            "%u.%u.%u.%u",
++            (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff,
++            (ifaddr >> 8) & 0xff, ifaddr & 0xff);
++
++  return buf;
++}
++
++void
++show_ip_eigrp_interface_header (struct vty *vty, struct eigrp *eigrp)
++{
++
++  vty_out (vty, "%s%s%d%s%s%s %-10s %-10s %-10s %-6s %-12s %-7s %-14s %-12s %-8s %-8s %-8s%s %-39s %-12s %-7s %-14s %-12s %-8s%s",
++           VTY_NEWLINE,
++           "EIGRP interfaces for AS(",eigrp->AS,")",VTY_NEWLINE,VTY_NEWLINE,
++           "Interface", "Bandwidth", "Delay", "Peers", "Xmit Queue", "Mean",
++           "Pacing Time", "Multicast", "Pending", "Hello", "Holdtime",
++           VTY_NEWLINE,"","Un/Reliable","SRTT","Un/Reliable","Flow Timer","Routes",
++           VTY_NEWLINE);
++}
++
++void
++show_ip_eigrp_interface_sub (struct vty *vty, struct eigrp *eigrp,
++			     struct eigrp_interface *ei)
++{
++  vty_out (vty, "%-11s ", eigrp_if_name_string (ei));
++  vty_out (vty, "%-11u",IF_DEF_PARAMS (ei->ifp)->bandwidth);
++  vty_out (vty, "%-11u",IF_DEF_PARAMS (ei->ifp)->delay);
++  vty_out (vty, "%-7u", ei->nbrs->count);
++  vty_out (vty, "%u %c %-10u",0,'/',eigrp_neighbor_packet_queue_sum (ei));
++  vty_out (vty, "%-7u %-14u %-12u %-8u",0,0,0,0);
++  vty_out (vty, "%-8u %-8u %s",IF_DEF_PARAMS (ei->ifp)->v_hello,IF_DEF_PARAMS (ei->ifp)->v_wait,VTY_NEWLINE);
++}
++
++void
++show_ip_eigrp_interface_detail (struct vty *vty, struct eigrp *eigrp,
++				struct eigrp_interface *ei)
++{
++  vty_out (vty, "%-2s %s %d %-3s %s","","Hello interval is ",0," sec",VTY_NEWLINE);
++  vty_out (vty, "%-2s %s %s %s","","Next xmit serial","<none>",VTY_NEWLINE);
++  vty_out (vty, "%-2s %s %d %s %d %s %d %s %d %s","","Un/reliable mcasts: ",0,"/",0,"Un/reliable ucasts: ",0,"/",0,VTY_NEWLINE);
++  vty_out (vty, "%-2s %s %d %s %d %s %d %s","","Mcast exceptions: ",0,"  CR packets: ",0,"  ACKs supressed: ",0,VTY_NEWLINE);
++  vty_out (vty, "%-2s %s %d %s %d %s","","Retransmissions sent: ",0,"Out-of-sequence rcvd: ",0,VTY_NEWLINE);
++  vty_out (vty, "%-2s %s %s %s %s","","Authentication mode is ","not","set",VTY_NEWLINE);
++  vty_out (vty, "%-2s %s %s","","Use multicast",VTY_NEWLINE);
++}
++
++void
++show_ip_eigrp_neighbor_header (struct vty *vty, struct eigrp *eigrp)
++{
++  vty_out (vty, "%s%s%d%s%s%s%-3s %-17s %-20s %-6s %-8s %-6s %-5s %-5s %-5s%s %-41s %-6s %-8s %-6s %-4s %-6s %-5s %s",
++           VTY_NEWLINE,
++           "EIGRP neighbors for AS(",eigrp->AS,")",VTY_NEWLINE,VTY_NEWLINE,
++           "H", "Address", "Interface", "Hold", "Uptime",
++           "SRTT", "RTO", "Q", "Seq", VTY_NEWLINE
++           ,"","(sec)","","(ms)","","Cnt","Num", VTY_NEWLINE);
++}
++
++void
++show_ip_eigrp_neighbor_sub (struct vty *vty, struct eigrp_neighbor *nbr,
++			    int detail)
++{
++
++  vty_out (vty, "%-3u %-17s %-21s",0,eigrp_neigh_ip_string (nbr),eigrp_if_name_string (nbr->ei));
++  vty_out (vty,"%-7lu",thread_timer_remain_second (nbr->t_holddown));
++  vty_out (vty,"%-8u %-6u %-5u",0,0,EIGRP_PACKET_RETRANS_TIME);
++  vty_out (vty,"%-7lu",nbr->retrans_queue->count);
++  vty_out (vty,"%u%s",nbr->recv_sequence_number,VTY_NEWLINE);
++
++
++  if (detail)
++    {
++      vty_out(vty,"    Version %u.%u/%u.%u",
++	      nbr->os_rel_major, nbr->os_rel_minor,
++	      nbr->tlv_rel_major, nbr->tlv_rel_minor);
++      vty_out(vty,", Retrans: %lu, Retries: %lu",
++	      nbr->retrans_queue->count, 0UL);
++      vty_out(vty,", %s%s", eigrp_nbr_state_str(nbr), VTY_NEWLINE);
++    }
++}
++
++/*
++ * Print standard header for show EIGRP topology output
++ */
++void
++show_ip_eigrp_topology_header (struct vty *vty, struct eigrp *eigrp)
++{
++  struct in_addr router_id;
++  router_id.s_addr = htonl(eigrp->router_id);
++
++  vty_out (vty, "%s%s%d%s%s%s%s%s%s%s%s%s%s%s",
++	     VTY_NEWLINE,
++	     "EIGRP Topology Table for AS(", eigrp->AS, ")/ID(", inet_ntoa(router_id), ")", VTY_NEWLINE,VTY_NEWLINE,
++	     "Codes: P - Passive, A - Active, U - Update, Q - Query, "
++	     "R - Reply", VTY_NEWLINE ,"       ","r - reply Status, s - sia Status",VTY_NEWLINE,VTY_NEWLINE);
++}
++
++void
++show_ip_eigrp_prefix_entry (struct vty *vty, struct eigrp_prefix_entry *tn)
++{
++  vty_out (vty, "%-3c",(tn->state > 0) ? 'A' : 'P');
++  vty_out (vty, "%s/%u, ",inet_ntoa (tn->destination_ipv4->prefix),tn->destination_ipv4->prefixlen);
++  vty_out (vty, "%u successors, ",eigrp_topology_get_successor(tn)->count);
++  vty_out (vty, "FD is %u, serno: %lu %s",tn->fdistance, tn->serno, VTY_NEWLINE);
++
++}
++
++void
++show_ip_eigrp_neighbor_entry (struct vty *vty, struct eigrp *eigrp, struct eigrp_neighbor_entry *te)
++{
++  if (te->adv_router == eigrp->neighbor_self)
++    vty_out (vty, "%-7s%s, %s%s"," ","via Connected",eigrp_if_name_string (te->ei), VTY_NEWLINE);
++  else
++    {
++      vty_out (vty, "%-7s%s%s (%u/%u), %s%s"," ","via ",inet_ntoa (te->adv_router->src),te->distance, te->reported_distance, eigrp_if_name_string (te->ei), VTY_NEWLINE);
++    }
++}
++
++
++DEFUN (show_debugging_eigrp,
++       show_debugging_eigrp_cmd,
++       "show debugging eigrp",
++       SHOW_STR
++       DEBUG_STR
++       EIGRP_STR)
++{
++  int i;
++
++  vty_out (vty, "EIGRP debugging status:%s", VTY_NEWLINE);
++
++  /* Show debug status for events. */
++  if (IS_DEBUG_EIGRP(event,EVENT))
++    vty_out (vty, "  EIGRP event debugging is on%s", VTY_NEWLINE);
++
++  /* Show debug status for EIGRP Packets. */
++  for (i = 0; i < 11 ; i++)
++  {
++      if (i == 8)
++        continue;
++
++	if (IS_DEBUG_EIGRP_PACKET (i, SEND) && IS_DEBUG_EIGRP_PACKET (i, RECV))
++	{
++		vty_out (vty, "  EIGRP packet %s%s debugging is on%s",
++		LOOKUP (eigrp_packet_type_str, i + 1),
++		IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "",
++		VTY_NEWLINE);
++	}
++	else
++	{
++		if (IS_DEBUG_EIGRP_PACKET (i, SEND))
++			vty_out (vty, "  EIGRP packet %s send%s debugging is on%s",
++			LOOKUP (eigrp_packet_type_str, i + 1),
++			IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "",
++			VTY_NEWLINE);
++		if (IS_DEBUG_EIGRP_PACKET (i, RECV))
++			vty_out (vty, "  EIGRP packet %s receive%s debugging is on%s",
++			LOOKUP (eigrp_packet_type_str, i + 1),
++			IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "",
++			VTY_NEWLINE);
++	}
++  }
++
++  return CMD_SUCCESS;
++}
++
++
++/*
++   [no] debug eigrp packet (hello|dd|ls-request|ls-update|ls-ack|all)
++                          [send|recv [detail]]
++*/
++
++DEFUN (debug_eigrp_transmit,
++       debug_eigrp_transmit_cmd,
++       "debug eigrp transmit (send|recv|all)",
++       DEBUG_STR
++       EIGRP_STR
++       "EIGRP transmission events\n"
++       "packet sent\n"
++       "packet received\n"
++       "all packets\n")
++{
++  int type = 0;
++  int flag = 0;
++  int i;
++
++  /* send or recv. */
++  if (strncmp (argv[0], "s", 1) == 0)
++	flag = EIGRP_DEBUG_SEND;
++  if (strncmp (argv[0], "r", 1) == 0)
++  	flag = EIGRP_DEBUG_RECV;
++  if (strncmp (argv[0], "a", 1) == 0)
++  	flag = EIGRP_DEBUG_SEND_RECV;
++
++  /* detail option */
++  if (argc > 1)
++  {
++	if (strncmp (argv[1], "d", 1) == 0)
++	  flag = EIGRP_DEBUG_PACKET_DETAIL;
++	if (strncmp (argv[1], "s", 1) == 0)
++	  flag = 0;
++
++  }
++
++  if (vty->node == CONFIG_NODE)
++	DEBUG_TRANSMIT_ON (0, flag);
++  else
++	TERM_DEBUG_TRANSMIT_ON (0, flag);
++
++  return CMD_SUCCESS;
++}
++
++ALIAS (debug_eigrp_transmit,
++       debug_eigrp_transmit_detail_cmd,
++       "debug eigrp transmit (send|recv|all) (detail|strange)",
++       DEBUG_STR
++       EIGRP_STR
++       "EIGRP transmission events\n"
++       "packet sent\n"
++       "packet received\n"
++       "all packets\n"
++       "more detail\n"
++       "this is really strange\n")
++
++DEFUN (no_debug_eigrp_transmit,
++       no_debug_eigrp_transmit_cmd,
++       "no debug eigrp transmit (send|recv|all)",
++       NO_STR
++       UNDEBUG_STR
++       EIGRP_STR
++       "EIGRP transmission events\n"
++       "packet sent\n"
++       "packet received\n"
++       "all packets\n")
++{
++  int type = 0;
++  int flag = 0;
++  int i;
++
++  /* send or recv. */
++  if (strncmp (argv[0], "s", 1) == 0)
++	flag = EIGRP_DEBUG_SEND;
++  if (strncmp (argv[0], "r", 1) == 0)
++  	flag = EIGRP_DEBUG_RECV;
++  if (strncmp (argv[0], "a", 1) == 0)
++  	flag = EIGRP_DEBUG_SEND_RECV;
++
++  /* detail option */
++  if (argc > 1)
++  {
++	if (strncmp (argv[1], "d", 1) == 0)
++	  flag = EIGRP_DEBUG_PACKET_DETAIL;
++	if (strncmp (argv[1], "s", 1) == 0)
++	  zlog_debug("this is not so strange anymore .... ");
++	  flag = 0;
++  }
++
++  if (vty->node == CONFIG_NODE)
++	DEBUG_TRANSMIT_OFF (0, flag);
++  else
++	TERM_DEBUG_TRANSMIT_OFF (0, flag);
++
++  return CMD_SUCCESS;
++}
++
++ALIAS (no_debug_eigrp_transmit,
++       no_debug_eigrp_transmit_detail_cmd,
++       "no debug eigrp transmit (send|recv|all) (detail|strange)",
++       NO_STR
++       DEBUG_STR
++       EIGRP_STR
++       "EIGRP transmission events\n"
++       "packet sent\n"
++       "packet received\n"
++       "all packets\n"
++       "more detail\n"
++       "this is really strange\n")
++
++DEFUN (debug_eigrp_packets,
++       debug_eigrp_packets_all_cmd,
++       "debug eigrp packets (siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all)",
++       DEBUG_STR
++       EIGRP_STR
++       "EIGRP packets\n"
++       "EIGRP SIA-Query packets\n"
++       "EIGRP SIA-Reply packets\n"
++       "EIGRP ack packets\n"
++       "EIGRP hello packets\n"
++       "EIGRP probe packets\n"
++       "EIGRP query packets\n"
++       "EIGRP reply packets\n"
++       "EIGRP request packets\n"
++       "EIGRP retransmissions\n"
++       "EIGRP stub packets\n"
++       "Display all EIGRP packets except Hellos\n"
++       "EIGRP update packets\n"
++       "Display all EIGRP packets\n")
++{
++  int type = 0;
++  int flag = 0;
++  int i;
++  assert (argc > 0);
++
++  /* Check packet type. */
++  if (strncmp (argv[0], "h", 1) == 0)
++    type = EIGRP_DEBUG_HELLO;
++  if (strncmp (argv[0], "u", 1) == 0)
++    type = EIGRP_DEBUG_UPDATE;
++  if (strncmp (argv[0], "q", 1) == 0)
++    type = EIGRP_DEBUG_QUERY;
++  if (strncmp (argv[0], "a", 1) == 0)
++    type = EIGRP_DEBUG_ACK;
++  if (strncmp (argv[0], "p", 1) == 0)
++    type = EIGRP_DEBUG_PROBE;
++  if (strncmp (argv[0], "st", 2) == 0)
++    type = EIGRP_DEBUG_STUB;
++  if (strncmp (argv[0], "rep", 3) == 0)
++    type = EIGRP_DEBUG_REPLY;
++  if (strncmp (argv[0], "req", 3) == 0)
++    type = EIGRP_DEBUG_REQUEST;
++  if (strncmp (argv[0], "siaq", 4) == 0)
++    type = EIGRP_DEBUG_SIAQUERY;
++  if (strncmp (argv[0], "siar", 4) == 0)
++    type = EIGRP_DEBUG_SIAREPLY;
++  if (strncmp (argv[0], "al", 2) == 0)
++     type = EIGRP_DEBUG_PACKETS_ALL;
++
++
++  /* All packet types, both send and recv. */
++  if (argc == 1)
++    flag = EIGRP_DEBUG_SEND_RECV;
++
++  /* send or recv. */
++  if (argc >= 2)
++  {
++    if (strncmp (argv[1], "s", 1) == 0)
++	  flag = EIGRP_DEBUG_SEND;
++    else if (strncmp (argv[1], "r", 1) == 0)
++	  flag = EIGRP_DEBUG_RECV;
++    else if (strncmp (argv[1], "d", 1) == 0)
++	  flag = EIGRP_DEBUG_SEND_RECV | EIGRP_DEBUG_PACKET_DETAIL;
++  }
++
++  /* detail. */
++  if (argc == 3)
++    if (strncmp (argv[2], "d", 1) == 0)
++      flag |= EIGRP_DEBUG_PACKET_DETAIL;
++
++  for (i = 0; i < 11; i++)
++    if (type & (0x01 << i))
++    {
++    	if (vty->node == CONFIG_NODE)
++		  DEBUG_PACKET_ON (i, flag);
++		else
++		  TERM_DEBUG_PACKET_ON (i, flag);
++    }
++
++  return CMD_SUCCESS;
++}
++
++ALIAS (debug_eigrp_packets,
++       debug_eigrp_packets_send_recv_cmd,
++       "debug eigrp packets (siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all) (send|recv|detail)",
++       DEBUG_STR
++       EIGRP_STR
++       "EIGRP packets\n"
++       "EIGRP SIA-Query packets\n"
++       "EIGRP SIA-Reply packets\n"
++       "EIGRP ack packets\n"
++       "EIGRP hello packets\n"
++       "EIGRP probe packets\n"
++       "EIGRP query packets\n"
++       "EIGRP reply packets\n"
++       "EIGRP request packets\n"
++       "EIGRP retransmissions\n"
++       "EIGRP stub packets\n"
++       "Display all EIGRP packets except Hellos\n"
++       "EIGRP update packets\n"
++       "Display all EIGRP packets\n"
++       "Packet sent\n"
++       "Packet received\n"
++       "Detail information\n")
++
++ALIAS (debug_eigrp_packets,
++       debug_eigrp_packets_send_recv_detail_cmd,
++       "debug eigrp packets (siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all) (send|recv) (detail|)",
++       DEBUG_STR
++       EIGRP_STR
++       "EIGRP packets\n"
++       "EIGRP SIA-Query packets\n"
++       "EIGRP SIA-Reply packets\n"
++       "EIGRP ack packets\n"
++       "EIGRP hello packets\n"
++       "EIGRP probe packets\n"
++       "EIGRP query packets\n"
++       "EIGRP reply packets\n"
++       "EIGRP request packets\n"
++       "EIGRP retransmissions\n"
++       "EIGRP stub packets\n"
++       "Display all EIGRP packets except Hellos\n"
++       "EIGRP update packets\n"
++       "Display all EIGRP packets\n"
++       "Packet sent\n"
++       "Packet received\n"
++       "Detail Information\n")
++
++
++DEFUN (no_debug_eigrp_packets,
++	  no_debug_eigrp_packets_all_cmd,
++	  "no debug eigrp packets (siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all)",
++	  NO_STR
++	  UNDEBUG_STR
++	  EIGRP_STR
++	  "EIGRP packets\n"
++	  "EIGRP SIA-Query packets\n"
++	  "EIGRP SIA-Reply packets\n"
++	  "EIGRP ack packets\n"
++	  "EIGRP hello packets\n"
++	  "EIGRP probe packets\n"
++	  "EIGRP query packets\n"
++	  "EIGRP reply packets\n"
++	  "EIGRP request packets\n"
++	  "EIGRP retransmissions\n"
++	  "EIGRP stub packets\n"
++	  "Display all EIGRP packets except Hellos\n"
++	  "EIGRP update packets\n"
++	  "Display all EIGRP packets\n")
++{
++ int type = 0;
++ int flag = 0;
++ int i;
++
++ assert (argc > 0);
++
++ /* Check packet type. */
++ if (strncmp (argv[0], "h", 1) == 0)
++   type = EIGRP_DEBUG_HELLO;
++ if (strncmp (argv[0], "u", 1) == 0)
++   type = EIGRP_DEBUG_UPDATE;
++ if (strncmp (argv[0], "q", 1) == 0)
++   type = EIGRP_DEBUG_QUERY;
++ if (strncmp (argv[0], "a", 1) == 0)
++   type = EIGRP_DEBUG_ACK;
++ if (strncmp (argv[0], "p", 1) == 0)
++   type = EIGRP_DEBUG_PROBE;
++ if (strncmp (argv[0], "st", 2) == 0)
++   type = EIGRP_DEBUG_STUB;
++ if (strncmp (argv[0], "rep", 3) == 0)
++   type = EIGRP_DEBUG_REPLY;
++ if (strncmp (argv[0], "req", 3) == 0)
++   type = EIGRP_DEBUG_REQUEST;
++ if (strncmp (argv[0], "siaq", 4) == 0)
++   type = EIGRP_DEBUG_SIAQUERY;
++ if (strncmp (argv[0], "siar", 4) == 0)
++   type = EIGRP_DEBUG_SIAREPLY;
++
++
++ /* Default, both send and recv. */
++ if (argc == 1)
++   flag = EIGRP_DEBUG_SEND_RECV;
++
++ /* send or recv. */
++ if (argc >= 2)
++ {
++   if (strncmp (argv[1], "s", 1) == 0)
++  flag = EIGRP_DEBUG_SEND;
++   else if (strncmp (argv[1], "r", 1) == 0)
++  flag = EIGRP_DEBUG_RECV;
++   else if (strncmp (argv[1], "d", 1) == 0)
++  flag = EIGRP_DEBUG_SEND_RECV | EIGRP_DEBUG_PACKET_DETAIL;
++ }
++
++ /* detail. */
++ if (argc == 3)
++   if (strncmp (argv[2], "d", 1) == 0)
++	 flag |= EIGRP_DEBUG_PACKET_DETAIL;
++
++ for (i = 0; i < 11; i++)
++   if (type & (0x01 << i))
++   {
++	if (vty->node == CONFIG_NODE)
++	  DEBUG_PACKET_OFF (i, flag);
++	else
++	  TERM_DEBUG_PACKET_OFF (i, flag);
++   }
++
++ return CMD_SUCCESS;
++}
++
++ALIAS (no_debug_eigrp_packets,
++	  no_debug_eigrp_packets_send_recv_cmd,
++	  "no debug eigrp packets (siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all) (send|recv|detail)",
++	  NO_STR
++	  UNDEBUG_STR
++	  EIGRP_STR
++	  "EIGRP packets\n"
++	  "EIGRP SIA-Query packets\n"
++	  "EIGRP SIA-Reply packets\n"
++	  "EIGRP ack packets\n"
++	  "EIGRP hello packets\n"
++	  "EIGRP probe packets\n"
++	  "EIGRP query packets\n"
++	  "EIGRP reply packets\n"
++	  "EIGRP request packets\n"
++	  "EIGRP retransmissions\n"
++	  "EIGRP stub packets\n"
++	  "Display all EIGRP packets except Hellos\n"
++	  "EIGRP update packets\n"
++	  "Display all EIGRP packets\n"
++	  "Packet sent\n"
++	  "Packet received\n"
++	  "Detail information\n")
++
++ALIAS (no_debug_eigrp_packets,
++	  no_debug_eigrp_packets_send_recv_detail_cmd,
++	  "no debug eigrp packets (siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all) (send|recv) (detail|)",
++	  NO_STR
++	  UNDEBUG_STR
++	  EIGRP_STR
++	  "EIGRP packets\n"
++	  "EIGRP SIA-Query packets\n"
++	  "EIGRP SIA-Reply packets\n"
++	  "EIGRP ack packets\n"
++	  "EIGRP hello packets\n"
++	  "EIGRP probe packets\n"
++	  "EIGRP query packets\n"
++	  "EIGRP reply packets\n"
++	  "EIGRP request packets\n"
++	  "EIGRP retransmissions\n"
++	  "EIGRP stub packets\n"
++	  "Display all EIGRP packets except Hellos\n"
++	  "EIGRP update packets\n"
++	  "Display all EIGRP packets\n"
++	  "Packet sent\n"
++	  "Packet received\n"
++	  "Detail Information\n")
++
++
++/* Debug node. */
++static struct cmd_node eigrp_debug_node =
++{
++  DEBUG_NODE,
++  "",
++  1 /* VTYSH */
++};
++
++/* Initialize debug commands. */
++void
++eigrp_debug_init ()
++{
++  install_node (&eigrp_debug_node, config_write_debug);
++
++  install_element (ENABLE_NODE, &show_debugging_eigrp_cmd);
++  install_element (ENABLE_NODE, &debug_eigrp_packets_all_cmd);
++  install_element (ENABLE_NODE, &no_debug_eigrp_packets_all_cmd);
++  install_element (ENABLE_NODE, &debug_eigrp_packets_send_recv_cmd);
++  install_element (ENABLE_NODE, &no_debug_eigrp_packets_send_recv_cmd);
++  install_element (ENABLE_NODE, &debug_eigrp_packets_send_recv_detail_cmd);
++  install_element (ENABLE_NODE, &no_debug_eigrp_packets_send_recv_detail_cmd);
++  install_element (ENABLE_NODE, &debug_eigrp_transmit_cmd);
++  install_element (ENABLE_NODE, &debug_eigrp_transmit_detail_cmd);
++  install_element (ENABLE_NODE, &no_debug_eigrp_transmit_cmd);
++  install_element (ENABLE_NODE, &no_debug_eigrp_transmit_detail_cmd);
++
++  install_element (CONFIG_NODE, &show_debugging_eigrp_cmd);
++  install_element (CONFIG_NODE, &debug_eigrp_packets_all_cmd);
++  install_element (CONFIG_NODE, &no_debug_eigrp_packets_all_cmd);
++  install_element (CONFIG_NODE, &debug_eigrp_packets_send_recv_cmd);
++  install_element (CONFIG_NODE, &no_debug_eigrp_packets_send_recv_cmd);
++  install_element (CONFIG_NODE, &debug_eigrp_packets_send_recv_detail_cmd);
++  install_element (CONFIG_NODE, &no_debug_eigrp_packets_send_recv_detail_cmd);
++  install_element (CONFIG_NODE, &debug_eigrp_transmit_cmd);
++  install_element (CONFIG_NODE, &debug_eigrp_transmit_detail_cmd);
++  install_element (CONFIG_NODE, &no_debug_eigrp_transmit_cmd);
++  install_element (CONFIG_NODE, &no_debug_eigrp_transmit_detail_cmd);
++}
++
++
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_dump.h eigrp/eigrpd/eigrp_dump.h
+--- a/eigrpd/eigrp_dump.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_dump.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,165 @@
++/*
++ * EIGRP Dump Functions and Debbuging.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRPD_DUMP_H_
++#define _ZEBRA_EIGRPD_DUMP_H_
++
++#define EIGRP_TIME_DUMP_SIZE		16
++
++/* general debug flags */
++extern unsigned long term_debug_eigrp;
++#define EIGRP_DEBUG_EVENT		0x01
++#define EIGRP_DEBUG_DETAIL		0x02
++#define EIGRP_DEBUG_TIMERS		0x04
++
++/* neighbor debug flags */
++extern unsigned long term_debug_eigrp_nei;
++#define EIGRP_DEBUG_NEI				0x01
++
++/* packet debug flags */
++extern unsigned long term_debug_eigrp_packet[];
++#define EIGRP_DEBUG_UPDATE			0x01
++#define EIGRP_DEBUG_REQUEST			0x02
++#define EIGRP_DEBUG_QUERY			0x04
++#define EIGRP_DEBUG_REPLY			0x08
++#define EIGRP_DEBUG_HELLO			0x10
++#define EIGRP_DEBUG_PROBE			0x40
++#define EIGRP_DEBUG_ACK 			0x80
++#define EIGRP_DEBUG_SIAQUERY	    0x200
++#define EIGRP_DEBUG_SIAREPLY	    0x400
++#define EIGRP_DEBUG_STUB 			0x800
++#define EIGRP_DEBUG_PACKETS_ALL     0xfff
++
++extern unsigned long term_debug_eigrp_transmit;
++#define EIGRP_DEBUG_SEND			0x01
++#define EIGRP_DEBUG_RECV			0x02
++#define EIGRP_DEBUG_SEND_RECV		0x03
++#define EIGRP_DEBUG_PACKET_DETAIL	0x04
++
++/* zebra debug flags */
++extern unsigned long term_debug_eigrp_zebra;
++#define EIGRP_DEBUG_ZEBRA_INTERFACE	0x01
++#define EIGRP_DEBUG_ZEBRA_REDISTRIBUTE	0x02
++#define EIGRP_DEBUG_ZEBRA		0x03
++
++/* Macro for setting debug option. */
++#define CONF_DEBUG_NEI_ON(a, b)		conf_debug_eigrp_nei[a] |= (b)
++#define CONF_DEBUG_NEI_OFF(a, b)	conf_debug_eigrp_nei[a] &= ~(b)
++#define TERM_DEBUG_NEI_ON(a, b)		term_debug_eigrp_nei[a] |= (b)
++#define TERM_DEBUG_NEI_OFF(a, b)	term_debug_eigrp_nei[a] &= ~(b)
++#define DEBUG_NEI_ON(a, b) \
++    do { \
++      CONF_DEBUG_NEI_ON(a, b); \
++      TERM_DEBUG_NEI_ON(a, b); \
++    } while (0)
++#define DEBUG_NEI_OFF(a, b) \
++    do { \
++      CONF_DEBUG_NEI_OFF(a, b); \
++      TERM_DEBUG_NEI_OFF(a, b); \
++    } while (0)
++
++#define CONF_DEBUG_PACKET_ON(a, b)	conf_debug_eigrp_packet[a] |= (b)
++#define CONF_DEBUG_PACKET_OFF(a, b)	conf_debug_eigrp_packet[a] &= ~(b)
++#define TERM_DEBUG_PACKET_ON(a, b)	term_debug_eigrp_packet[a] |= (b)
++#define TERM_DEBUG_PACKET_OFF(a, b)	term_debug_eigrp_packet[a] &= ~(b)
++#define DEBUG_PACKET_ON(a, b) \
++    do { \
++      CONF_DEBUG_PACKET_ON(a, b); \
++      TERM_DEBUG_PACKET_ON(a, b); \
++    } while (0)
++#define DEBUG_PACKET_OFF(a, b) \
++    do { \
++      CONF_DEBUG_PACKET_OFF(a, b); \
++      TERM_DEBUG_PACKET_OFF(a, b); \
++    } while (0)
++
++#define CONF_DEBUG_TRANSMIT_ON(a, b)	conf_debug_eigrp_transmit |= (b)
++#define CONF_DEBUG_TRANSMIT_OFF(a, b)	conf_debug_eigrp_transmit &= ~(b)
++#define TERM_DEBUG_TRANSMIT_ON(a, b)	term_debug_eigrp_transmit |= (b)
++#define TERM_DEBUG_TRANSMIT_OFF(a, b)	term_debug_eigrp_transmit &= ~(b)
++#define DEBUG_TRANSMIT_ON(a, b) \
++    do { \
++      CONF_DEBUG_TRANSMIT_ON(a, b); \
++      TERM_DEBUG_TRANSMIT_ON(a, b); \
++    } while (0)
++#define DEBUG_TRANSMIT_OFF(a, b) \
++    do { \
++      CONF_DEBUG_TRANSMIT_OFF(a, b); \
++      TERM_DEBUG_TRANSMIT_OFF(a, b); \
++    } while (0)
++
++#define CONF_DEBUG_ON(a, b)		conf_debug_eigrp_ ## a |= (EIGRP_DEBUG_ ## b)
++#define CONF_DEBUG_OFF(a, b)		conf_debug_eigrp_ ## a &= ~(EIGRP_DEBUG_ ## b)
++#define TERM_DEBUG_ON(a, b)		term_debug_eigrp_ ## a |= (EIGRP_DEBUG_ ## b)
++#define TERM_DEBUG_OFF(a, b)		term_debug_eigrp_ ## a &= ~(EIGRP_DEBUG_ ## b)
++#define DEBUG_ON(a, b) \
++     do { \
++       CONF_DEBUG_ON(a, b); \
++       TERM_DEBUG_ON(a, b); \
++     } while (0)
++#define DEBUG_OFF(a, b) \
++     do { \
++       CONF_DEBUG_OFF(a, b); \
++       TERM_DEBUG_OFF(a, b); \
++     } while (0)
++
++/* Macro for checking debug option. */
++#define IS_DEBUG_EIGRP_PACKET(a, b) \
++	(term_debug_eigrp_packet[a] & EIGRP_DEBUG_ ## b)
++#define IS_DEBUG_EIGRP_TRANSMIT(a, b) \
++        (term_debug_eigrp_transmit & EIGRP_DEBUG_ ## b)
++#define IS_DEBUG_EIGRP_NEI(a, b) \
++	(term_debug_eigrp_nei & EIGRP_DEBUG_ ## b)
++#define IS_DEBUG_EIGRP(a, b) \
++	(term_debug_eigrp & EIGRP_DEBUG_ ## b)
++#define IS_DEBUG_EIGRP_EVENT IS_DEBUG_EIGRP(event, EVENT)
++
++
++/* Prototypes. */
++extern const char *eigrp_if_name_string (struct eigrp_interface *);
++extern const char *eigrp_if_ip_string (struct eigrp_interface *);
++extern const char *eigrp_neigh_ip_string (struct eigrp_neighbor *);
++extern const char *eigrp_topology_ip_string (struct eigrp_prefix_entry *);
++
++extern void eigrp_ip_header_dump(struct ip *);
++extern void eigrp_header_dump(struct eigrp_header *);
++
++extern void show_ip_eigrp_interface_header (struct vty *, struct eigrp *);
++extern void show_ip_eigrp_neighbor_header (struct vty *, struct eigrp *);
++extern void show_ip_eigrp_topology_header (struct vty *, struct eigrp *);
++extern void show_ip_eigrp_interface_detail (struct vty *, struct eigrp *,
++		 	 	 	 struct eigrp_interface *);
++extern void show_ip_eigrp_interface_sub (struct vty *, struct eigrp *,
++					 struct eigrp_interface *);
++extern void show_ip_eigrp_neighbor_sub (struct vty *, struct eigrp_neighbor *, int);
++extern void show_ip_eigrp_prefix_entry (struct vty *, struct eigrp_prefix_entry *);
++extern void show_ip_eigrp_neighbor_entry (struct vty *, struct eigrp *, struct eigrp_neighbor_entry *);
++
++extern void eigrp_debug_init (void);
++
++#endif /* _ZEBRA_EIGRPD_DUMP_H_ */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_filter.c eigrp/eigrpd/eigrp_filter.c
+--- a/eigrpd/eigrp_filter.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_filter.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,155 @@
++/*
++ * EIGRP Interface Functions.
++ * Copyright (C) 2013-2015
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *   Frantisek Gazo
++ *   Tomas Hvorkovy
++ *   Martin Kontsek
++ *   Lukas Koribsky
++ *
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++//#include "filter.h"
++//#include "plist.h"
++//#include "distribute.h"
++
++#include "if.h"
++#include "command.h"
++#include "prefix.h"
++#include "table.h"
++#include "thread.h"
++#include "memory.h"
++#include "log.h"
++#include "stream.h"
++#include "filter.h"
++#include "sockunion.h"
++#include "sockopt.h"
++#include "routemap.h"
++#include "if_rmap.h"
++#include "plist.h"
++#include "distribute.h"
++#include "md5.h"
++#include "keychain.h"
++#include "privs.h"
++
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrp_const.h"
++#include "eigrpd/eigrp_filter.h"
++
++/* Distribute-list update functions. */
++void
++eigrp_distribute_update (struct distribute *dist)
++{
++  struct interface *ifp;
++  struct eigrp_interface *ei;
++  struct access_list *alist;
++  struct prefix_list *plist;
++
++  if (! dist->ifname)
++    return;
++
++  ifp = if_lookup_by_name (dist->ifname);
++  if (ifp == NULL)
++    return;
++
++  ei = ifp->info;
++
++  if (dist->list[DISTRIBUTE_IN])
++    {
++      alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
++      if (alist)
++	ei->list[EIGRP_FILTER_IN] = alist;
++      else
++	ei->list[EIGRP_FILTER_IN] = NULL;
++    }
++  else
++    ei->list[EIGRP_FILTER_IN] = NULL;
++
++  if (dist->list[DISTRIBUTE_OUT])
++    {
++      alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
++      if (alist)
++	ei->list[EIGRP_FILTER_OUT] = alist;
++      else
++	ei->list[EIGRP_FILTER_OUT] = NULL;
++    }
++  else
++    ei->list[EIGRP_FILTER_OUT] = NULL;
++
++  if (dist->prefix[DISTRIBUTE_IN])
++    {
++      plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
++      if (plist)
++	ei->prefix[EIGRP_FILTER_IN] = plist;
++      else
++	ei->prefix[EIGRP_FILTER_IN] = NULL;
++    }
++  else
++    ei->prefix[EIGRP_FILTER_IN] = NULL;
++
++  if (dist->prefix[DISTRIBUTE_OUT])
++    {
++      plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
++      if (plist)
++	ei->prefix[EIGRP_FILTER_OUT] = plist;
++      else
++	ei->prefix[EIGRP_FILTER_OUT] = NULL;
++    }
++  else
++    ei->prefix[EIGRP_FILTER_OUT] = NULL;
++}
++
++void
++eigrp_distribute_update_interface (struct interface *ifp)
++{
++  struct distribute *dist;
++
++  dist = distribute_lookup (ifp->name);
++  if (dist)
++    eigrp_distribute_update (dist);
++}
++
++/* Update all interface's distribute list. */
++/* ARGSUSED */
++void
++eigrp_distribute_update_all (struct prefix_list *notused)
++{
++  struct interface *ifp;
++  struct listnode *node, *nnode;
++
++  for (ALL_LIST_ELEMENTS (eigrp_om->iflist, node, nnode, ifp))
++    eigrp_distribute_update_interface (ifp);
++}
++
++/* ARGSUSED */
++void
++eigrp_distribute_update_all_wrapper(struct access_list *notused)
++{
++        eigrp_distribute_update_all(NULL);
++}
++
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_filter.h eigrp/eigrpd/eigrp_filter.h
+--- a/eigrpd/eigrp_filter.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_filter.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,20 @@
++/*
++ * eigrp_filter.h
++ *
++ *  Created on: Feb 26, 2015
++ *      Author: martin
++ */
++
++#ifndef EIGRPD_EIGRP_FILTER_H_
++#define EIGRPD_EIGRP_FILTER_H_
++
++
++extern void eigrp_distribute_update (struct distribute *);
++
++extern void eigrp_distribute_update_interface (struct interface *);
++
++extern void eigrp_distribute_update_all (struct prefix_list *);
++
++extern void eigrp_distribute_update_all_wrapper(struct access_list *);
++
++#endif /* EIGRPD_EIGRP_FILTER_H_ */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_fsm.c eigrp/eigrpd/eigrp_fsm.c
+--- a/eigrpd/eigrp_fsm.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_fsm.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,502 @@
++/*
++ * EIGRPd Finite State Machine (DUAL).
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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 contains functions for executing logic of finite state machine
++ *
++ *                                +------------ +
++ *                                |     (7)     |
++ *                                |             v
++ *                    +=====================================+
++ *                    |                                     |
++ *                    |              Passive                |
++ *                    |                                     |
++ *                    +=====================================+
++ *                        ^     |     ^     ^     ^    |
++ *                     (3)|     |  (1)|     |  (1)|    |
++ *                        |  (0)|     |  (3)|     | (2)|
++ *                        |     |     |     |     |    +---------------+
++ *                        |     |     |     |     |                     \
++ *              +--------+      |     |     |     +-----------------+    \
++ *            /                /     /      |                        \    \
++ *          /                /     /        +----+                    \    \
++ *         |                |     |               |                    |    |
++ *         |                v     |               |                    |    v
++ *    +===========+   (6)  +===========+       +===========+   (6)   +===========+
++ *    |           |------->|           |  (5)  |           |-------->|           |
++ *    |           |   (4)  |           |------>|           |   (4)   |           |
++ *    | ACTIVE 0  |<-------| ACTIVE 1  |       | ACTIVE 2  |<--------| ACTIVE 3  |
++ * +--|           |     +--|           |    +--|           |      +--|           |
++ * |  +===========+     |  +===========+    |  +===========+      |  +===========+
++ * |       ^  |(5)      |      ^            |    ^    ^           |         ^
++ * |       |  +---------|------|------------|----+    |           |         |
++ * +-------+            +------+            +---------+           +---------+
++ *    (7)                 (7)                  (7)                   (7)
++ *
++ * 0- input event other than query from successor, FC not satisfied
++ * 1- last reply, FD is reset
++ * 2- query from successor, FC not satisfied
++ * 3- last reply, FC satisfied with current value of FDij
++ * 4- distance increase while in active state
++ * 5- query from successor while in active state
++ * 6- last reply, FC not satisfied with current value of FDij
++ * 7- state not changed, usually by receiving not last reply
++ *
++ */
++
++#include <thread.h>
++#include <zebra.h>
++
++#include "prefix.h"
++#include "table.h"
++#include "memory.h"
++#include "log.h"
++#include "linklist.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_network.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_topology.h"
++#include "eigrpd/eigrp_fsm.h"
++
++/*
++ * Prototypes
++ */
++int
++eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *);
++int
++eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *);
++int
++eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *);
++int
++eigrp_fsm_event_lr(struct eigrp_fsm_action_message *);
++int
++eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *);
++int
++eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *);
++int
++eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *);
++int
++eigrp_fsm_event_qact(struct eigrp_fsm_action_message *);
++
++//---------------------------------------------------------------------
++
++/*
++ * NSM - field of fields of struct containing one function each.
++ * Which function is used depends on actual state of FSM and occurred
++ * event(arrow in diagram). Usage:
++ * NSM[actual/starting state][occurred event].func
++ * Functions are should be executed within separate thread.
++ */
++struct {
++	int
++	(*func)(struct eigrp_fsm_action_message *);
++} NSM[EIGRP_FSM_STATE_MAX][EIGRP_FSM_EVENT_MAX] = { {
++//PASSIVE STATE
++		{ eigrp_fsm_event_nq_fcn }, /* Event 0 */
++		{ eigrp_fsm_event_keep_state }, /* Event 1 */
++		{ eigrp_fsm_event_q_fcn }, /* Event 2 */
++		{ eigrp_fsm_event_keep_state }, /* Event 3 */
++		{ eigrp_fsm_event_keep_state }, /* Event 4 */
++		{ eigrp_fsm_event_keep_state }, /* Event 5 */
++		{ eigrp_fsm_event_keep_state }, /* Event 6 */
++		{ eigrp_fsm_event_keep_state }, /* Event 7 */
++}, {
++//Active 0 state
++		{ eigrp_fsm_event_keep_state }, /* Event 0 */
++		{ eigrp_fsm_event_keep_state }, /* Event 1 */
++		{ eigrp_fsm_event_keep_state }, /* Event 2 */
++		{ eigrp_fsm_event_lr_fcs }, /* Event 3 */
++		{ eigrp_fsm_event_keep_state }, /* Event 4 */
++		{ eigrp_fsm_event_qact }, /* Event 5 */
++		{ eigrp_fsm_event_lr_fcn }, /* Event 6 */
++		{ eigrp_fsm_event_keep_state }, /* Event 7 */
++
++}, {
++//Active 1 state
++		{ eigrp_fsm_event_keep_state }, /* Event 0 */
++		{ eigrp_fsm_event_lr }, /* Event 1 */
++		{ eigrp_fsm_event_keep_state }, /* Event 2 */
++		{ eigrp_fsm_event_keep_state }, /* Event 3 */
++		{ eigrp_fsm_event_dinc }, /* Event 4 */
++		{ eigrp_fsm_event_qact }, /* Event 5 */
++		{ eigrp_fsm_event_keep_state }, /* Event 6 */
++		{ eigrp_fsm_event_keep_state }, /* Event 7 */
++}, {
++//Active 2 state
++		{ eigrp_fsm_event_keep_state }, /* Event 0 */
++		{ eigrp_fsm_event_keep_state }, /* Event 1 */
++		{ eigrp_fsm_event_keep_state }, /* Event 2 */
++		{ eigrp_fsm_event_lr_fcs }, /* Event 3 */
++		{ eigrp_fsm_event_keep_state }, /* Event 4 */
++		{ eigrp_fsm_event_keep_state }, /* Event 5 */
++		{ eigrp_fsm_event_lr_fcn }, /* Event 6 */
++		{ eigrp_fsm_event_keep_state }, /* Event 7 */
++}, {
++//Active 3 state
++		{ eigrp_fsm_event_keep_state }, /* Event 0 */
++		{ eigrp_fsm_event_lr }, /* Event 1 */
++		{ eigrp_fsm_event_keep_state }, /* Event 2 */
++		{ eigrp_fsm_event_keep_state }, /* Event 3 */
++		{ eigrp_fsm_event_dinc }, /* Event 4 */
++		{ eigrp_fsm_event_keep_state }, /* Event 5 */
++		{ eigrp_fsm_event_keep_state }, /* Event 6 */
++		{ eigrp_fsm_event_keep_state }, /* Event 7 */
++}, };
++
++/*
++ * Main function in which are make decisions which event occurred.
++ * msg - argument of type struct eigrp_fsm_action_message contain
++ * details about what happen
++ *
++ * Return number of occurred event (arrow in diagram).
++ *
++ */
++int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) {
++	// Loading base information from message
++	//struct eigrp *eigrp = msg->eigrp;
++	struct eigrp_prefix_entry *prefix = msg->prefix;
++	struct eigrp_neighbor_entry *entry = msg->entry;
++	u_char actual_state = prefix->state;
++
++	if (entry == NULL) {
++		entry = eigrp_neighbor_entry_new();
++		entry->adv_router = msg->adv_router;
++		entry->ei = msg->adv_router->ei;
++		entry->prefix = prefix;
++		msg->entry = entry;
++	}
++
++	// Dividing by actual state of prefix's FSM
++	switch (actual_state) {
++	case EIGRP_FSM_STATE_PASSIVE: {
++		//Calculate resultant metrics and insert to correct position in entries list
++		eigrp_topology_update_distance(msg);
++
++		struct eigrp_neighbor_entry * head =
++				(struct eigrp_neighbor_entry *) entry->prefix->entries->head->data;
++		//zlog_info ("flag: %d rdist: %u dist: %u pfdist: %u pdist: %u", head->flags, head->reported_distance, head->distance, prefix->fdistance, prefix->distance);
++		if (head->reported_distance < prefix->fdistance) {
++			return EIGRP_FSM_KEEP_STATE;
++		}
++		/*
++		 * if best entry doesn't satisfy feasibility condition it means move to active state
++		 * dependently if it was query from successor
++		 */
++		else {
++			if (msg->packet_type == EIGRP_OPC_QUERY) {
++				return EIGRP_FSM_EVENT_Q_FCN;
++			} else {
++				return EIGRP_FSM_EVENT_NQ_FCN;
++			}
++		}
++
++		break;
++	}
++	case EIGRP_FSM_STATE_ACTIVE_0: {
++		eigrp_topology_update_distance(msg);
++
++		if (msg->packet_type == EIGRP_OPC_REPLY) {
++			listnode_delete(prefix->rij, entry->adv_router);
++			if (prefix->rij->count) {
++				return EIGRP_FSM_KEEP_STATE;
++			} else {
++				zlog_info("All reply received\n");
++				if (((struct eigrp_neighbor_entry *) prefix->entries->head->data)->reported_distance
++						< prefix->fdistance) {
++					return EIGRP_FSM_EVENT_LR_FCS;
++				}
++
++				return EIGRP_FSM_EVENT_LR_FCN;
++			}
++		} else if (msg->packet_type == EIGRP_OPC_QUERY
++				&& (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
++			return EIGRP_FSM_EVENT_QACT;
++		}
++
++		return EIGRP_FSM_KEEP_STATE;
++
++		break;
++	}
++	case EIGRP_FSM_STATE_ACTIVE_1: {
++		int change = eigrp_topology_update_distance(msg);
++
++		if (msg->packet_type == EIGRP_OPC_QUERY
++				&& (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
++			return EIGRP_FSM_EVENT_QACT;
++		} else if (msg->packet_type == EIGRP_OPC_REPLY) {
++			listnode_delete(prefix->rij, entry->adv_router);
++
++			if (change == 1
++					&& (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
++				return EIGRP_FSM_EVENT_DINC;
++			} else if (prefix->rij->count) {
++				return EIGRP_FSM_KEEP_STATE;
++			} else {
++				zlog_info("All reply received\n");
++				return EIGRP_FSM_EVENT_LR;
++			}
++		} else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1
++				&& (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
++			return EIGRP_FSM_EVENT_DINC;
++		}
++		return EIGRP_FSM_KEEP_STATE;
++
++		break;
++	}
++	case EIGRP_FSM_STATE_ACTIVE_2: {
++
++		eigrp_topology_update_distance(msg);
++
++		if (msg->packet_type == EIGRP_OPC_REPLY) {
++			listnode_delete(prefix->rij, entry->adv_router);
++			if (prefix->rij->count) {
++				return EIGRP_FSM_KEEP_STATE;
++			} else {
++				zlog_info("All reply received\n");
++				if (((struct eigrp_neighbor_entry *) prefix->entries->head->data)->reported_distance
++						< prefix->fdistance) {
++					return EIGRP_FSM_EVENT_LR_FCS;
++				}
++
++				return EIGRP_FSM_EVENT_LR_FCN;
++			}
++		}
++		return EIGRP_FSM_KEEP_STATE;
++
++		break;
++	}
++	case EIGRP_FSM_STATE_ACTIVE_3: {
++
++		int change = eigrp_topology_update_distance(msg);
++
++		if (msg->packet_type == EIGRP_OPC_REPLY) {
++			listnode_delete(prefix->rij, entry->adv_router);
++
++			if (change == 1
++					&& (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
++				return EIGRP_FSM_EVENT_DINC;
++			} else if (prefix->rij->count) {
++				return EIGRP_FSM_KEEP_STATE;
++			} else {
++				zlog_info("All reply received\n");
++				return EIGRP_FSM_EVENT_LR;
++			}
++		} else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1
++				&& (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
++			return EIGRP_FSM_EVENT_DINC;
++		}
++		return EIGRP_FSM_KEEP_STATE;
++
++		break;
++	}
++	}
++
++	return EIGRP_FSM_KEEP_STATE;
++}
++
++/*
++ * Function made to execute in separate thread.
++ * Load argument from thread and execute proper NSM function
++ */
++int eigrp_fsm_event(struct eigrp_fsm_action_message *msg, int event) {
++
++	zlog_info("EIGRP AS: %d State: %d  Event: %d Network: %s\n", msg->eigrp->AS,
++			msg->prefix->state, event, eigrp_topology_ip_string(msg->prefix));
++	(*(NSM[msg->prefix->state][event].func))(msg);
++
++	return 1;
++}
++/*
++ * Function of event 0.
++ *
++ */
++int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg) {
++	struct eigrp *eigrp = msg->eigrp;
++	struct eigrp_prefix_entry *prefix = msg->prefix;
++	struct list *successors = eigrp_topology_get_successor(prefix);
++	prefix->state = EIGRP_FSM_STATE_ACTIVE_1;
++	prefix->rdistance = prefix->distance = prefix->fdistance =
++			((struct eigrp_neighbor_entry *) successors->head->data)->distance;
++	prefix->reported_metric =
++			((struct eigrp_neighbor_entry *) successors->head->data)->total_metric;
++
++	if (eigrp_nbr_count_get()) {
++		prefix->req_action |= EIGRP_FSM_NEED_QUERY;
++		listnode_add(eigrp->topology_changes_internalIPV4,prefix);
++	} else {
++		eigrp_fsm_event_lr(msg); //in the case that there are no more neighbors left
++	}
++
++	return 1;
++}
++
++int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg) {
++	struct eigrp *eigrp = msg->eigrp;
++	struct eigrp_prefix_entry *prefix = msg->prefix;
++	struct list *successors = eigrp_topology_get_successor(prefix);
++	prefix->state = EIGRP_FSM_STATE_ACTIVE_3;
++	prefix->rdistance = prefix->distance = prefix->fdistance =
++			((struct eigrp_neighbor_entry *) successors->head->data)->distance;
++	prefix->reported_metric =
++			((struct eigrp_neighbor_entry *) successors->head->data)->total_metric;
++	if (eigrp_nbr_count_get()) {
++			prefix->req_action |= EIGRP_FSM_NEED_QUERY;
++			listnode_add(eigrp->topology_changes_internalIPV4,prefix);
++		} else {
++			eigrp_fsm_event_lr(msg); //in the case that there are no more neighbors left
++		}
++
++	return 1;
++}
++
++int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg) {
++
++	struct eigrp_prefix_entry *prefix = msg->prefix;
++	struct eigrp_neighbor_entry *entry = msg->entry;
++
++	if (prefix->state == EIGRP_FSM_STATE_PASSIVE) {
++		if (!eigrp_metrics_is_same(&prefix->reported_metric,
++				&((struct eigrp_neighbor_entry *) prefix->entries->head->data)->total_metric)) {
++			prefix->rdistance =
++					prefix->fdistance =
++							prefix->distance =
++									((struct eigrp_neighbor_entry *) prefix->entries->head->data)->distance;
++			prefix->reported_metric =
++					((struct eigrp_neighbor_entry *) prefix->entries->head->data)->total_metric;
++			if (msg->packet_type == EIGRP_OPC_QUERY)
++				eigrp_send_reply(msg->adv_router, msg->entry);
++			prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
++			listnode_add((eigrp_lookup())->topology_changes_internalIPV4,prefix);
++		}
++		eigrp_topology_update_node_flags(prefix);
++		eigrp_update_routing_table(prefix);
++	}
++
++	if (msg->packet_type == EIGRP_OPC_QUERY)
++		eigrp_send_reply(msg->adv_router, prefix);
++
++	return 1;
++}
++
++int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg) {
++	struct eigrp *eigrp = msg->eigrp;
++	struct eigrp_prefix_entry *prefix = msg->prefix;
++	prefix->fdistance =
++			prefix->distance =
++					prefix->rdistance =
++							((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->distance;
++	prefix->reported_metric =
++			((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->total_metric;
++	if (prefix->state == EIGRP_FSM_STATE_ACTIVE_3)
++		eigrp_send_reply(
++				((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor(
++						prefix)->head->data))->adv_router, prefix);
++	prefix->state = EIGRP_FSM_STATE_PASSIVE;
++	prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
++	listnode_add(eigrp->topology_changes_internalIPV4,prefix);
++	eigrp_topology_update_node_flags(prefix);
++	eigrp_update_routing_table(prefix);
++	eigrp_update_topology_table_prefix(eigrp->topology_table, prefix);
++
++	return 1;
++}
++
++int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg) {
++
++	msg->prefix->state =
++			msg->prefix->state == EIGRP_FSM_STATE_ACTIVE_1 ?
++					EIGRP_FSM_STATE_ACTIVE_0 : EIGRP_FSM_STATE_ACTIVE_2;
++	msg->prefix->distance =
++			((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor(
++					msg->prefix)->head->data))->distance;
++	if (!msg->prefix->rij->count) {
++		(*(NSM[msg->prefix->state][eigrp_get_fsm_event(msg)].func))(msg);
++	}
++
++	return 1;
++}
++
++int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg) {
++	struct eigrp *eigrp = msg->eigrp;
++	struct eigrp_prefix_entry *prefix = msg->prefix;
++	prefix->state = EIGRP_FSM_STATE_PASSIVE;
++	prefix->distance =
++			prefix->rdistance =
++					((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->distance;
++	prefix->reported_metric =
++			((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->total_metric;
++	prefix->fdistance =
++			prefix->fdistance > prefix->distance ?
++					prefix->distance : prefix->fdistance;
++	if (prefix->state == EIGRP_FSM_STATE_ACTIVE_2)
++		eigrp_send_reply(
++				((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor(
++						prefix)->head->data))->adv_router, prefix);
++	prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
++	listnode_add(eigrp->topology_changes_internalIPV4,prefix);
++	eigrp_topology_update_node_flags(prefix);
++	eigrp_update_routing_table(prefix);
++	eigrp_update_topology_table_prefix(eigrp->topology_table, prefix);
++
++	return 1;
++}
++
++int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg) {
++	struct eigrp *eigrp = msg->eigrp;
++	struct eigrp_prefix_entry *prefix = msg->prefix;
++	prefix->state =
++			prefix->state == EIGRP_FSM_STATE_ACTIVE_0 ?
++					EIGRP_FSM_STATE_ACTIVE_1 : EIGRP_FSM_STATE_ACTIVE_3;
++	struct eigrp_neighbor_entry *best_successor =
++			((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor(
++					prefix)->head->data));
++	prefix->rdistance = prefix->distance = best_successor->distance;
++	prefix->reported_metric = best_successor->total_metric;
++	if (eigrp_nbr_count_get()) {
++		prefix->req_action |= EIGRP_FSM_NEED_QUERY;
++		listnode_add(eigrp->topology_changes_internalIPV4,prefix);
++	} else {
++		eigrp_fsm_event_lr(msg); //in the case that there are no more neighbors left
++	}
++
++	return 1;
++}
++
++int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg) {
++	msg->prefix->state = EIGRP_FSM_STATE_ACTIVE_2;
++	msg->prefix->distance =
++			((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor(
++					msg->prefix)->head->data))->distance;
++	return 1;
++}
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_fsm.h eigrp/eigrpd/eigrp_fsm.h
+--- a/eigrpd/eigrp_fsm.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_fsm.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,37 @@
++/*
++ * EIGRP Finite State Machine (DUAL).
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRP_FSM_H
++#define _ZEBRA_EIGRP_FSM_H
++
++
++extern int eigrp_get_fsm_event (struct eigrp_fsm_action_message *);
++extern int eigrp_fsm_event (struct eigrp_fsm_action_message *, int);
++
++
++#endif /* _ZEBRA_EIGRP_DUAL_H */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_hello.c eigrp/eigrpd/eigrp_hello.c
+--- a/eigrpd/eigrp_hello.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_hello.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,722 @@
++/*
++ * EIGRP Sending and Receiving EIGRP Hello Packets.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "thread.h"
++#include "memory.h"
++#include "linklist.h"
++#include "prefix.h"
++#include "if.h"
++#include "table.h"
++#include "sockunion.h"
++#include "stream.h"
++#include "log.h"
++#include "sockopt.h"
++#include "checksum.h"
++#include "md5.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_macros.h"
++
++/* Packet Type String. */
++static const struct message eigrp_general_tlv_type_str[] =
++{
++  { EIGRP_TLV_PARAMETER,	"PARAMETER"		},
++  { EIGRP_TLV_AUTH,		"AUTH"			},
++  { EIGRP_TLV_SEQ,		"SEQ"			},
++  { EIGRP_TLV_SW_VERSION,	"SW_VERSION"		},
++  { EIGRP_TLV_NEXT_MCAST_SEQ,	"NEXT_MCAST_SEQ"	},
++  { EIGRP_TLV_PEER_TERMINATION,	"PEER_TERMINATION"	},
++  { EIGRP_TLV_PEER_MTRLIST,	"PEER_MTRLIST"		},
++  { EIGRP_TLV_PEER_TIDLIST,	"PEER_TIDLIST"		},
++};
++
++static const size_t eigrp_general_tlv_type_str_max = sizeof(eigrp_general_tlv_type_str) /
++  sizeof(eigrp_general_tlv_type_str[0]);
++
++
++/*
++ * @fn eigrp_hello_timer
++ *
++ * @param[in]	thread	current execution thread timer is associated with
++ * 
++ * @return int	always returns 0
++ *
++ * @par
++ * Called once per "hello" time interval, default 5 seconds
++ * Sends hello packet via multicast for all interfaces eigrp
++ * is configured for
++ */
++int
++eigrp_hello_timer (struct thread *thread)
++{
++  struct eigrp_interface *ei;
++
++  ei = THREAD_ARG(thread);
++  ei->t_hello = NULL;
++
++  if (IS_DEBUG_EIGRP(0, TIMERS))
++    zlog (NULL, LOG_DEBUG, "Start Hello Timer (%s) Expire [%u]",
++	  IF_NAME(ei), EIGRP_IF_PARAM(ei, v_hello));
++
++  /* Sending hello packet. */
++  eigrp_hello_send(ei, EIGRP_HELLO_NORMAL);
++
++  /* Hello timer set. */
++  ei->t_hello = thread_add_timer(master, eigrp_hello_timer, ei,
++				 EIGRP_IF_PARAM(ei, v_hello));
++
++  return 0;
++}
++
++/**
++ * @fn eigrp_hello_parameter_decode
++ *
++ * @param[in]		nbr	neighbor the ACK should be sent to
++ * @param[in]		param	pointer packet TLV is stored to
++ *
++ * @return u_int16_t	number of bytes added to packet stream
++ *
++ * @par
++ * Encode Parameter TLV, used to convey metric weights and the hold time.
++ *
++ * @usage
++ * Note the addition of K6 for the new extended metrics, and does not apply to
++ * older TLV packet formats.
++ */
++static void
++eigrp_hello_parameter_decode (struct eigrp_neighbor *nbr,
++			       struct eigrp_tlv_hdr_type *tlv)			      
++{
++  struct eigrp *eigrp = nbr->ei->eigrp;
++  struct TLV_Parameter_Type *param = (struct TLV_Parameter_Type *)tlv;
++
++  /* copy over the values passed in by the neighbor */
++  nbr->K1 = param->K1;
++  nbr->K2 = param->K2;
++  nbr->K3 = param->K3;
++  nbr->K4 = param->K4;
++  nbr->K5 = param->K5;
++  nbr->K6 = param->K6;
++  nbr->v_holddown = ntohs(param->hold_time);
++
++  /*
++   * Check K1-K5 have the correct values to be able to become neighbors
++   * K6 does not have to match
++   */
++  if ((eigrp->k_values[0] == nbr->K1) &&
++      (eigrp->k_values[1] == nbr->K2) &&
++      (eigrp->k_values[2] == nbr->K3) &&
++      (eigrp->k_values[3] == nbr->K4) &&
++      (eigrp->k_values[4] == nbr->K5))
++    {
++
++      if (eigrp_nbr_state_get(nbr) == EIGRP_NEIGHBOR_DOWN)
++	{
++	  zlog_info("Neighbor %s (%s) is pending: new adjacency",
++		    inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
++
++	  /* Expedited hello sent */
++	    eigrp_hello_send(nbr->ei, EIGRP_HELLO_NORMAL);
++
++//	  if(ntohl(nbr->ei->address->u.prefix4.s_addr) > ntohl(nbr->src.s_addr))
++	      eigrp_update_send_init(nbr);
++
++	  eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING);
++	}
++    }
++  else
++    {
++      if (eigrp_nbr_state_get(nbr) != EIGRP_NEIGHBOR_DOWN)
++	{
++	  if ((param->K1 & param->K2 & param->K3 & param->K4 & param->K5) == 255)
++	    {
++              zlog_info ("Neighbor %s (%s) going down: Peer Termination",
++                         inet_ntoa (nbr->src),ifindex2ifname (nbr->ei->ifp->ifindex));
++              eigrp_nbr_delete (nbr);
++	    }
++	  else
++	    {
++              zlog_info ("Neighbor %s (%s) going down: Kvalue mismatch",
++                         inet_ntoa (nbr->src),ifindex2ifname (nbr->ei->ifp->ifindex));
++              eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
++	    }
++	}
++    }
++}
++
++static u_char
++eigrp_hello_authentication_decode(struct stream *s, struct eigrp_tlv_hdr_type *tlv_header, struct eigrp_neighbor *nbr)
++{
++
++  struct TLV_MD5_Authentication_Type *md5;
++
++  md5 = (struct TLV_MD5_Authentication_Type *) tlv_header;
++
++  if(md5->auth_type == EIGRP_AUTH_TYPE_MD5)
++    return eigrp_check_md5_digest(s, tlv_header, nbr, EIGRP_AUTH_BASIC_HELLO_FLAG);
++  else if (md5->auth_type == EIGRP_AUTH_TYPE_SHA256)
++    return eigrp_check_sha256_digest(s, (struct TLV_SHA256_Authentication_Type *) tlv_header, nbr, EIGRP_AUTH_BASIC_HELLO_FLAG);
++
++  return 0;
++}
++
++/**
++ * @fn eigrp_sw_version_decode
++ *
++ * @param[in]		nbr	neighbor the ACK shoudl be sent to
++ * @param[in]		param	pointer to TLV software version information
++ *
++ * @return void
++ *
++ * @par
++ * Read the software version in the specified location.
++ * This consists of two bytes of OS version, and two bytes of EIGRP
++ * revision number.
++ */
++static void
++eigrp_sw_version_decode (struct eigrp_neighbor *nbr,
++			 struct eigrp_tlv_hdr_type *tlv)			      
++{
++  struct TLV_Software_Type *version = (struct TLV_Software_Type *)tlv;
++
++  nbr->os_rel_major = version->vender_major;
++  nbr->os_rel_minor = version->vender_minor;
++  nbr->tlv_rel_major = version->eigrp_major;
++  nbr->tlv_rel_minor = version->eigrp_minor;
++  return;
++}
++
++/**
++ * @fn eigrp_peer_termination_decode
++ *
++ * @param[in]		nbr	neighbor the ACK shoudl be sent to
++ * @param[in]		param	pointer to TLV software version information
++ *
++ * @return void
++ *
++ * @par
++ * Read the list of addresses in the TLV and match to out address. If
++ * a match is found, move the sending neighbor to the down state. If
++ * out address is not in the TLV, then ignore the peer termination
++ *
++ * @usage
++ *   Place holder - Not currently supported.
++ */
++static void
++eigrp_peer_termination_decode (struct eigrp_neighbor *nbr,
++			       struct eigrp_tlv_hdr_type *tlv)
++{
++  return;
++}
++
++/*
++ * @fn eigrp_hello_receive
++ *
++ * @param[in]	eigrp		eigrp routing process
++ * @param[in]	iph		pointer to ip header
++ * @param[in]	eigrph		pointer to eigrp header
++ * @param[in]	s		input ip stream
++ * @param[in]	ei		eigrp interface packet arrived on
++ * @param[in]	size		size of eigrp packet
++ *
++ * @return void
++ *
++ * @par
++ * This is the main worker function for processing hello packets. It
++ * will validate the peer associated with the src ip address of the ip
++ * header, and then decode each of the general TLVs which the packet
++ * may contain.
++ * 
++ * @usage
++ * Not all TLVs are current decoder.  This is a work in progress..
++ */
++void
++eigrp_hello_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
++		     struct stream *s, struct eigrp_interface *ei, int size)
++{
++  struct eigrp_tlv_hdr_type *tlv_header;
++  struct eigrp_neighbor *nbr;
++  uint16_t	type;
++  uint16_t	length;
++
++  /* get neighbor struct */
++  nbr = eigrp_nbr_get(ei, eigrph, iph);
++
++  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
++  assert(nbr);
++  
++  if (IS_DEBUG_EIGRP_PACKET(eigrph->opcode - 1, RECV))
++    zlog_debug("Processing Hello size[%u] int(%s) nbr(%s)",
++	       size, ifindex2ifname(nbr->ei->ifp->ifindex), 
++	       inet_ntoa(nbr->src));
++
++  size -= EIGRP_HEADER_LEN;
++  if (size < 0)
++    return;
++
++  tlv_header = (struct eigrp_tlv_hdr_type *)eigrph->tlv;
++
++  do {
++    type = ntohs(tlv_header->type);
++    length = ntohs(tlv_header->length);
++
++    if ((length > 0) && (length <= size))
++      {
++	if (IS_DEBUG_EIGRP_PACKET(0, RECV))
++	  zlog_debug("  General TLV(%s)", LOOKUP(eigrp_general_tlv_type_str, type));
++
++	// determine what General TLV is being processed
++	switch (type)
++	  {
++	  case EIGRP_TLV_PARAMETER:
++	    eigrp_hello_parameter_decode(nbr, tlv_header);
++	    break;
++	  case EIGRP_TLV_AUTH:
++	    {
++//              if(eigrp_hello_authentication_decode(s,tlv_header,nbr) == 0)
++//                return;
++//              else
++//                break;
++              break;
++	    }
++	  case EIGRP_TLV_SEQ:
++	    break;
++	  case EIGRP_TLV_SW_VERSION:
++	    eigrp_sw_version_decode(nbr, tlv_header);
++	    break;
++	  case EIGRP_TLV_NEXT_MCAST_SEQ:
++	    break;
++	  case EIGRP_TLV_PEER_TERMINATION:
++	    eigrp_peer_termination_decode(nbr, tlv_header);
++	    break;
++	  case EIGRP_TLV_PEER_MTRLIST:
++	  case EIGRP_TLV_PEER_TIDLIST:
++	    break;
++	  default:
++	    break;
++	  }
++    }
++
++    tlv_header = (struct eigrp_tlv_hdr_type *)(((char *)tlv_header) + length);
++    size -= length;
++
++  } while (size > 0);
++
++
++  /*If received packet is hello with Parameter TLV*/
++  if (ntohl(eigrph->ack) == 0)
++    {
++      /* increment statistics. */
++      ei->hello_in++;
++      eigrp_nbr_state_update(nbr);
++
++    }
++
++  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
++      zlog_debug("Hello Packet received from %s", inet_ntoa(nbr->src));
++
++}
++
++/**
++ * @fn eigrp_sw_version_encode
++ *
++ * @param[in,out]	s	packet stream TLV is stored to
++ *
++ * @return u_int16_t	number of bytes added to packet stream
++ *
++ * @par
++ * Store the software version in the specified location.
++ * This consists of two bytes of OS version, and two bytes of EIGRP
++ * revision number.
++ */
++static u_int16_t
++eigrp_sw_version_encode (struct stream *s)
++{
++  u_int16_t length = EIGRP_TLV_SW_VERSION_LEN;
++
++  // setup the tlv fields
++  stream_putw(s, EIGRP_TLV_SW_VERSION);
++  stream_putw(s, length);
++
++  // encode the version of quagga we're running
++  // DVS: need to figure out a cleaner way to do this
++  stream_putc(s, 0);		//!< major os version
++  stream_putc(s, 99);		//!< minor os version
++
++  /* and the core eigrp version */
++  stream_putc(s, EIGRP_MAJOR_VERSION);
++  stream_putc(s, EIGRP_MINOR_VERSION);
++
++  return(length);
++}
++
++/**
++ * @fn eigrp_tidlist_encode
++ *
++ * @param[in,out]	s	packet stream TLV is stored to
++ *
++ * @return void
++ *
++ * @par
++ * If doing mutli-topology, then store the supported TID list.
++ * This is currently a place holder function
++ */
++static u_int16_t
++eigrp_tidlist_encode (struct stream *s)
++{
++  u_int16_t length = EIGRP_TLV_SW_VERSION_LEN;
++  return 0;
++}
++
++/**
++ * @fn eigrp_sequence_encode
++ *
++ * @param[in,out]       s       packet stream TLV is stored to
++ *
++ * @return u_int16_t    number of bytes added to packet stream
++ *
++ * @par
++ * Part of conditional receive process
++ *
++ */
++static u_int16_t
++eigrp_sequence_encode (struct stream *s)
++{
++  u_int16_t length = EIGRP_TLV_SEQ_BASE_LEN;
++  struct eigrp *eigrp;
++  struct eigrp_interface *ei;
++  struct listnode *node, *node2, *nnode2;
++  struct eigrp_neighbor *nbr;
++  size_t backup_end, size_end;
++  int found;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      return 0;
++    }
++
++  // add in the parameters TLV
++  backup_end = stream_get_endp(s);
++  stream_putw(s, EIGRP_TLV_SEQ);
++  size_end = s->endp;
++  stream_putw(s, 0x0000);
++  stream_putc(s, IPV4_MAX_BYTELEN);
++
++  found = 0;
++  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
++    {
++      for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
++        {
++          if(nbr->multicast_queue->count > 0)
++            {
++              length += (u_int16_t) stream_put_ipv4(s,nbr->src.s_addr);
++              found = 1;
++            }
++        }
++    }
++
++  if(found == 0)
++    {
++      stream_set_endp(s,backup_end);
++      return 0;
++    }
++
++  backup_end = stream_get_endp (s);
++  stream_set_endp (s,size_end);
++  stream_putw (s, length);
++  stream_set_endp (s, backup_end);
++
++  return length;
++}
++
++/**
++ * @fn eigrp_sequence_encode
++ *
++ * @param[in,out]       s       packet stream TLV is stored to
++ *
++ * @return u_int16_t    number of bytes added to packet stream
++ *
++ * @par
++ * Part of conditional receive process
++ *
++ */
++static u_int16_t
++eigrp_next_sequence_encode (struct stream *s)
++{
++  u_int16_t length = EIGRP_NEXT_SEQUENCE_TLV_SIZE;
++  struct eigrp *eigrp;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      return 0;
++    }
++
++  // add in the parameters TLV
++    stream_putw(s, EIGRP_TLV_NEXT_MCAST_SEQ);
++    stream_putw(s, EIGRP_NEXT_SEQUENCE_TLV_SIZE);
++    stream_putl(s,eigrp->sequence_number+1);
++
++  return length;
++}
++
++/**
++ * @fn eigrp_hello_parameter_encode
++ *
++ * @param[in]		ei	pointer to interface hello packet came in on
++ * @param[in,out]	s	packet stream TLV is stored to
++ *
++ * @return u_int16_t	number of bytes added to packet stream
++ *
++ * @par
++ * Encode Parameter TLV, used to convey metric weights and the hold time.
++ *
++ * @usage
++ * Note the addition of K6 for the new extended metrics, and does not apply to
++ * older TLV packet formats.
++ */
++static u_int16_t
++eigrp_hello_parameter_encode (struct eigrp_interface *ei, struct stream *s, u_char flags)
++{
++    u_int16_t length = EIGRP_TLV_PARAMETER_LEN;
++
++  // add in the parameters TLV
++  stream_putw(s, EIGRP_TLV_PARAMETER);
++  stream_putw(s, EIGRP_TLV_PARAMETER_LEN);
++
++  //if graceful shutdown is needed to be announced, send all 255 in K values
++  if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN)
++    {
++      stream_putc(s, 0xff); /* K1 */
++      stream_putc(s, 0xff); /* K2 */
++      stream_putc(s, 0xff); /* K3 */
++      stream_putc(s, 0xff); /* K4 */
++      stream_putc(s, 0xff); /* K5 */
++      stream_putc(s, 0xff); /* K6 */
++    }
++  else // set k values
++    {
++      stream_putc(s, ei->eigrp->k_values[0]); /* K1 */
++      stream_putc(s, ei->eigrp->k_values[1]); /* K2 */
++      stream_putc(s, ei->eigrp->k_values[2]); /* K3 */
++      stream_putc(s, ei->eigrp->k_values[3]); /* K4 */
++      stream_putc(s, ei->eigrp->k_values[4]); /* K5 */
++      stream_putc(s, ei->eigrp->k_values[5]); /* K6 */
++    }
++
++  // and set hold time value..
++  stream_putw(s, IF_DEF_PARAMS(ei->ifp)->v_wait);
++
++  return length;
++}
++
++/**
++ * @fn eigrp_hello_encode
++ *
++ * @param[in]		ei	pointer to interface hello packet came in on
++ * @param[in]		s	packet stream TLV is stored to
++ * @param[in]		ack	if non-zero, neigbors sequence packet to ack
++ *
++ * @return eigrp_packet		pointer initialize hello packet
++ *
++ * @par
++ * Allocate an EIGRP hello packet, and add in the the approperate TLVs
++ *
++ */
++static struct eigrp_packet *
++eigrp_hello_encode (struct eigrp_interface *ei, in_addr_t addr, u_int32_t ack, u_char flags)
++{
++  struct eigrp_packet *ep;
++  u_int16_t length = EIGRP_HEADER_LEN;
++
++  // allocate a new packet to be sent
++  ep = eigrp_packet_new(ei->ifp->mtu);
++
++  if (ep)
++    {
++      // encode common header feilds
++      eigrp_packet_header_init(EIGRP_OPC_HELLO, ei, ep->s, 0, 0, ack);
++
++      // encode Authentication TLV
++      if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
++        {
++          length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei);
++        }
++      else if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_SHA256) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
++        {
++          length += eigrp_add_authTLV_SHA256_to_stream(ep->s,ei);
++        }
++
++      // encode Hello packet with approperate TLVs
++      if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN)
++        length += eigrp_hello_parameter_encode(ei, ep->s, EIGRP_HELLO_GRACEFUL_SHUTDOWN);
++      else
++        length += eigrp_hello_parameter_encode(ei, ep->s, EIGRP_HELLO_NORMAL);
++
++      // figure out the version of code we're running
++      length += eigrp_sw_version_encode(ep->s);
++
++      if(flags & EIGRP_HELLO_ADD_SEQUENCE)
++        {
++          length += eigrp_sequence_encode(ep->s);
++          length += eigrp_next_sequence_encode(ep->s);
++        }
++
++      // add in the TID list if doing multi-topology
++      length += eigrp_tidlist_encode(ep->s);
++
++      // Set packet length
++      ep->length = length;
++
++      // set soruce address for the hello packet
++      ep->dst.s_addr = addr;
++
++      if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
++        {
++          eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_BASIC_HELLO_FLAG);
++        }
++      else if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_SHA256) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
++        {
++          eigrp_make_sha256_digest(ei,ep->s, EIGRP_AUTH_BASIC_HELLO_FLAG);
++        }
++
++      // EIGRP Checksum
++      eigrp_packet_checksum(ei, ep->s, length);
++    }
++
++  return(ep);
++}
++
++/**
++ * @fn eigrp_hello_send
++ *
++ * @param[in]		nbr	neighbor the ACK should be sent to
++ *
++ * @return void
++ *
++ * @par
++ *  Send (unicast) a hello packet with the destination address
++ *  associated with the neighbor.  The eigrp header ACK feild will be
++ *  updated to the neighbor's sequence number to acknolodge any
++ *  outstanding packets
++ */
++void
++eigrp_hello_send_ack (struct eigrp_neighbor *nbr)
++{
++  struct eigrp_packet *ep;
++
++  /* if packet succesfully created, add it to the interface queue */
++  ep = eigrp_hello_encode(nbr->ei, nbr->src.s_addr, nbr->recv_sequence_number, EIGRP_HELLO_NORMAL);
++
++  if (ep)
++    {
++      if (IS_DEBUG_EIGRP_PACKET(0, SEND))
++	zlog_debug("Queueing [Hello] Ack Seq [%u] nbr [%s]",
++		   nbr->recv_sequence_number, inet_ntoa(nbr->src));
++
++      /* Add packet to the top of the interface output queue*/
++      eigrp_fifo_push_head(nbr->ei->obuf, ep);
++
++      /* Hook thread to write packet. */
++      if (nbr->ei->on_write_q == 0)
++	{
++	  listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
++	  nbr->ei->on_write_q = 1;
++	}
++      if (nbr->ei->eigrp->t_write == NULL)
++	nbr->ei->eigrp->t_write =
++	  thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
++    }
++}
++
++/**
++ * @fn eigrp_hello_send
++ *
++ * @param[in]		ei	pointer to interface hello shoudl be sent
++ *
++ * @return void
++ *
++ * @par
++ * Build and enqueue a generic (multicast) periodic hello packet for
++ * sending.  If no packets are currently queues, the packet will be
++ * sent immadiatly
++ */
++void
++eigrp_hello_send (struct eigrp_interface *ei, u_char flags)
++{
++  struct eigrp_packet *ep = NULL;
++
++  /* If this is passive interface, do not send EIGRP Hello.
++  if ((EIGRP_IF_PASSIVE_STATUS (ei) == EIGRP_IF_PASSIVE) ||
++      (ei->type != EIGRP_IFTYPE_NBMA))
++    return;
++  */
++
++  if (IS_DEBUG_EIGRP_PACKET(0, SEND))
++    zlog_debug("Queueing [Hello] Interface(%s)", IF_NAME(ei));
++
++  /* if packet was succesfully created, then add it to the interface queue */
++  ep = eigrp_hello_encode(ei, htonl(EIGRP_MULTICAST_ADDRESS), 0, flags);
++
++  if (ep)
++    {
++      // Add packet to the top of the interface output queue
++      eigrp_fifo_push_head(ei->obuf, ep);
++
++      /* Hook thread to write packet. */
++      if (ei->on_write_q == 0)
++        {
++          listnode_add(ei->eigrp->oi_write_q, ei);
++          ei->on_write_q = 1;
++        }
++
++      if (ei->eigrp->t_write == NULL)
++        {
++          if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN)
++            {
++              ei->eigrp->t_write =
++                  thread_execute(master, eigrp_write, ei->eigrp, ei->eigrp->fd);
++            }
++          else
++            {
++              ei->eigrp->t_write =
++                thread_add_write(master, eigrp_write, ei->eigrp, ei->eigrp->fd);
++            }
++	}
++    }
++}
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_interface.c eigrp/eigrpd/eigrp_interface.c
+--- a/eigrpd/eigrp_interface.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_interface.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,569 @@
++/*
++ * EIGRP Interface Functions.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "thread.h"
++#include "linklist.h"
++#include "prefix.h"
++#include "if.h"
++#include "table.h"
++#include "memory.h"
++#include "command.h"
++#include "stream.h"
++#include "log.h"
++#include "keychain.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_network.h"
++#include "eigrpd/eigrp_topology.h"
++
++static void
++eigrp_delete_from_if (struct interface *, struct eigrp_interface *);
++
++static void
++eigrp_add_to_if (struct interface *ifp, struct eigrp_interface *ei)
++{
++  struct route_node *rn;
++  struct prefix p;
++
++  p = *ei->address;
++  p.prefixlen = IPV4_MAX_PREFIXLEN;
++
++  rn = route_node_get (IF_OIFS (ifp), &p);
++  /* rn->info should either be NULL or equal to this ei
++   * as route_node_get may return an existing node
++   */
++  assert (!rn->info || rn->info == ei);
++  rn->info = ei;
++}
++
++struct eigrp_interface *
++eigrp_if_new (struct eigrp *eigrp, struct interface *ifp, struct prefix *p)
++{
++  struct eigrp_interface *ei;
++
++  if ((ei = eigrp_if_table_lookup (ifp, p)) == NULL)
++    {
++      ei = XCALLOC (MTYPE_EIGRP_IF, sizeof (struct eigrp_interface));
++      memset (ei, 0, sizeof (struct eigrp_interface));
++    }
++  else
++    return ei;
++
++  /* Set zebra interface pointer. */
++  ei->ifp = ifp;
++  ei->address = p;
++
++  eigrp_add_to_if (ifp, ei);
++  listnode_add (eigrp->eiflist, ei);
++
++  ei->type = EIGRP_IFTYPE_BROADCAST;
++
++  /* Initialize neighbor list. */
++  ei->nbrs = list_new ();
++
++  ei->crypt_seqnum = time (NULL);
++
++  return ei;
++}
++
++/* lookup ei for specified prefix/ifp */
++struct eigrp_interface *
++eigrp_if_table_lookup (struct interface *ifp, struct prefix *prefix)
++{
++  struct prefix p;
++  struct route_node *rn;
++  struct eigrp_interface *rninfo = NULL;
++
++  p = *prefix;
++  p.prefixlen = IPV4_MAX_PREFIXLEN;
++
++  /* route_node_get implicitly locks */
++  if ((rn = route_node_lookup (IF_OIFS (ifp), &p)))
++    {
++      rninfo = (struct eigrp_interface *) rn->info;
++      route_unlock_node (rn);
++    }
++
++  return rninfo;
++}
++
++int
++eigrp_if_delete_hook (struct interface *ifp)
++{
++
++  struct route_node *rn;
++
++  route_table_finish (IF_OIFS (ifp));
++
++  for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn))
++    if (rn->info)
++      eigrp_del_if_params (rn->info);
++  route_table_finish (IF_OIFS_PARAMS (ifp));
++
++  XFREE (MTYPE_EIGRP_IF_INFO, ifp->info);
++  ifp->info = NULL;
++
++  return 0;
++}
++
++void
++eigrp_if_init ()
++{
++  /* Initialize Zebra interface data structure. */
++  if_init ();
++  eigrp_om->iflist = iflist;
++  if_add_hook (IF_NEW_HOOK, eigrp_if_new_hook);
++  if_add_hook (IF_DELETE_HOOK, eigrp_if_delete_hook);
++}
++
++int
++eigrp_if_new_hook (struct interface *ifp)
++{
++  int rc = 0;
++
++  ifp->info = XCALLOC (MTYPE_EIGRP_IF_INFO, sizeof (struct eigrp_if_info));
++
++  IF_OIFS (ifp) = route_table_init ();
++  IF_OIFS_PARAMS (ifp) = route_table_init ();
++
++  IF_DEF_PARAMS (ifp) = eigrp_new_if_params ();
++
++  SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello);
++  IF_DEF_PARAMS (ifp)->v_hello = (u_int32_t) EIGRP_HELLO_INTERVAL_DEFAULT;
++
++  SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait);
++  IF_DEF_PARAMS (ifp)->v_wait = (u_int16_t) EIGRP_HOLD_INTERVAL_DEFAULT;
++
++  SET_IF_PARAM (IF_DEF_PARAMS (ifp), bandwidth);
++  IF_DEF_PARAMS (ifp)->bandwidth = (u_int32_t) EIGRP_BANDWIDTH_DEFAULT;
++
++  SET_IF_PARAM (IF_DEF_PARAMS (ifp), delay);
++  IF_DEF_PARAMS (ifp)->delay = (u_int32_t) EIGRP_DELAY_DEFAULT;
++
++  SET_IF_PARAM (IF_DEF_PARAMS (ifp), reliability);
++  IF_DEF_PARAMS (ifp)->reliability = (u_char) EIGRP_RELIABILITY_DEFAULT;
++
++  SET_IF_PARAM (IF_DEF_PARAMS (ifp), load);
++  IF_DEF_PARAMS (ifp)->load = (u_char) EIGRP_LOAD_DEFAULT;
++
++  SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type);
++  IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_NONE;
++
++  SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_keychain);
++  IF_DEF_PARAMS (ifp)->auth_keychain= NULL;
++
++  return rc;
++}
++
++struct eigrp_if_params *
++eigrp_new_if_params (void)
++{
++  struct eigrp_if_params *eip;
++
++  eip = XCALLOC (MTYPE_EIGRP_IF_PARAMS, sizeof (struct eigrp_if_params));
++  if (!eip)
++    return NULL;
++
++  UNSET_IF_PARAM (eip, passive_interface);
++  UNSET_IF_PARAM (eip, v_hello);
++  UNSET_IF_PARAM (eip, v_wait);
++  UNSET_IF_PARAM (eip, bandwidth);
++  UNSET_IF_PARAM (eip, delay);
++  UNSET_IF_PARAM (eip, reliability);
++  UNSET_IF_PARAM (eip, load);
++  UNSET_IF_PARAM (eip, auth_keychain);
++  UNSET_IF_PARAM (eip, auth_type);
++
++
++  return eip;
++}
++
++void
++eigrp_del_if_params (struct eigrp_if_params *eip)
++{
++  if(eip->auth_keychain)
++    free(eip->auth_keychain);
++
++  XFREE (MTYPE_EIGRP_IF_PARAMS, eip);
++}
++
++struct eigrp_if_params *
++eigrp_lookup_if_params (struct interface *ifp, struct in_addr addr)
++{
++  struct prefix_ipv4 p;
++  struct route_node *rn;
++
++  p.family = AF_INET;
++  p.prefixlen = IPV4_MAX_PREFIXLEN;
++  p.prefix = addr;
++
++  rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*) &p);
++
++  if (rn)
++    {
++      route_unlock_node (rn);
++      return rn->info;
++    }
++
++  return NULL;
++}
++
++int
++eigrp_if_up (struct eigrp_interface *ei)
++{
++  struct eigrp_prefix_entry *pe;
++  struct eigrp_neighbor_entry *ne;
++  struct eigrp_metrics metric;
++  struct eigrp_interface *ei2;
++  struct listnode *node, *nnode;
++  struct eigrp *eigrp = eigrp_lookup ();
++
++  if (ei == NULL)
++    return 0;
++
++  if (eigrp != NULL)
++    eigrp_adjust_sndbuflen (eigrp, ei->ifp->mtu);
++  else
++    zlog_warn ("%s: eigrp_lookup () returned NULL", __func__);
++  eigrp_if_stream_set (ei);
++
++  /* Set multicast memberships appropriately for new state. */
++  eigrp_if_set_multicast (ei);
++
++  thread_add_event (master, eigrp_hello_timer, ei, (1));
++
++  /*Prepare metrics*/
++  metric.bandwith = eigrp_bandwidth_to_scaled (EIGRP_IF_PARAM (ei,bandwidth));
++  metric.delay = eigrp_delay_to_scaled (EIGRP_IF_PARAM (ei,delay));
++  metric.load = EIGRP_IF_PARAM (ei,load);
++  metric.reliability = EIGRP_IF_PARAM (ei,reliability);
++  metric.mtu[0] = 0xDC;
++  metric.mtu[1] = 0x05;
++  metric.mtu[2] = 0x00;
++  metric.hop_count = 0;
++  metric.flags = 0;
++  metric.tag = 0;
++
++  /*Add connected entry to topology table*/
++
++  struct prefix_ipv4 *dest_addr = prefix_ipv4_new ();
++
++  dest_addr->family = AF_INET;
++  dest_addr->prefix = ei->connected->address->u.prefix4;
++  dest_addr->prefixlen = ei->connected->address->prefixlen;
++  apply_mask_ipv4 (dest_addr);
++  pe = eigrp_topology_table_lookup_ipv4 (eigrp->topology_table, dest_addr);
++
++  if (pe == NULL)
++    {
++      pe = eigrp_prefix_entry_new ();
++      pe->serno = eigrp->serno;
++      pe->destination_ipv4 = dest_addr;
++      pe->af = AF_INET;
++      pe->nt = EIGRP_TOPOLOGY_TYPE_CONNECTED;
++
++      pe->state = EIGRP_FSM_STATE_PASSIVE;
++      pe->fdistance = eigrp_calculate_metrics (eigrp, &metric);
++      pe->req_action |= EIGRP_FSM_NEED_UPDATE;
++      eigrp_prefix_entry_add (eigrp->topology_table, pe);
++      listnode_add(eigrp->topology_changes_internalIPV4, pe);
++    }
++  ne = eigrp_neighbor_entry_new ();
++  ne->ei = ei;
++  ne->reported_metric = metric;
++  ne->total_metric = metric;
++  ne->distance = eigrp_calculate_metrics (eigrp, &metric);
++  ne->reported_distance = 0;
++  ne->prefix = pe;
++  ne->adv_router = eigrp->neighbor_self;
++  ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
++  eigrp_neighbor_entry_add (pe, ne);
++
++  for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei2))
++    {
++      if (ei2->nbrs->count != 0)
++        {
++          eigrp_update_send (ei2);
++        }
++    }
++
++  pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
++  listnode_delete(eigrp->topology_changes_internalIPV4, pe);
++
++  return 1;
++}
++
++int
++eigrp_if_down (struct eigrp_interface *ei)
++{
++
++  struct listnode *node, *nnode, *node2, *nnode2;
++  struct eigrp_neighbor *nbr;
++
++  if (ei == NULL)
++    return 0;
++
++  /* Shutdown packet reception and sending */
++  if(ei->t_hello)
++    THREAD_OFF (ei->t_hello);
++
++  eigrp_if_stream_unset (ei);
++
++  /*Set infinite metrics to routes learned by this interface and start query process*/
++  for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
++    {
++      eigrp_nbr_delete(nbr);
++    }
++
++  return 1;
++}
++
++void
++eigrp_if_stream_set (struct eigrp_interface *ei)
++{
++  /* set output fifo queue. */
++  if (ei->obuf == NULL)
++    ei->obuf = eigrp_fifo_new ();
++}
++
++void
++eigrp_if_stream_unset (struct eigrp_interface *ei)
++{
++  struct eigrp *eigrp = ei->eigrp;
++
++  if (ei->obuf)
++    {
++      eigrp_fifo_free (ei->obuf);
++      ei->obuf = NULL;
++
++      if (ei->on_write_q)
++        {
++          listnode_delete (eigrp->oi_write_q, ei);
++          if (list_isempty (eigrp->oi_write_q))
++            thread_cancel (eigrp->t_write);
++          ei->on_write_q = 0;
++        }
++    }
++}
++
++void
++eigrp_if_set_multicast (struct eigrp_interface *ei)
++{
++  if ((EIGRP_IF_PASSIVE_STATUS (ei) == EIGRP_IF_ACTIVE))
++    {
++      /* The interface should belong to the EIGRP-all-routers group. */
++      if (!EI_MEMBER_CHECK (ei, MEMBER_ALLROUTERS)
++          && (eigrp_if_add_allspfrouters (ei->eigrp, ei->address,
++              ei->ifp->ifindex) >= 0))
++        /* Set the flag only if the system call to join succeeded. */
++        EI_MEMBER_JOINED (ei, MEMBER_ALLROUTERS);
++    }
++  else
++    {
++      /* The interface should NOT belong to the EIGRP-all-routers group. */
++      if (EI_MEMBER_CHECK (ei, MEMBER_ALLROUTERS))
++        {
++          /* Only actually drop if this is the last reference */
++          if (EI_MEMBER_COUNT (ei, MEMBER_ALLROUTERS) == 1)
++            eigrp_if_drop_allspfrouters (ei->eigrp, ei->address,
++                ei->ifp->ifindex);
++          /* Unset the flag regardless of whether the system call to leave
++           the group succeeded, since it's much safer to assume that
++           we are not a member. */
++          EI_MEMBER_LEFT (ei, MEMBER_ALLROUTERS);
++        }
++    }
++}
++
++u_char
++eigrp_default_iftype (struct interface *ifp)
++{
++  if (if_is_pointopoint (ifp))
++    return EIGRP_IFTYPE_POINTOPOINT;
++  else if (if_is_loopback (ifp))
++    return EIGRP_IFTYPE_LOOPBACK;
++  else
++    return EIGRP_IFTYPE_BROADCAST;
++}
++
++void
++eigrp_if_free (struct eigrp_interface *ei, int source)
++{
++
++  if (source == INTERFACE_DOWN_BY_VTY)
++    {
++      THREAD_OFF (ei->t_hello);
++      eigrp_hello_send(ei,EIGRP_HELLO_GRACEFUL_SHUTDOWN);
++    }
++
++  eigrp_if_down (ei);
++
++  list_delete (ei->nbrs);
++  eigrp_delete_from_if (ei->ifp, ei);
++  listnode_delete (ei->eigrp->eiflist, ei);
++
++  thread_cancel_event (master, ei);
++
++  memset (ei, 0, sizeof (*ei));
++  XFREE (MTYPE_EIGRP_IF, ei);
++}
++
++static void
++eigrp_delete_from_if (struct interface *ifp, struct eigrp_interface *ei)
++{
++  struct route_node *rn;
++  struct prefix p;
++
++  p = *ei->address;
++  p.prefixlen = IPV4_MAX_PREFIXLEN;
++
++  rn = route_node_lookup (IF_OIFS (ei->ifp), &p);
++  assert (rn);
++  assert (rn->info);
++  rn->info = NULL;
++  route_unlock_node (rn);
++  route_unlock_node (rn);
++}
++
++/* Simulate down/up on the interface.  This is needed, for example, when
++ the MTU changes. */
++void
++eigrp_if_reset (struct interface *ifp)
++{
++  struct route_node *rn;
++
++  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
++    {
++      struct eigrp_interface *ei;
++
++      if ((ei = rn->info) == NULL)
++        continue;
++
++      eigrp_if_down (ei);
++      eigrp_if_up (ei);
++    }
++}
++
++struct eigrp_interface *
++eigrp_if_lookup_by_local_addr (struct eigrp *eigrp, struct interface *ifp,
++    struct in_addr address)
++{
++  struct listnode *node;
++  struct eigrp_interface *ei;
++
++  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
++    {
++      if (ifp && ei->ifp != ifp)
++        continue;
++
++      if (IPV4_ADDR_SAME (&address, &ei->address->u.prefix4))
++        return ei;
++    }
++
++  return NULL;
++}
++
++/* determine receiving interface by ifp and source address */
++struct eigrp_interface *
++eigrp_if_lookup_recv_if (struct eigrp *eigrp, struct in_addr src,
++    struct interface *ifp)
++{
++  struct route_node *rn;
++  struct prefix_ipv4 addr;
++  struct eigrp_interface *ei, *match;
++
++  addr.family = AF_INET;
++  addr.prefix = src;
++  addr.prefixlen = IPV4_MAX_BITLEN;
++
++  match = NULL;
++
++  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
++    {
++      ei = rn->info;
++
++      if (!ei) /* oi can be NULL for PtP aliases */
++        continue;
++
++      if (if_is_loopback (ei->ifp))
++        continue;
++
++      if (prefix_match (CONNECTED_PREFIX (ei->connected),
++          (struct prefix *) &addr))
++        {
++          if ((match == NULL)
++              || (match->address->prefixlen < ei->address->prefixlen))
++            match = ei;
++        }
++    }
++
++  return match;
++}
++
++u_int32_t
++eigrp_bandwidth_to_scaled (u_int32_t bandwidth)
++{
++  u_int64_t temp_bandwidth = (256ull * 10000000) / bandwidth;
++
++  temp_bandwidth =
++      temp_bandwidth < EIGRP_MAX_METRIC ? temp_bandwidth : EIGRP_MAX_METRIC;
++
++  return (u_int32_t) temp_bandwidth;
++
++}
++
++u_int32_t
++eigrp_scaled_to_bandwidth (u_int32_t scaled)
++{
++  u_int64_t temp_scaled = scaled * (256ull * 10000000);
++
++  temp_scaled =
++      temp_scaled < EIGRP_MAX_METRIC ? temp_scaled : EIGRP_MAX_METRIC;
++
++  return (u_int32_t) temp_scaled;
++}
++
++u_int32_t
++eigrp_delay_to_scaled (u_int32_t delay)
++{
++  return delay * 256;
++}
++
++u_int32_t
++eigrp_scaled_to_delay (u_int32_t scaled)
++{
++  return scaled / 256;
++}
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_interface.h eigrp/eigrpd/eigrp_interface.h
+--- a/eigrpd/eigrp_interface.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_interface.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,68 @@
++/*
++ * EIGRP Interface Functions.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRP_INTERFACE_H_
++#define _ZEBRA_EIGRP_INTERFACE_H_
++
++/*Prototypes*/
++extern void eigrp_if_init (void);
++extern int eigrp_if_new_hook (struct interface *);
++extern int eigrp_if_delete_hook (struct interface *);
++
++extern void eigrp_del_if_params (struct eigrp_if_params *);
++extern struct eigrp_if_params *eigrp_new_if_params (void);
++extern struct eigrp_interface * eigrp_if_new (struct eigrp *, struct interface *,
++                                              struct prefix *);
++extern struct eigrp_interface * eigrp_if_table_lookup (struct interface *,
++                                                       struct prefix *);
++extern struct eigrp_if_params *eigrp_lookup_if_params (struct interface *,
++                                                struct in_addr);
++extern int eigrp_if_up (struct eigrp_interface *);
++extern void eigrp_if_stream_set (struct eigrp_interface *);
++extern void eigrp_if_set_multicast (struct eigrp_interface *);
++extern u_char eigrp_default_iftype (struct interface *);
++extern void eigrp_if_free (struct eigrp_interface *, int);
++extern int eigrp_if_down (struct eigrp_interface *);
++extern void eigrp_if_stream_unset (struct eigrp_interface *);
++
++extern struct eigrp_interface *eigrp_if_lookup_by_local_addr (struct eigrp *,
++                                                              struct interface *,
++                                                              struct in_addr);
++struct eigrp_interface * eigrp_if_lookup_recv_if (struct eigrp *, struct in_addr,
++                                                  struct interface *);
++
++/* Simulate down/up on the interface. */
++extern void eigrp_if_reset (struct interface *);
++
++extern u_int32_t eigrp_bandwidth_to_scaled (u_int32_t);
++extern u_int32_t eigrp_scaled_to_bandwidth (u_int32_t);
++extern u_int32_t eigrp_delay_to_scaled (u_int32_t);
++extern u_int32_t eigrp_scaled_to_delay (u_int32_t);
++
++
++#endif /* ZEBRA_EIGRP_INTERFACE_H_ */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_macros.h eigrp/eigrpd/eigrp_macros.h
+--- a/eigrpd/eigrp_macros.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_macros.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,85 @@
++/*
++ * EIGRP Macros Definition.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRP_MACROS_H_
++#define _ZEBRA_EIGRP_MACROS_H_
++
++#define DECLARE_IF_PARAM(T, P) T P; u_char P##__config:1
++#define IF_EIGRP_IF_INFO(I) ((struct eigrp_if_info *)((I)->info))
++#define IF_OIFS(I)  (IF_EIGRP_IF_INFO (I)->eifs)
++#define IF_OIFS_PARAMS(I) (IF_EIGRP_IF_INFO (I)->params)
++
++#define SET_IF_PARAM(S, P) ((S)->P##__config) = 1
++#define IF_DEF_PARAMS(I) (IF_EIGRP_IF_INFO (I)->def_params)
++
++#define UNSET_IF_PARAM(S, P) ((S)->P##__config) = 0
++
++#define EIGRP_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config)
++#define EIGRP_IF_PARAM(O, P) \
++        (EIGRP_IF_PARAM_CONFIGURED ((O)->params, P)?\
++                        (O)->params->P:IF_DEF_PARAMS((O)->ifp)->P)
++
++#define EIGRP_IF_PASSIVE_STATUS(O) \
++       (EIGRP_IF_PARAM_CONFIGURED((O)->params, passive_interface) ? \
++         (O)->params->passive_interface : \
++         (EIGRP_IF_PARAM_CONFIGURED(IF_DEF_PARAMS((O)->ifp), passive_interface) ? \
++           IF_DEF_PARAMS((O)->ifp)->passive_interface : \
++           (O)->eigrp->passive_interface_default))
++
++//------------------------------------------------------------------------------------------------------------------------------------
++
++#define EIGRP_IF_STRING_MAXLEN  40
++#define IF_NAME(I)      eigrp_if_name_string ((I))
++
++//------------------------------------------------------------------------------------------------------------------------------------
++
++/*Macros for EIGRP interface multicast membership*/
++#define EI_MEMBER_FLAG(M) (1 << (M))
++#define EI_MEMBER_COUNT(O,M) (IF_EIGRP_IF_INFO(ei->ifp)->membership_counts[(M)])
++#define EI_MEMBER_CHECK(O,M) \
++    (CHECK_FLAG((O)->multicast_memberships, EI_MEMBER_FLAG(M)))
++#define EI_MEMBER_JOINED(O,M) \
++  do { \
++    SET_FLAG ((O)->multicast_memberships, EI_MEMBER_FLAG(M)); \
++    IF_EIGRP_IF_INFO((O)->ifp)->membership_counts[(M)]++; \
++  } while (0)
++#define EI_MEMBER_LEFT(O,M) \
++  do { \
++    UNSET_FLAG ((O)->multicast_memberships, EI_MEMBER_FLAG(M)); \
++    IF_EIGRP_IF_INFO((O)->ifp)->membership_counts[(M)]--; \
++  } while (0)
++
++//-----------------------------------------------------------------------------------------------------------------------------------
++/* Topology Macros */
++
++
++/* FSM macros*/
++#define EIGRP_FSM_EVENT_SCHEDULE(I,E) \
++      thread_add_event (master, eigrp_fsm_event, (I), (E))
++
++#endif /* _ZEBRA_EIGRP_MACROS_H_ */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_main.c eigrp/eigrpd/eigrp_main.c
+--- a/eigrpd/eigrp_main.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_main.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,347 @@
++/*
++ * EIGRP Main Routine.
++ * Copyright (C) 2013-2015
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *   Frantisek Gazo
++ *   Tomas Hvorkovy
++ *   Martin Kontsek
++ *   Lukas Koribsky
++ *
++ * 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.
++ */
++#include <zebra.h>
++
++#include <lib/version.h>
++#include "getopt.h"
++#include "thread.h"
++#include "prefix.h"
++#include "linklist.h"
++#include "if.h"
++#include "vector.h"
++#include "vty.h"
++#include "command.h"
++#include "filter.h"
++#include "plist.h"
++#include "stream.h"
++#include "log.h"
++#include "memory.h"
++#include "privs.h"
++#include "sigevent.h"
++#include "zclient.h"
++#include "keychain.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_network.h"
++#include "eigrpd/eigrp_snmp.h"
++#include "eigrpd/eigrp_filter.h"
++
++/* eigprd privileges */
++zebra_capabilities_t _caps_p [] = 
++{
++  ZCAP_NET_RAW,
++  ZCAP_BIND,
++  ZCAP_NET_ADMIN,
++};
++
++struct zebra_privs_t eigrpd_privs =
++{
++#if defined (QUAGGA_USER) && defined (QUAGGA_GROUP)
++  .user = QUAGGA_USER,
++  .group = QUAGGA_GROUP,
++#endif
++#if defined (VTY_GROUP)
++  .vty_group = VTY_GROUP,
++#endif
++  .caps_p = _caps_p,
++  .cap_num_p = array_size (_caps_p),
++  .cap_num_i = 0
++};
++
++/* EIGRPd options. */
++struct option longopts[] =
++{
++  { "daemon",      no_argument,       NULL, 'd'},
++  { "config_file", required_argument, NULL, 'f'},
++  { "pid_file",    required_argument, NULL, 'i'},
++  { "socket",      required_argument, NULL, 'z'},
++  { "dryrun",      no_argument,       NULL, 'C'},
++  { "help",        no_argument,       NULL, 'h'},
++  { "vty_addr",    required_argument, NULL, 'A'},
++  { "vty_port",    required_argument, NULL, 'P'},
++  { "user",        required_argument, NULL, 'u'},
++  { "group",       required_argument, NULL, 'g'},
++  { "version",     no_argument,       NULL, 'v'},
++  { 0 }
++};
++
++/* Help information display. */
++static void __attribute__ ((noreturn))
++usage (char *progname, int status)
++{
++  if (status != 0)
++    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
++  else
++    {
++      printf ("Usage : %s [OPTION...]\n\
++Daemon which manages EIGRP.\n\n\
++-d, --daemon       Runs in daemon mode\n\
++-f, --config_file  Set configuration file name\n\
++-i, --pid_file     Set process identifier file name\n\
++-z, --socket       Set path of zebra socket\n\
++-A, --vty_addr     Set vty's bind address\n\
++-P, --vty_port     Set vty's port number\n\
++-u, --user         User to run as\n\
++-g, --group        Group to run as\n\
++-v, --version      Print program version\n\
++-C, --dryrun       Check configuration for validity and exit\n\
++-h, --help         Display this help and exit\n\
++\n\
++Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
++    }
++  exit (status);
++}
++
++/* Master of threads. */
++struct thread_master *master;
++
++/* Process ID saved for use by init system */
++const char *pid_file = PATH_EIGRPD_PID;
++
++/* Configuration filename and directory. */
++char *config_default = SYSCONFDIR EIGRP_DEFAULT_CONFIG;
++
++/* SIGHUP handler. */
++static void 
++sighup (void)
++{
++  zlog (NULL, LOG_INFO, "SIGHUP received");
++}
++
++/* SIGINT / SIGTERM handler. */
++static void
++sigint (void)
++{
++  zlog_notice ("Terminating on signal");
++  eigrp_terminate ();
++}
++
++/* SIGUSR1 handler. */
++static void
++sigusr1 (void)
++{
++  zlog_rotate (NULL);
++}
++
++struct quagga_signal_t eigrp_signals[] =
++{
++  {
++    .signal = SIGHUP,
++    .handler = &sighup,
++  },
++  {
++    .signal = SIGUSR1,
++    .handler = &sigusr1,
++  },  
++  {
++    .signal = SIGINT,
++    .handler = &sigint,
++  },
++  {
++    .signal = SIGTERM,
++    .handler = &sigint,
++  },
++};
++
++/* EIGRPd main routine. */
++int
++main (int argc, char **argv)
++{
++  char *p;
++  char *vty_addr = NULL;
++  int vty_port = EIGRP_VTY_PORT;
++  int daemon_mode = 0;
++  char *config_file = NULL;
++  char *progname;
++  struct thread thread;
++  int dryrun = 0;
++  
++  /* Set umask before anything for security */
++  umask (0027);
++  
++  /* get program name */
++  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
++  
++  while (1)
++    {
++      int opt;
++
++      opt = getopt_long (argc, argv, "df:i:z:hA:P:u:g:vC", longopts, 0);
++
++      if (opt == EOF)
++        break;
++
++      switch (opt)
++        {
++        case 0:
++          break;
++        case 'd':
++          daemon_mode = 1;
++          break;
++        case 'f':
++          config_file = optarg;
++          break;
++        case 'A':
++          vty_addr = optarg;
++          break;
++        case 'i':
++          pid_file = optarg;
++          break;
++        case 'z':
++          zclient_serv_path_set (optarg);
++          break;
++        case 'P':
++          /* Deal with atoi() returning 0 on failure, and eigrpd not
++             listening on eigrpd port... */
++          if (strcmp(optarg, "0") == 0)
++            {
++              vty_port = 0;
++              break;
++            }
++          vty_port = atoi (optarg);
++          if (vty_port <= 0 || vty_port > 0xffff)
++            vty_port = EIGRP_VTY_PORT;
++          break;
++        case 'u':
++          eigrpd_privs.user = optarg;
++          break;
++        case 'g':
++          eigrpd_privs.group = optarg;
++          break;
++        case 'v':
++          print_version (progname);
++          exit (0);
++          break;
++        case 'C':
++          dryrun = 1;
++          break;
++        case 'h':
++          usage (progname, 0);
++          break;
++        default:
++          usage (progname, 1);
++          break;
++        }
++    }
++
++    /* Invoked by a priviledged user? -- endo. */
++  if (geteuid () != 0)
++    {
++      errno = EPERM;
++      perror (progname);
++      exit (1);
++    }
++  
++  zlog_default = openzlog (progname, ZLOG_EIGRP,
++			   LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
++  /* EIGRP master init. */
++  eigrp_master_init ();
++  
++  /* Initializations. */
++  master = eigrp_om->master;
++  
++  /* Library inits. */
++  zprivs_init (&eigrpd_privs);
++  signal_init (master, array_size (eigrp_signals), eigrp_signals);
++  cmd_init (1);
++  vty_init (master);
++  memory_init ();
++
++  /*EIGRPd init*/
++  eigrp_if_init ();
++  eigrp_zebra_init ();
++  eigrp_debug_init ();
++
++  /* Get configuration file. */
++  /* EIGRP VTY inits */
++  eigrp_vty_init ();
++  keychain_init();
++  eigrp_vty_show_init ();
++  eigrp_vty_if_init ();
++
++#ifdef HAVE_SNMP
++  eigrp_snmp_init ();
++#endif /* HAVE_SNMP */
++
++  /* Access list install. */
++  access_list_init ();
++  access_list_add_hook (eigrp_distribute_update_all_wrapper);
++  access_list_delete_hook (eigrp_distribute_update_all_wrapper);
++
++  /* Prefix list initialize.*/
++  prefix_list_init ();
++  prefix_list_add_hook (eigrp_distribute_update_all);
++  prefix_list_delete_hook (eigrp_distribute_update_all);
++
++  /* Distribute list install. */
++  distribute_list_init (EIGRP_NODE);
++  distribute_list_add_hook (eigrp_distribute_update);
++  distribute_list_delete_hook (eigrp_distribute_update);
++
++  vty_read_config (config_file, config_default);
++
++
++  /* Start execution only if not in dry-run mode */
++  if (dryrun)
++    return (0);
++  
++  /* Change to the daemon program. */
++  if (daemon_mode && daemon (0, 0) < 0)
++    {
++      zlog_err ("EIGRPd daemon failed: %s", strerror (errno));
++      exit (1);
++    }
++
++  /* Process id file create. */
++  pid_output (pid_file);
++
++  /* Create VTY socket */
++  vty_serv_sock (vty_addr, vty_port, EIGRP_VTYSH_PATH);
++
++//  /* Print banner. */
++  zlog_notice ("EIGRPd %s starting: vty@%d", QUAGGA_VERSION, vty_port);
++
++  /* Fetch next active thread. */
++  while (thread_fetch (master, &thread))
++    thread_call (&thread);
++
++  /* Not reached. */
++  return (0);
++  
++}
+diff -Nur quagga-0.99.22.4/eigrpd/EIGRP-MIB.txt eigrp/eigrpd/EIGRP-MIB.txt
+--- a/eigrpd/EIGRP-MIB.txt	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/EIGRP-MIB.txt	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,1321 @@
++CISCO-EIGRP-MIB DEFINITIONS ::= BEGIN
++
++    IMPORTS
++        MODULE-IDENTITY,
++        OBJECT-TYPE,
++        NOTIFICATION-TYPE,
++        Unsigned32,
++        Gauge32,
++        Counter32,
++        Counter64
++            FROM SNMPv2-SMI
++        TruthValue,
++        TEXTUAL-CONVENTION
++            FROM SNMPv2-TC
++        SnmpAdminString
++            FROM SNMP-FRAMEWORK-MIB
++        MODULE-COMPLIANCE,
++        OBJECT-GROUP,
++        NOTIFICATION-GROUP
++            FROM SNMPv2-CONF
++        ciscoMgmt
++            FROM CISCO-SMI
++        InterfaceIndexOrZero,
++        ifIndex
++            FROM IF-MIB
++        InetAddressType,
++        InetAddress,
++        InetAddressPrefixLength
++            FROM INET-ADDRESS-MIB;
++
++ciscoEigrpMIB MODULE-IDENTITY
++    LAST-UPDATED        "200411160000Z"
++    ORGANIZATION        "Cisco Systems, Inc."
++    CONTACT-INFO        "Cisco Systems
++                         Customer Service
++
++                         Postal: 170 W Tasman Drive
++                                 San Jose, CA  95134
++                                 USA
++
++                         Tel: +1 800 553-NETS
++
++                         E-mail: cs-eigrp at cisco.com"
++    DESCRIPTION
++        "Enhanced Interior Gateway Protocol (EIGRP) is a Cisco
++         proprietary distance vector routing protocol.   It is based on
++         the Diffusing Update Algorithm (DUAL), which is a method of
++         finding loop-free paths through a network.   Directly
++         connected routers running EIGRP form neighbor adjacencies in
++         order to propagate best-path and alternate-path routing
++         information for configured and learned routes.
++
++         The tables defined within the MIB are closely aligned with how
++         the router command-line interface for EIGRP displays
++         information on EIGRP configurations, i.e., the topology table
++         contains objects associated with the EIGRP topology commands,
++         and the peer table contains objects associated withe EIGRP
++         neighbor commands, etc.
++
++         There are five main tables within this mib:
++
++            EIGRP VPN table
++               Contains information regarding which virtual private
++               networks (VPN) are configured with EIGRP.
++
++            EIGRP traffic statistics table
++               Contains counter & statistcs regarding specific types of
++               EIGRP packets sent and related collective information
++               per VPN and per autonomous system (AS).
++
++            EIGRP topology table
++               Contains information regarding EIGRP routes received in
++               updates and originated locally.   EIGRP sends and
++               receives routing updates from adjacent routers running
++               EIGRP with which it formed a peer relationship.
++
++            EIGRP peer (neighbor) table
++               Contains information about neighbor EIGRP routers with
++               which peer adjacencies have been established.   EIGRP
++               uses a Hello protocol to form neighbor relationships
++               with directly connected routers also running EIGRP.
++
++            EIGRP interfaces table
++               Contains information and statistics on each of the
++               interfaces on the router over which EIGRP has been
++               configured to run."
++
++
++    REVISION    "200411160000Z"
++    DESCRIPTION
++                "Initial version of the MIB module."
++    ::= { ciscoMgmt 449 }
++
++--
++-- Textual Conventions
++--
++
++    EigrpUpTimeString ::= TEXTUAL-CONVENTION
++        DISPLAY-HINT "8a"
++        STATUS       current
++        DESCRIPTION
++            "Specifies a timer value in days, hours, minutes,
++             and seconds in ASCII format.
++
++             If the up time is less than 24 hours, the number
++             of days will not be reflected and the string will
++             be formatted like this: 'hh:mm:ss', reflecting
++             hours, minutes, and seconds.
++
++             If the up time is greater than 24 hours, EIGRP is
++             less precise and the minutes and seconds are not
++             reflected.  Instead only the days and hours are shown
++             and the string will be formatted like this: 'xxxdxxh'." 
++        SYNTAX       OCTET STRING (SIZE (0..8))
++
++    EigrpVersionString ::= TEXTUAL-CONVENTION 
++        DISPLAY-HINT "1d.1d/1d.1d"
++        STATUS     current
++        DESCRIPTION
++            "Specifies an ASCII string representing the IOS major
++             and minor version followed by the EIGRP major and minor
++             version."
++        SYNTAX       OCTET STRING (SIZE (0..9))
++
++--
++-- Objects
++--
++
++    cEigrpMIBNotifications OBJECT IDENTIFIER ::= { ciscoEigrpMIB 0 }
++    cEigrpMIBObjects       OBJECT IDENTIFIER ::= { ciscoEigrpMIB 1 }
++    cEigrpMIBConformance   OBJECT IDENTIFIER ::= { ciscoEigrpMIB 2 }
++    cEigrpVpnInfo          OBJECT IDENTIFIER ::= { cEigrpMIBObjects 1 }
++    cEigrpAsInfo           OBJECT IDENTIFIER ::= { cEigrpMIBObjects 2 }
++    cEigrpTopologyInfo     OBJECT IDENTIFIER ::= { cEigrpMIBObjects 3 }
++    cEigrpPeerInfo         OBJECT IDENTIFIER ::= { cEigrpMIBObjects 4 }
++    cEigrpInterfaceInfo    OBJECT IDENTIFIER ::= { cEigrpMIBObjects 5 }
++
++    -- EIGRP VPN Base Table definition
++
++    cEigrpVpnTable OBJECT-TYPE
++        SYNTAX     SEQUENCE OF CEigrpVpnEntry
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "This table contains information on those VPN's configured
++             to run EIGRP.  The VPN creation on a router is independent
++             of the routing protocol to be used over it.   A VPN is
++             given a name and has a dedicated routing table associated
++             with it.  This routing table is identified internally
++             by a unique integer value."
++        ::= { cEigrpVpnInfo 1 }
++
++    cEigrpVpnEntry OBJECT-TYPE
++        SYNTAX     CEigrpVpnEntry
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "Information relating to a single VPN which is configured
++             to run EIGRP."
++        INDEX { cEigrpVpnId }
++        ::= { cEigrpVpnTable 1 }
++
++   CEigrpVpnEntry ::=
++       SEQUENCE {
++           cEigrpVpnId  Unsigned32,
++           cEigrpVpnName SnmpAdminString
++       }
++
++    cEigrpVpnId  OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "The unique VPN identifier.  This is a unique integer
++             relative to all other VPN's defined on the router.  It
++             also identifies internally the routing table instance."
++        ::= { cEigrpVpnEntry 1 }
++
++    cEigrpVpnName  OBJECT-TYPE
++        SYNTAX     SnmpAdminString
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The name given to the VPN."
++        ::= { cEigrpVpnEntry 2 }
++
++    --  EIGRP Traffic Stats table definition
++
++    cEigrpTraffStatsTable OBJECT-TYPE
++        SYNTAX     SEQUENCE OF CEigrpTraffStatsEntry
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "Table of EIGRP traffic statistics and information
++             associated with all EIGRP autonomous systems."
++        ::= { cEigrpAsInfo 1 }
++
++    cEigrpTraffStatsEntry OBJECT-TYPE
++        SYNTAX     CEigrpTraffStatsEntry
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "The set of statistics and information for a single EIGRP
++             Autonomous System."
++        INDEX { cEigrpVpnId, cEigrpAsNumber }
++        ::= { cEigrpTraffStatsTable 1 }
++
++    CEigrpTraffStatsEntry ::=
++        SEQUENCE {
++            cEigrpAsNumber        Unsigned32,
++            cEigrpNbrCount        Unsigned32,
++            cEigrpHellosSent      Counter32,
++            cEigrpHellosRcvd      Counter32,
++            cEigrpUpdatesSent     Counter32,
++            cEigrpUpdatesRcvd     Counter32,
++            cEigrpQueriesSent     Counter32,
++            cEigrpQueriesRcvd     Counter32,
++            cEigrpRepliesSent     Counter32,
++            cEigrpRepliesRcvd     Counter32,
++            cEigrpAcksSent        Counter32,
++            cEigrpAcksRcvd        Counter32,
++            cEigrpInputQHighMark  Unsigned32,
++            cEigrpInputQDrops     Counter32,
++            cEigrpSiaQueriesSent  Counter32,
++            cEigrpSiaQueriesRcvd  Counter32,
++            cEigrpAsRouterIdType  InetAddressType,
++            cEigrpAsRouterId      InetAddress,
++            cEigrpTopoRoutes      Counter32,
++            cEigrpHeadSerial      Counter64,
++            cEigrpNextSerial      Counter64,
++            cEigrpXmitPendReplies Unsigned32,
++            cEigrpXmitDummies     Unsigned32
++        }
++
++    cEigrpAsNumber  OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "The Autonomous System number which is unique integer
++             per VPN."
++        ::= { cEigrpTraffStatsEntry 1 }
++
++    cEigrpNbrCount  OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number of live EIGRP neighbors formed on all
++           interfaces whose IP addresses fall under networks configured
++           in the EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 2 }
++
++    cEigrpHellosSent  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number Hello packets that have been sent to all
++           EIGRP neighbors formed on all interfaces whose IP addresses
++           fall under networks configured for the EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 3 }
++
++    cEigrpHellosRcvd  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number Hello packets that have been received
++           from all EIGRP neighbors formed on all interfaces whose IP
++           addresses fall under networks configured for the
++           EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 4 }
++
++    cEigrpUpdatesSent  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number routing update packets that have been
++           sent to all EIGRP neighbors formed on all interfaces whose
++           IP addresses fall under networks configured for the
++           EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 5 }
++
++    cEigrpUpdatesRcvd  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number routing update packets that have been
++           received from all EIGRP neighbors formed on all interfaces
++           whose IP addresses fall under networks configured for the
++           EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 6 }
++
++    cEigrpQueriesSent  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number alternate route query packets that have
++           been sent to all EIGRP neighbors formed on all interfaces
++           whose IP addresses fall under networks configured for the
++           EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 7 }
++
++    cEigrpQueriesRcvd  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number alternate route query packets that
++           have been received from all EIGRP neighbors formed on
++           all interfaces whose IP addresses fall under networks
++           configured for the EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 8 }
++
++    cEigrpRepliesSent  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number query reply packets that have been sent
++           to all EIGRP neighbors formed on all interfaces whose IP
++           addresses fall under networks configured for the
++           EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 9 }
++
++    cEigrpRepliesRcvd  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number query reply packets that have been
++           received from all EIGRP neighbors formed on all interfaces
++           whose IP addresses fall under networks configured for the
++           EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 10 }
++
++    cEigrpAcksSent  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number packet acknowledgements that have been
++           sent to all EIGRP neighbors formed on all interfaces whose
++           IP addresses fall under networks configured for the
++           EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 11 }
++
++    cEigrpAcksRcvd  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number packet acknowledgements that have been
++           received from all EIGRP neighbors formed on all interfaces
++           whose IP addresses fall under networks configured for the
++           EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 12 }
++
++    cEigrpInputQHighMark  OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The highest number of EIGRP packets in the input queue
++             waiting to be processed internally addressed to this
++             AS."
++        ::= { cEigrpTraffStatsEntry 13 }
++
++    cEigrpInputQDrops  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The number of EIGRP packets dropped from the input
++           queue due to it being full within the AS."
++        ::= { cEigrpTraffStatsEntry 14 }
++
++    cEigrpSiaQueriesSent  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number of Stuck-In-Active (SIA) query packets
++           sent to all EIGRP neighbors formed on all interfaces whose
++           IP addresses fall under networks configured for the
++           EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 15 }
++
++    cEigrpSiaQueriesRcvd  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number of Stuck-In-Active (SIA) query packets
++           received from all EIGRP neighbors formed on all interfaces
++           whose IP addresses fall under networks configured for the
++           EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 16 }
++
++    cEigrpAsRouterIdType  OBJECT-TYPE
++        SYNTAX     InetAddressType
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The format of the router-id configured or automatically
++           selected for the EIGRP AS."
++        ::= { cEigrpTraffStatsEntry 17 }
++
++    cEigrpAsRouterId  OBJECT-TYPE
++        SYNTAX     InetAddress
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The router-id configured or automatically selected for the
++           EIGRP AS.   Each EIGRP routing process has a unique
++           router-id selected from each autonomous system configured.
++           The format is governed by object cEigrpAsRouterIdType."
++        ::= { cEigrpTraffStatsEntry 18 }
++
++    cEigrpTopoRoutes  OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "The total number of EIGRP derived routes currently existing
++           in the topology table for the AS."
++        ::= { cEigrpTraffStatsEntry 19 }
++
++    cEigrpHeadSerial  OBJECT-TYPE
++        SYNTAX     Counter64
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "Routes in a topology table for an AS are assigned serial
++             numbers and are sequenced internally as they are inserted
++             and deleted.   The serial number of the first route in
++             that internal sequence is called the head serial number.
++             Each AS has its own topology table, and its own serial
++             number space, each of which begins with the value 1.
++             A serial number of zero implies that there are no routes
++             in the topology."
++        ::= { cEigrpTraffStatsEntry 20 }
++
++    cEigrpNextSerial  OBJECT-TYPE
++        SYNTAX     Counter64
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The serial number that would be assigned to the next new
++             or changed route in the topology table for the AS."
++        ::= { cEigrpTraffStatsEntry 21 }
++
++    cEigrpXmitPendReplies  OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++           "When alternate route query packets are sent to adjacent
++           EIGRP peers in an AS, replies are expected.   This object
++           is the total number of outstanding replies expected to
++           queries that have been sent to peers in the current AS.
++           It remains at zero most of the time until an EIGRP route
++           becomes active."
++        ::= { cEigrpTraffStatsEntry 22 }
++
++    cEigrpXmitDummies  OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "A dummy is a temporary internal entity used as a place
++             holder in the topology table for an AS. They are not
++             transmitted in routing updates.  This is the total
++             number currently in existence associated with the AS."
++        ::= { cEigrpTraffStatsEntry 23 }
++
++    --  EIGRP topology table definition
++
++    cEigrpTopoTable OBJECT-TYPE
++        SYNTAX     SEQUENCE OF CEigrpTopoEntry
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "The table of EIGRP routes and their associated
++             attributes for an Autonomous System (AS) configured
++             in a VPN is called a topology table.  All route entries in
++             the topology table will be indexed by IP network type,
++             IP network number and network mask (prefix) size."
++        ::= { cEigrpTopologyInfo 1 }
++
++    cEigrpTopoEntry OBJECT-TYPE
++        SYNTAX     CEigrpTopoEntry
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "The entry for a single EIGRP topology table in the given
++             AS."
++        INDEX { cEigrpVpnId, cEigrpAsNumber, cEigrpDestNetType,
++                cEigrpDestNet, cEigrpDestNetPrefixLen }
++        ::= { cEigrpTopoTable 1 }
++
++    CEigrpTopoEntry ::=
++        SEQUENCE {
++            cEigrpDestNetType             InetAddressType,
++            cEigrpDestNet                 InetAddress,
++            cEigrpDestNetPrefixLen        InetAddressPrefixLength,
++            cEigrpActive                  TruthValue,
++            cEigrpStuckInActive           TruthValue,
++            cEigrpDestSuccessors          Unsigned32,
++            cEigrpFdistance               Unsigned32,
++            cEigrpRouteOriginType         SnmpAdminString,
++            cEigrpRouteOriginAddrType     InetAddressType,
++            cEigrpRouteOriginAddr         InetAddress,
++            cEigrpNextHopAddressType      InetAddressType,
++            cEigrpNextHopAddress          InetAddress,
++            cEigrpNextHopInterface        SnmpAdminString,
++            cEigrpDistance                Unsigned32,
++            cEigrpReportDistance          Unsigned32
++        }
++
++    cEigrpDestNetType OBJECT-TYPE
++        SYNTAX     InetAddressType
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "The format of the destination IP network number for
++             a single route in the topology table in the AS specified
++             in cEigrpDestNet."
++        ::= { cEigrpTopoEntry 1 }
++
++    cEigrpDestNet OBJECT-TYPE
++        SYNTAX     InetAddress
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "The destination IP network number for a single route in
++             the topology table in the AS.  The format is governed
++             by object cEigrpDestNetType."
++        ::= { cEigrpTopoEntry 2 }
++
++    cEigrpDestNetPrefixLen OBJECT-TYPE
++        SYNTAX     InetAddressPrefixLength
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "The prefix length associated with the destination IP
++             network address for a single route in the topology
++             table in the AS.  The format is governed by the object
++             cEigrpDestNetType."
++        ::= { cEigrpTopoEntry 4 }
++
++    cEigrpActive OBJECT-TYPE
++        SYNTAX     TruthValue
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "A value of true(1) indicates the route to the
++             destination network has failed and an active (query)
++             search for an alternative path is in progress.  A value
++             of false(2) indicates the route is stable (passive)."
++        ::= { cEigrpTopoEntry 5 }
++
++    cEigrpStuckInActive OBJECT-TYPE
++        SYNTAX     TruthValue
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "A value of true(1) indicates that that this route which is
++             in active state (cEigrpActive = true(1)) has not received
++             any replies to queries for alternate paths, and a second
++             EIGRP route query, called a stuck-in-active query, has
++             now been sent."
++        ::= { cEigrpTopoEntry 6 }
++
++    cEigrpDestSuccessors OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "A successor is the next routing hop for a path to the
++             destination IP network number for a single route in the
++             topology table in the AS.  There can be several
++             potential successors if there are multiple paths to the
++             destination.   This is the total number of successors for
++             a topology entry."
++        ::= { cEigrpTopoEntry 7 }
++
++    cEigrpFdistance OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++             "The feasibility (best) distance is the minimum distance
++             from this router to the destination IP network in
++             this topology entry.  The feasibility distance is
++             used in determining the best successor for a path to the
++             destination network."
++        ::= { cEigrpTopoEntry 8 }
++
++     cEigrpRouteOriginType OBJECT-TYPE
++        SYNTAX     SnmpAdminString
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++             "This is a text string describing the internal origin
++              of the EIGRP route represented by the topology entry."
++        ::= { cEigrpTopoEntry 9 }
++
++     cEigrpRouteOriginAddrType OBJECT-TYPE
++        SYNTAX     InetAddressType
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++             "The format of the IP address defined as the origin of
++             this topology route entry."
++        ::= { cEigrpTopoEntry 10 }
++
++     cEigrpRouteOriginAddr OBJECT-TYPE
++        SYNTAX     InetAddress
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++             "If the origin of the topology route entry is external
++              to this router, then this object is the IP address
++              of the router from which it originated.  The format 
++              is governed by object cEigrpRouteOriginAddrType."
++        ::= { cEigrpTopoEntry 11 }
++
++     cEigrpNextHopAddressType OBJECT-TYPE
++        SYNTAX     InetAddressType
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++             "The format of the next hop IP address for the route
++              represented by the topology entry."
++        ::= { cEigrpTopoEntry 12 }
++
++     cEigrpNextHopAddress OBJECT-TYPE
++        SYNTAX     InetAddress
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++             "This is the next hop IP address for the route represented
++              by the topology entry.   The next hop is where
++              network traffic will be routed to in order to reach
++              the destination network for this topology entry.  The
++              format is governed by cEigrpNextHopAddressType."
++        ::= { cEigrpTopoEntry 13 }
++
++     cEigrpNextHopInterface OBJECT-TYPE
++        SYNTAX     SnmpAdminString
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++             "The interface through which the next hop IP address
++              is reached to send network traffic to the destination
++              network represented by the topology entry."
++        ::= { cEigrpTopoEntry 14 }
++
++     cEigrpDistance OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++             "The computed distance to the destination network entry
++             from this router."
++        ::= { cEigrpTopoEntry 15 }
++
++     cEigrpReportDistance OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++             "The computed distance to the destination network in the
++              topology entry reported to this router by the originator
++              of this route."
++        ::= { cEigrpTopoEntry 16 }
++
++    --  EIGRP Peer table per VPN and AS (expansion table)
++
++    cEigrpPeerTable OBJECT-TYPE
++        SYNTAX     SEQUENCE OF CEigrpPeerEntry
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "The table of established EIGRP peers (neighbors) in the
++             selected autonomous system.   Peers are indexed by their
++             unique internal handle id, as well as the AS number and
++             VPN id.   The peer entry is removed from the table if
++             the peer is declared down."
++    ::= { cEigrpPeerInfo 1 }
++
++    cEigrpPeerEntry OBJECT-TYPE
++        SYNTAX     CEigrpPeerEntry
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "Statistics and operational parameters for a single peer
++             in the AS."
++        INDEX { cEigrpVpnId, cEigrpAsNumber, cEigrpHandle }
++        ::= { cEigrpPeerTable 1 }
++
++    CEigrpPeerEntry ::=
++        SEQUENCE {
++            cEigrpHandle        Unsigned32,
++            cEigrpPeerAddrType  InetAddressType,
++            cEigrpPeerAddr      InetAddress,
++            cEigrpPeerIfIndex   InterfaceIndexOrZero,
++            cEigrpHoldTime      Unsigned32,
++            cEigrpUpTime        EigrpUpTimeString,
++            cEigrpSrtt          Unsigned32,
++            cEigrpRto           Unsigned32,
++            cEigrpPktsEnqueued  Unsigned32,
++            cEigrpLastSeq       Unsigned32,
++            cEigrpVersion       EigrpVersionString,
++            cEigrpRetrans       Counter32,
++            cEigrpRetries       Unsigned32
++        }
++
++    cEigrpHandle OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "The unique internal identifier for the peer in the AS.
++             This is a unique value among peer entries in a selected
++             table."
++        ::= { cEigrpPeerEntry 1 }
++
++    cEigrpPeerAddrType OBJECT-TYPE
++        SYNTAX     InetAddressType
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The format of the remote source IP address used by the
++             peer to establish the EIGRP adjacency with this router."
++        ::= { cEigrpPeerEntry 2 }
++
++    cEigrpPeerAddr OBJECT-TYPE
++        SYNTAX     InetAddress
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The source IP address used by the peer to establish the
++             EIGRP adjacency with this router.  The format is
++             governed by object cEigrpPeerAddrType."
++        ::= { cEigrpPeerEntry 3 }
++
++    cEigrpPeerIfIndex OBJECT-TYPE
++        SYNTAX     InterfaceIndexOrZero
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The ifIndex of the interface on this router through
++             which this peer can be reached."
++        ::= { cEigrpPeerEntry 4 }
++
++    cEigrpHoldTime OBJECT-TYPE
++        SYNTAX     Unsigned32
++        UNITS      "seconds"
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The count-down timer indicating how much time must
++             pass without receiving a hello packet from this
++             EIGRP peer before this router declares the peer down.
++             A peer declared as down is removed from the table and
++             is no longer visible."
++        ::= { cEigrpPeerEntry 5 }
++
++    cEigrpUpTime OBJECT-TYPE
++        SYNTAX       EigrpUpTimeString
++        MAX-ACCESS   read-only
++        STATUS       current
++        DESCRIPTION
++            "The elapsed time since the EIGRP adjacency was first
++             established with the peer."
++        ::= { cEigrpPeerEntry 6 }
++
++    cEigrpSrtt OBJECT-TYPE
++        SYNTAX     Unsigned32
++        UNITS      "milliseconds"
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The computed smooth round trip time for packets to and
++             from the peer."
++        ::= { cEigrpPeerEntry 7 }
++
++    cEigrpRto OBJECT-TYPE
++        SYNTAX     Unsigned32
++        UNITS      "milliseconds"
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The computed retransmission timeout for the peer.
++             This value is computed over time as packets are sent to
++             the peer and acknowledgements are received from it,
++             and is the amount of time to wait before resending
++             a packet from the retransmission queue to the peer
++             when an expected acknowledgement has not been received."
++        ::= { cEigrpPeerEntry 8 }
++
++    cEigrpPktsEnqueued OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The number of any EIGRP packets currently enqueued
++             waiting to be sent to this peer."
++        ::= { cEigrpPeerEntry 9 }
++
++    cEigrpLastSeq OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "All transmitted EIGRP packets have a sequence number
++             assigned. This is the sequence number of the last EIGRP
++             packet sent to this peer."
++        ::= { cEigrpPeerEntry 10 }
++
++    cEigrpVersion OBJECT-TYPE
++        SYNTAX     EigrpVersionString
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The EIGRP version information reported by the remote
++             peer."
++        ::= { cEigrpPeerEntry 11 }
++
++    cEigrpRetrans OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The cumulative number of retransmissions to this peer
++             during the period that the peer adjacency has remained
++             up."
++        ::= { cEigrpPeerEntry 12 }
++
++    cEigrpRetries OBJECT-TYPE
++        SYNTAX     Unsigned32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The number of times the current unacknowledged packet
++             has been retried, i.e. resent to this peer to be
++             acknowledged."
++        ::= { cEigrpPeerEntry 13 }
++
++    --  EIGRP Interfaces table per VPN and AS
++
++    cEigrpInterfaceTable OBJECT-TYPE
++        SYNTAX     SEQUENCE OF CEigrpInterfaceEntry
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "The table of interfaces over which EIGRP is running, and
++             their associated statistics.   This table is independent
++             of whether any peer adjacencies have been formed over
++             the interfaces or not.   Interfaces running EIGRP are
++             determined by whether their assigned IP addresses fall
++             within configured EIGRP network statements."
++        ::= { cEigrpInterfaceInfo 1 }
++
++    cEigrpInterfaceEntry OBJECT-TYPE
++        SYNTAX     CEigrpInterfaceEntry
++        MAX-ACCESS not-accessible
++        STATUS     current
++        DESCRIPTION
++            "Information for a single interface running EIGRP in the
++             AS and VPN."
++        INDEX { cEigrpVpnId, cEigrpAsNumber, ifIndex }
++        ::= { cEigrpInterfaceTable 1 }
++
++    CEigrpInterfaceEntry ::=
++        SEQUENCE {
++            cEigrpPeerCount        Gauge32,
++            cEigrpXmitReliableQ    Gauge32,
++            cEigrpXmitUnreliableQ  Gauge32,
++            cEigrpMeanSrtt         Unsigned32,
++            cEigrpPacingReliable   Unsigned32,
++            cEigrpPacingUnreliable Unsigned32,
++            cEigrpMFlowTimer       Unsigned32,
++            cEigrpPendingRoutes    Gauge32,
++            cEigrpHelloInterval    Unsigned32,
++            cEigrpXmitNextSerial   Counter64,
++            cEigrpUMcasts          Counter32,
++            cEigrpRMcasts          Counter32,
++            cEigrpUUcasts          Counter32,
++            cEigrpRUcasts          Counter32,
++            cEigrpMcastExcepts     Counter32,
++            cEigrpCRpkts           Counter32,
++            cEigrpAcksSuppressed   Counter32,
++            cEigrpRetransSent       Counter32,
++            cEigrpOOSrcvd          Counter32,
++            cEigrpAuthMode         INTEGER,
++            cEigrpAuthKeyChain    SnmpAdminString
++         }
++
++    cEigrpPeerCount OBJECT-TYPE
++        SYNTAX     Gauge32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The number of EIGRP adjacencies currently formed with
++             peers reached through this interface."
++        ::= { cEigrpInterfaceEntry 3 }
++
++    cEigrpXmitReliableQ OBJECT-TYPE
++        SYNTAX     Gauge32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The number of EIGRP packets currently waiting in the
++             reliable transport (acknowledgement-required) 
++             transmission queue to be sent to a peer."
++        ::= { cEigrpInterfaceEntry 4 }
++
++    cEigrpXmitUnreliableQ OBJECT-TYPE
++        SYNTAX     Gauge32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The number EIGRP of packets currently waiting in
++             the unreliable transport (no acknowledgement required)
++             transmission queue."
++        ::= { cEigrpInterfaceEntry 5 }
++
++    cEigrpMeanSrtt OBJECT-TYPE
++        SYNTAX     Unsigned32
++        UNITS      "milliseconds"
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The average of all the computed smooth round trip time
++             values for a packet to and from all peers established on
++             this interface."
++        ::= { cEigrpInterfaceEntry 6 }
++
++    cEigrpPacingReliable OBJECT-TYPE
++        SYNTAX     Unsigned32
++        UNITS      "milliseconds"
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The configured time interval between EIGRP packet
++             transmissions on the interface when the reliable transport
++             method is used."
++        ::= { cEigrpInterfaceEntry 7 }
++
++    cEigrpPacingUnreliable OBJECT-TYPE
++        SYNTAX     Unsigned32
++        UNITS      "milliseconds"
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The configured time interval between EIGRP packet
++             transmissions on the interface when the unreliable
++             transport method is used."
++        ::= { cEigrpInterfaceEntry 8 }
++
++    cEigrpMFlowTimer OBJECT-TYPE
++        SYNTAX     Unsigned32
++        UNITS      "milliseconds"
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The configured multicast flow control timer value for
++             this interface."
++        ::= { cEigrpInterfaceEntry 9 }
++
++    cEigrpPendingRoutes OBJECT-TYPE
++        SYNTAX     Gauge32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The number of queued EIGRP routing updates awaiting
++             transmission on this interface."
++        ::= { cEigrpInterfaceEntry 10 }
++
++    cEigrpHelloInterval OBJECT-TYPE
++        SYNTAX     Unsigned32
++        UNITS      "seconds"
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The configured time interval between Hello packet
++             transmissions for this interface."
++        ::= { cEigrpInterfaceEntry 11 }
++
++    cEigrpXmitNextSerial OBJECT-TYPE
++        SYNTAX     Counter64
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The serial number of the next EIGRP packet that is to
++             be queued for transmission on this interface."
++        ::= { cEigrpInterfaceEntry 12 }
++
++    cEigrpUMcasts OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The total number of unreliable (no acknowledgement
++             required) EIGRP multicast packets sent on this
++             interface."
++        ::= { cEigrpInterfaceEntry 13 }
++
++    cEigrpRMcasts OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The total number of reliable (acknowledgement required)
++             EIGRP multicast packets sent on this interface."
++        ::= { cEigrpInterfaceEntry 14 }
++
++    cEigrpUUcasts OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The total number of unreliable (no acknowledgement
++             required) EIGRP unicast packets sent on this
++             interface."
++        ::= { cEigrpInterfaceEntry 15 }
++
++    cEigrpRUcasts OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The total number of reliable (acknowledgement required)
++             unicast packets sent on this interface."
++        ::= { cEigrpInterfaceEntry 16 }
++
++    cEigrpMcastExcepts OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The total number of EIGRP multicast exception
++             transmissions that have occurred on this interface."
++        ::= { cEigrpInterfaceEntry 17 }
++
++    cEigrpCRpkts OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The total number EIGRP Conditional-Receive packets sent on
++             this interface."
++        ::= { cEigrpInterfaceEntry 18 }
++
++    cEigrpAcksSuppressed OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The total number of individual EIGRP acknowledgement
++             packets that have been suppressed and combined in
++             an already enqueued outbound reliable packet on this
++             interface."
++        ::= { cEigrpInterfaceEntry 19 }
++
++    cEigrpRetransSent OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The total number EIGRP packet retransmissions sent on
++             the interface."
++        ::= { cEigrpInterfaceEntry 20 }
++
++    cEigrpOOSrcvd OBJECT-TYPE
++        SYNTAX     Counter32
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The total number of out-of-sequence EIGRP packets
++             received."
++        ::= { cEigrpInterfaceEntry 21 }
++
++    cEigrpAuthMode OBJECT-TYPE
++        SYNTAX     INTEGER {
++                       none(1),
++                       md5(2)
++                   }
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The EIGRP authentication mode of the interface.
++            none  :  no authentication enabled on the interface
++            md5   :  MD5 authentication enabled on the interface"
++        ::= { cEigrpInterfaceEntry 22 }
++
++    cEigrpAuthKeyChain OBJECT-TYPE
++        SYNTAX     SnmpAdminString
++        MAX-ACCESS read-only
++        STATUS     current
++        DESCRIPTION
++            "The name of the authentication key-chain configured
++             on this interface.   The key-chain is a reference to
++             which set of secret keys are to be accessed in order
++             to determine which secret key string to use.  The key
++             chain name is not the secret key string password and
++             can also be used in other routing protocols, such
++             as RIP and ISIS."
++        ::= { cEigrpInterfaceEntry 23 }
++
++    -- Notifications
++
++    cEigrpAuthFailureEvent NOTIFICATION-TYPE
++        OBJECTS { cEigrpPeerAddrType, cEigrpPeerAddr }
++        STATUS     current
++        DESCRIPTION
++            "This notification is sent when EIGRP MD5 authentication
++             is enabled on any interface and peer adjacencies are
++             formed, and any adjacencies go down as a result of an
++             authentication failure."
++        ::=  { cEigrpMIBNotifications 1 }
++
++    cEigrpRouteStuckInActive NOTIFICATION-TYPE
++        OBJECTS { cEigrpPeerAddrType, cEigrpPeerAddr,
++                  cEigrpStuckInActive }
++        STATUS     current
++        DESCRIPTION
++            "This notification is sent when a route in the topology
++             table is stuck in an active state.  During the query
++             phase for a new route to a destination network, a route
++             is described as being in the active state if when an
++             alternate path is actively being sought, no replies are
++             received to normal queries or stuck-in-active queries."
++        ::=  { cEigrpMIBNotifications 2 }
++
++    -- Conformance
++
++    cEigrpMIBCompliances
++        OBJECT IDENTIFIER ::= { cEigrpMIBConformance 1 }
++
++    cEigrpMIBGroups
++        OBJECT IDENTIFIER ::= { cEigrpMIBConformance 2 }
++
++    -- Compliance
++
++    cEigrpMIBCompliance MODULE-COMPLIANCE
++        STATUS     current
++        DESCRIPTION
++            "The compliance statement for entities which implement
++             the Cisco EIGRP Management MIB."
++        MODULE
++            MANDATORY-GROUPS {
++                cEigrpVpnDataGroup,
++                cEigrpTrafficStatsGroup,
++                cEigrpInterfaceDataGroup,
++                cEigrpPeerDataGroup,
++                cEigrpTopoDataGroup,
++                cEigrpNotificationsGroup
++            }
++
++            OBJECT cEigrpAsRouterIdType
++            SYNTAX INTEGER { ipv4(1) }
++            DESCRIPTION
++                "An implementation is only required to support
++                 IPv4 address type."
++
++            OBJECT cEigrpRouteOriginAddrType
++            SYNTAX INTEGER { ipv4(1) }
++            DESCRIPTION
++                "An implementation is only required to support
++                 IPv4 address type."
++
++            OBJECT cEigrpNextHopAddressType
++            SYNTAX INTEGER { ipv4(1) }
++            DESCRIPTION
++                "An implementation is only required to support
++                 IPv4 address type."
++
++            OBJECT cEigrpPeerAddrType
++            SYNTAX INTEGER { ipv4(1) }
++            DESCRIPTION
++                "An implementation is only required to support
++                 IPv4 address type."
++        ::= { cEigrpMIBCompliances 1 }
++
++    -- Units of Conformance
++
++    cEigrpVpnDataGroup OBJECT-GROUP
++        OBJECTS {
++            cEigrpVpnName
++        }
++        STATUS     current
++        DESCRIPTION
++            "The collection of VPN names which have been configured
++             with one or more EIGRP autonmous systems."
++        ::= { cEigrpMIBGroups 1 }
++
++    cEigrpTrafficStatsGroup OBJECT-GROUP
++        OBJECTS {
++            cEigrpHellosSent,
++            cEigrpHellosRcvd,
++            cEigrpUpdatesSent,
++            cEigrpUpdatesRcvd,
++            cEigrpQueriesSent,
++            cEigrpQueriesRcvd,
++            cEigrpRepliesSent,
++            cEigrpRepliesRcvd,
++            cEigrpAcksSent,
++            cEigrpAcksRcvd,
++            cEigrpInputQHighMark,
++            cEigrpInputQDrops,
++            cEigrpSiaQueriesSent,
++            cEigrpSiaQueriesRcvd
++        }
++        STATUS     current
++        DESCRIPTION
++            "A collection of objects providing management information
++             regarding collective EIGRP packet statistics for all EIGRP
++             autonomous systems configured."
++        ::= { cEigrpMIBGroups 2 }
++
++    cEigrpInterfaceDataGroup OBJECT-GROUP
++        OBJECTS {
++            cEigrpPeerCount,
++            cEigrpXmitReliableQ,
++            cEigrpXmitUnreliableQ,
++            cEigrpMeanSrtt,
++            cEigrpPacingReliable,
++            cEigrpPacingUnreliable,
++            cEigrpMFlowTimer,
++            cEigrpPendingRoutes,
++            cEigrpHelloInterval,
++            cEigrpXmitNextSerial,
++            cEigrpUMcasts,
++            cEigrpRMcasts,
++            cEigrpUUcasts,
++            cEigrpRUcasts,
++            cEigrpMcastExcepts,
++            cEigrpCRpkts,
++            cEigrpAcksSuppressed,
++            cEigrpRetransSent,
++            cEigrpOOSrcvd,
++            cEigrpAuthMode,
++            cEigrpAuthKeyChain
++        }
++        STATUS     current
++        DESCRIPTION
++            "A collection of objects providing management information
++             for interfaces over which EIGRP is configured and
++             running."
++        ::= { cEigrpMIBGroups 3 }
++
++    cEigrpPeerDataGroup OBJECT-GROUP
++        OBJECTS {
++            cEigrpNbrCount,
++            cEigrpPeerAddrType,
++            cEigrpPeerAddr,
++            cEigrpPeerIfIndex,
++            cEigrpHoldTime,
++            cEigrpUpTime,
++            cEigrpSrtt,
++            cEigrpRto,
++            cEigrpPktsEnqueued,
++            cEigrpLastSeq,
++            cEigrpVersion,
++            cEigrpRetrans,
++            cEigrpRetries
++        }
++        STATUS     current
++        DESCRIPTION
++            "A collection of objects providing management information
++             for EIGRP peer adjacencies formed in the EIGRP
++             autonoumous systems."
++        ::= { cEigrpMIBGroups 4 }
++
++    cEigrpTopoDataGroup OBJECT-GROUP
++        OBJECTS {
++            cEigrpAsRouterId,
++            cEigrpAsRouterIdType,
++            cEigrpTopoRoutes,
++            cEigrpHeadSerial,
++            cEigrpNextSerial,
++            cEigrpXmitPendReplies,
++            cEigrpXmitDummies,
++            cEigrpActive,
++            cEigrpStuckInActive,
++            cEigrpDestSuccessors,
++            cEigrpFdistance,
++            cEigrpRouteOriginType,
++            cEigrpRouteOriginAddrType,
++            cEigrpRouteOriginAddr,
++            cEigrpNextHopAddressType,
++            cEigrpNextHopAddress,
++            cEigrpNextHopInterface,
++            cEigrpDistance,
++            cEigrpReportDistance
++        }
++        STATUS     current
++        DESCRIPTION
++            "A collection of objects providing management information
++             for EIGRP topology routes derived within autonomous
++             systems and received in updates from EIGRP neighbors."
++        ::= { cEigrpMIBGroups 5 }
++
++    cEigrpNotificationsGroup NOTIFICATION-GROUP
++        NOTIFICATIONS {
++            cEigrpAuthFailureEvent,
++            cEigrpRouteStuckInActive
++        }
++        STATUS     current
++        DESCRIPTION
++            "Group of notifications on EIGRP routers."
++        ::= { cEigrpMIBGroups 6 }
++END
+\ No newline at end of file
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_neighbor.c eigrp/eigrpd/eigrp_neighbor.c
+--- a/eigrpd/eigrp_neighbor.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_neighbor.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,294 @@
++/*
++ * EIGRP Neighbor Handling.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "linklist.h"
++#include "prefix.h"
++#include "memory.h"
++#include "command.h"
++#include "thread.h"
++#include "stream.h"
++#include "table.h"
++#include "log.h"
++#include "keychain.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_network.h"
++#include "eigrpd/eigrp_topology.h"
++
++
++struct eigrp_neighbor *
++eigrp_nbr_new (struct eigrp_interface *ei)
++{
++  struct eigrp_neighbor *nbr;
++
++  /* Allcate new neighbor. */
++  nbr = XCALLOC (MTYPE_EIGRP_NEIGHBOR, sizeof (struct eigrp_neighbor));
++
++  /* Relate neighbor to the interface. */
++  nbr->ei = ei;
++
++  /* Set default values. */
++
++  eigrp_nbr_state_set (nbr, EIGRP_NEIGHBOR_DOWN);
++
++  return nbr;
++}
++
++/**
++ *@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
++ *                                   proto_item *ti)
++ *
++ * @par
++ * Create a new neighbor structure and initalize it.
++ */
++static struct eigrp_neighbor *
++eigrp_nbr_add (struct eigrp_interface *ei, struct eigrp_header *eigrph,
++              struct ip *iph)
++{
++  struct eigrp_neighbor *nbr;
++
++  nbr = eigrp_nbr_new (ei);
++  nbr->src = iph->ip_src;
++
++//  if (IS_DEBUG_EIGRP_EVENT)
++//    zlog_debug("NSM[%s:%s]: start", IF_NAME (nbr->oi),
++//               inet_ntoa (nbr->router_id));
++
++  return nbr;
++}
++
++struct eigrp_neighbor *
++eigrp_nbr_get (struct eigrp_interface *ei, struct eigrp_header *eigrph,
++              struct ip *iph)
++{
++  struct eigrp_neighbor *nbr;
++  struct listnode *node, *nnode;
++
++  for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
++    {
++      if (iph->ip_src.s_addr == nbr->src.s_addr)
++        {
++          return nbr;
++        }
++    }
++
++  nbr = eigrp_nbr_add (ei, eigrph, iph);
++  listnode_add (ei->nbrs, nbr);
++
++  return nbr;
++}
++
++struct eigrp_neighbor *
++eigrp_nbr_lookup_by_addr (struct eigrp_interface *ei, struct in_addr *addr)
++{
++  struct eigrp_neighbor *nbr;
++  struct listnode *node, *nnode;
++
++  for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
++      {
++        if (addr == nbr->src.s_addr)
++          {
++            return nbr;
++          }
++      }
++
++  return NULL;
++}
++
++
++/* Delete specified EIGRP neighbor from interface. */
++void
++eigrp_nbr_delete (struct eigrp_neighbor *nbr)
++{
++
++  eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
++  eigrp_topology_neighbor_down(nbr->ei->eigrp, nbr);
++
++  /* Cancel all events. *//* Thread lookup cost would be negligible. */
++  thread_cancel_event (master, nbr);
++  eigrp_fifo_free (nbr->multicast_queue);
++  eigrp_fifo_free (nbr->retrans_queue);
++  THREAD_OFF (nbr->t_holddown);
++
++  listnode_delete (nbr->ei->nbrs,nbr);
++  XFREE (MTYPE_EIGRP_NEIGHBOR, nbr);
++}
++
++int
++holddown_timer_expired (struct thread *thread)
++{
++  struct eigrp_neighbor *nbr;
++
++  nbr = THREAD_ARG (thread);
++
++  zlog_info ("Neighbor %s (%s) is down: holding time expired",
++	     inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
++  nbr->state = EIGRP_NEIGHBOR_DOWN;
++  eigrp_nbr_delete (nbr);
++
++  return 0;
++}
++
++u_char
++eigrp_nbr_state_get (struct eigrp_neighbor *nbr)
++{
++  return(nbr->state);
++}
++
++void
++eigrp_nbr_state_set (struct eigrp_neighbor *nbr, u_char state)
++{
++
++  nbr->state = state;
++
++  if (eigrp_nbr_state_get(nbr) == EIGRP_NEIGHBOR_DOWN)
++    {
++      // reset all the seq/ack counters
++      nbr->recv_sequence_number = 0;
++      nbr->init_sequence_number = 0;
++      nbr->retrans_counter = 0;
++
++      // Kvalues
++      nbr->K1 = EIGRP_K1_DEFAULT;
++      nbr->K2 = EIGRP_K2_DEFAULT;
++      nbr->K3 = EIGRP_K3_DEFAULT;
++      nbr->K4 = EIGRP_K4_DEFAULT;
++      nbr->K5 = EIGRP_K5_DEFAULT;
++      nbr->K6 = EIGRP_K6_DEFAULT;
++
++      // hold time..
++      nbr->v_holddown = EIGRP_HOLD_INTERVAL_DEFAULT;
++      THREAD_OFF(nbr->t_holddown);
++
++      /* out with the old */
++      if (nbr->multicast_queue)
++        eigrp_fifo_free (nbr->multicast_queue);
++      if (nbr->retrans_queue)
++      eigrp_fifo_free (nbr->retrans_queue);
++
++      /* in with the new */
++      nbr->retrans_queue = eigrp_fifo_new ();
++      nbr->multicast_queue = eigrp_fifo_new ();
++
++      nbr->crypt_seqnum = 0;
++    }
++}
++
++const char *
++eigrp_nbr_state_str (struct eigrp_neighbor *nbr)
++{
++  const char *state;
++  switch (nbr->state)
++    {
++    case EIGRP_NEIGHBOR_DOWN:
++      {
++	state = "Down";
++	break;
++      }
++    case EIGRP_NEIGHBOR_PENDING:
++      {
++	state = "Waiting for Init";
++	break;
++      }
++    case EIGRP_NEIGHBOR_UP:
++      {
++	state = "Up";
++	break;
++      }
++    }
++
++  return(state);
++}
++
++void
++eigrp_nbr_state_update (struct eigrp_neighbor *nbr)
++{
++  switch (nbr->state)
++    {
++    case EIGRP_NEIGHBOR_DOWN:
++      {
++	/*Start Hold Down Timer for neighbor*/
++//	THREAD_OFF(nbr->t_holddown);
++//	THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired,
++//			nbr, nbr->v_holddown);
++	break;
++      }
++    case EIGRP_NEIGHBOR_PENDING:
++      {
++	/*Reset Hold Down Timer for neighbor*/
++	THREAD_OFF(nbr->t_holddown);
++	THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired, nbr,
++			nbr->v_holddown);
++	break;
++      }
++    case EIGRP_NEIGHBOR_UP:
++      {
++	/*Reset Hold Down Timer for neighbor*/
++	THREAD_OFF(nbr->t_holddown);
++	THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired, nbr,
++			nbr->v_holddown);
++	break;
++      }
++    }
++}
++
++int eigrp_nbr_count_get(void){
++
++	struct eigrp_interface *iface;
++	struct listnode *node, *node2, *nnode2;
++	struct eigrp_neighbor *nbr;
++	struct eigrp *eigrp = eigrp_lookup();
++	u_int32_t counter;
++
++	if (eigrp == NULL)
++	  {
++	    zlog_debug("EIGRP Routing Process not enabled");
++	    return 0;
++	  }
++
++	counter=0;
++	for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface))
++	  {
++	    for (ALL_LIST_ELEMENTS(iface->nbrs, node2, nnode2, nbr))
++	      {
++	        if (nbr->state == EIGRP_NEIGHBOR_UP){
++	          counter++;
++	        }
++	      }
++	  }
++	return counter;
++}
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_neighbor.h eigrp/eigrpd/eigrp_neighbor.h
+--- a/eigrpd/eigrp_neighbor.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_neighbor.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,50 @@
++/*
++ * EIGRP Neighbor Handling Functions.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRP_NEIGHBOR_H
++#define _ZEBRA_EIGRP_NEIGHBOR_H
++
++/* Prototypes */
++extern struct eigrp_neighbor *eigrp_nbr_get(struct eigrp_interface *,
++					    struct eigrp_header *,
++					    struct ip *);
++extern struct eigrp_neighbor *eigrp_nbr_new (struct eigrp_interface *);
++extern void eigrp_nbr_delete(struct eigrp_neighbor *);
++
++extern int holddown_timer_expired(struct thread *);
++
++extern int eigrp_neighborship_check(struct eigrp_neighbor *,struct TLV_Parameter_Type *);
++extern void eigrp_nbr_state_update(struct eigrp_neighbor *);
++extern void eigrp_nbr_state_set(struct eigrp_neighbor *, u_char state);
++extern u_char eigrp_nbr_state_get(struct eigrp_neighbor *);
++extern int eigrp_nbr_count_get(void);
++extern const char *eigrp_nbr_state_str(struct eigrp_neighbor *);
++extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr (struct eigrp_interface *, struct in_addr *);
++
++
++#endif /* _ZEBRA_EIGRP_NEIGHBOR_H */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_network.c eigrp/eigrpd/eigrp_network.c
+--- a/eigrpd/eigrp_network.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_network.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,458 @@
++/*
++ * EIGRP Network Related Functions.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "thread.h"
++#include "linklist.h"
++#include "prefix.h"
++#include "if.h"
++#include "sockunion.h"
++#include "log.h"
++#include "sockopt.h"
++#include "privs.h"
++#include "table.h"
++
++extern struct zebra_privs_t eigrpd_privs;
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_network.h"
++
++static int
++eigrp_network_match_iface(const struct connected *, const struct prefix *);
++static void
++eigrp_network_run_interface(struct eigrp *, struct prefix *, struct interface *);
++
++int
++eigrp_sock_init(void)
++{
++  int eigrp_sock;
++  int ret, hincl = 1;
++
++  if (eigrpd_privs.change(ZPRIVS_RAISE))
++    zlog_err("eigrp_sock_init: could not raise privs, %s",
++        safe_strerror(errno));
++
++  eigrp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP);
++  if (eigrp_sock < 0)
++    {
++      int save_errno = errno;
++      if (eigrpd_privs.change(ZPRIVS_LOWER))
++        zlog_err("eigrp_sock_init: could not lower privs, %s",
++            safe_strerror(errno));
++      zlog_err("eigrp_read_sock_init: socket: %s", safe_strerror(save_errno));
++      exit(1);
++    }
++
++#ifdef IP_HDRINCL
++  /* we will include IP header with packet */
++  ret = setsockopt(eigrp_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl));
++  if (ret < 0)
++    {
++      int save_errno = errno;
++      if (eigrpd_privs.change(ZPRIVS_LOWER))
++        zlog_err("eigrp_sock_init: could not lower privs, %s",
++            safe_strerror(errno));
++      zlog_warn("Can't set IP_HDRINCL option for fd %d: %s", eigrp_sock,
++          safe_strerror(save_errno));
++
++    }
++#elif defined (IPTOS_PREC_INTERNETCONTROL)
++#warning "IP_HDRINCL not available on this system"
++#warning "using IPTOS_PREC_INTERNETCONTROL"
++  ret = setsockopt_ipv4_tos (eigrp_sock, IPTOS_PREC_INTERNETCONTROL);
++  if (ret < 0)
++    {
++      int save_errno = errno;
++      if ( eigrpd_privs.change (ZPRIVS_LOWER) )
++      zlog_err ("eigrpd_sock_init: could not lower privs, %s",
++          safe_strerror (errno) );
++      zlog_warn ("can't set sockopt IP_TOS %d to socket %d: %s",
++          tos, eigrp_sock, safe_strerror (save_errno));
++      close (eigrp_sock); /* Prevent sd leak. */
++      return ret;
++    }
++#else /* !IPTOS_PREC_INTERNETCONTROL */
++#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
++  zlog_warn ("IP_HDRINCL option not available");
++#endif /* IP_HDRINCL */
++
++  ret = setsockopt_ifindex(AF_INET, eigrp_sock, 1);
++
++  if (ret < 0)
++    zlog_warn("Can't set pktinfo option for fd %d", eigrp_sock);
++
++  if (eigrpd_privs.change(ZPRIVS_LOWER))
++    {
++      zlog_err("eigrp_sock_init: could not lower privs, %s",
++          safe_strerror(errno));
++    }
++
++  return eigrp_sock;
++}
++
++void
++eigrp_adjust_sndbuflen(struct eigrp * eigrp, unsigned int buflen)
++{
++  int ret, newbuflen;
++  /* Check if any work has to be done at all. */
++  if (eigrp->maxsndbuflen >= buflen)
++    return;
++  if (eigrpd_privs.change(ZPRIVS_RAISE))
++    zlog_err("%s: could not raise privs, %s", __func__, safe_strerror(errno));
++  /* Now we try to set SO_SNDBUF to what our caller has requested
++   * (the MTU of a newly added interface). However, if the OS has
++   * truncated the actual buffer size to somewhat less size, try
++   * to detect it and update our records appropriately. The OS
++   * may allocate more buffer space, than requested, this isn't
++   * a error.
++   */
++  ret = setsockopt_so_sendbuf(eigrp->fd, buflen);
++  newbuflen = getsockopt_so_sendbuf(eigrp->fd);
++  if (ret < 0 || newbuflen < 0 || newbuflen < (int) buflen)
++    zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d", __func__, buflen,
++        newbuflen);
++  if (newbuflen >= 0)
++    eigrp->maxsndbuflen = (unsigned int) newbuflen;
++  else
++    zlog_warn("%s: failed to get SO_SNDBUF", __func__);
++  if (eigrpd_privs.change(ZPRIVS_LOWER))
++    zlog_err("%s: could not lower privs, %s", __func__, safe_strerror(errno));
++}
++
++int
++eigrp_if_ipmulticast(struct eigrp *top, struct prefix *p, unsigned int ifindex)
++{
++  u_char val;
++  int ret, len;
++
++  val = 0;
++  len = sizeof(val);
++
++  /* Prevent receiving self-origined multicast packets. */
++  ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *) &val, len);
++  if (ret < 0)
++    zlog_warn("can't setsockopt IP_MULTICAST_LOOP (0) for fd %d: %s", top->fd,
++        safe_strerror(errno));
++
++  /* Explicitly set multicast ttl to 1 -- endo. */
++  val = 1;
++  ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &val, len);
++  if (ret < 0)
++    zlog_warn("can't setsockopt IP_MULTICAST_TTL (1) for fd %d: %s", top->fd,
++        safe_strerror(errno));
++
++  ret = setsockopt_ipv4_multicast_if(top->fd, ifindex);
++  if (ret < 0)
++    zlog_warn("can't setsockopt IP_MULTICAST_IF (fd %d, addr %s, "
++        "ifindex %u): %s", top->fd, inet_ntoa(p->u.prefix4), ifindex,
++        safe_strerror(errno));
++
++  return ret;
++}
++
++/* Join to the EIGRP multicast group. */
++int
++eigrp_if_add_allspfrouters(struct eigrp *top, struct prefix *p,
++    unsigned int ifindex)
++{
++  int ret;
++
++  ret = setsockopt_ipv4_multicast(top->fd, IP_ADD_MEMBERSHIP,
++      htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
++  if (ret < 0)
++    zlog_warn("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, "
++        "ifindex %u, AllSPFRouters): %s; perhaps a kernel limit "
++        "on # of multicast group memberships has been exceeded?", top->fd,
++        inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno));
++  else
++    zlog_debug("interface %s [%u] join EIGRP Multicast group.",
++        inet_ntoa(p->u.prefix4), ifindex);
++
++  return ret;
++}
++
++int
++eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p,
++    unsigned int ifindex)
++{
++  int ret;
++
++  ret = setsockopt_ipv4_multicast(top->fd, IP_DROP_MEMBERSHIP,
++      htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
++  if (ret < 0)
++    zlog_warn("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, "
++        "ifindex %u, AllSPFRouters): %s", top->fd, inet_ntoa(p->u.prefix4),
++        ifindex, safe_strerror(errno));
++  else
++    zlog_debug("interface %s [%u] leave EIGRP Multicast group.",
++        inet_ntoa(p->u.prefix4), ifindex);
++
++  return ret;
++}
++
++int
++eigrp_network_set(struct eigrp *eigrp, struct prefix_ipv4 *p)
++{
++  struct route_node *rn;
++  struct interface *ifp;
++  struct listnode *node;
++
++  rn = route_node_get(eigrp->networks, (struct prefix *) p);
++  if (rn->info)
++    {
++      /* There is already same network statement. */
++      route_unlock_node(rn);
++      return 0;
++    }
++
++  struct prefix_ipv4 *pref = prefix_ipv4_new();
++  PREFIX_COPY_IPV4(pref,p);
++  rn->info = (void *) pref;
++
++  /* Schedule Router ID Update. */
++//    if (eigrp->router_id == 0)
++//      eigrp_router_id_update(eigrp);
++  /* Run network config now. */
++  /* Get target interface. */
++  for (ALL_LIST_ELEMENTS_RO(eigrp_om->iflist, node, ifp))
++    eigrp_network_run_interface(eigrp, (struct prefix *) p, ifp);
++
++  return 1;
++}
++
++/* Check whether interface matches given network
++ * returns: 1, true. 0, false
++ */
++static int
++eigrp_network_match_iface(const struct connected *co, const struct prefix *net)
++{
++  /* new approach: more elegant and conceptually clean */
++  return prefix_match(net, CONNECTED_PREFIX (co));
++}
++
++static void
++eigrp_network_run_interface(struct eigrp *eigrp, struct prefix *p,
++    struct interface *ifp)
++{
++  struct listnode *cnode;
++  struct connected *co;
++
++  /* if interface prefix is match specified prefix,
++   then create socket and join multicast group. */
++  for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, co))
++    {
++
++      if (CHECK_FLAG (co->flags,ZEBRA_IFA_SECONDARY))
++        continue;
++
++      if (p->family == co->address->family
++          && !eigrp_if_table_lookup(ifp, co->address)
++          && eigrp_network_match_iface(co, p))
++        {
++          struct eigrp_interface *ei;
++
++          ei = eigrp_if_new(eigrp, ifp, co->address);
++          ei->connected = co;
++
++          ei->params = eigrp_lookup_if_params(ifp, ei->address->u.prefix4);
++
++          /* Relate eigrp interface to eigrp instance. */
++          ei->eigrp = eigrp;
++
++          /* update network type as interface flag */
++          /* If network type is specified previously,
++           skip network type setting. */
++          ei->type = IF_DEF_PARAMS (ifp)->type;
++
++          /* if router_id is not configured, dont bring up
++           * interfaces.
++           * eigrp_router_id_update() will call eigrp_if_update
++           * whenever r-id is configured instead.
++           */
++          if (if_is_operative(ifp))
++            eigrp_if_up(ei);
++        }
++    }
++}
++
++void
++eigrp_if_update(struct interface *ifp)
++{
++  struct listnode *node, *nnode;
++  struct route_node *rn;
++  struct eigrp *eigrp;
++
++  /*
++   * In the event there are multiple eigrp autonymnous systems running,
++   * we need to check eac one and add the interface as approperate
++   */
++  for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp))
++    {
++      /* EIGRP must be on and Router-ID must be configured. */
++      if (!eigrp || eigrp->router_id == 0)
++        continue;
++
++      /* Run each network for this interface. */
++      for (rn = route_top(eigrp->networks); rn; rn = route_next(rn))
++        if (rn->info != NULL)
++          {
++            eigrp_network_run_interface(eigrp, &rn->p, ifp);
++          }
++    }
++}
++
++int
++eigrp_network_unset(struct eigrp *eigrp, struct prefix_ipv4 *p)
++{
++  struct route_node *rn;
++  struct listnode *node, *nnode;
++  struct eigrp_interface *ei;
++  struct prefix *pref;
++
++  rn = route_node_lookup(eigrp->networks, (struct prefix *) p);
++  if (rn == NULL)
++    return 0;
++
++  pref = rn->info;
++  route_unlock_node (rn);
++
++  if (!IPV4_ADDR_SAME (&pref->u.prefix4, &p->prefix))
++      return 0;
++
++  prefix_ipv4_free(rn->info);
++  rn->info = NULL;
++  route_unlock_node(rn); /* initial reference */
++
++  /* Find interfaces that not configured already.  */
++  for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei))
++    {
++      int found = 0;
++      struct connected *co = ei->connected;
++
++      for (rn = route_top(eigrp->networks); rn; rn = route_next(rn))
++        {
++          if (rn->info == NULL)
++            continue;
++
++          if (eigrp_network_match_iface(co, &rn->p))
++            {
++              zlog_debug("eigrp_network_unset()2");
++              found = 1;
++              route_unlock_node(rn);
++              break;
++            }
++        }
++
++      if (found == 0)
++        {
++          eigrp_if_free(ei, INTERFACE_DOWN_BY_VTY);
++        }
++    }
++
++  return 1;
++}
++
++u_int32_t
++eigrp_calculate_metrics(struct eigrp *eigrp, struct eigrp_metrics *metric)
++{
++  u_int64_t temp_metric;
++  temp_metric = 0;
++
++  if(metric->delay == EIGRP_MAX_METRIC)
++    return EIGRP_MAX_METRIC;
++
++  // EIGRP Metric = {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
++
++  if (eigrp->k_values[0])
++    temp_metric += (eigrp->k_values[0] * metric->bandwith);
++  if (eigrp->k_values[1])
++    temp_metric += ((eigrp->k_values[1] * metric->bandwith)
++        / (256 - metric->load));
++  if (eigrp->k_values[2])
++    temp_metric += (eigrp->k_values[2] * metric->delay);
++  if (eigrp->k_values[3] && !eigrp->k_values[4])
++    temp_metric *= eigrp->k_values[3];
++  if (!eigrp->k_values[3] && eigrp->k_values[4])
++    temp_metric *= (eigrp->k_values[4] / metric->reliability);
++  if (eigrp->k_values[3] && eigrp->k_values[4])
++    temp_metric *= ((eigrp->k_values[4] / metric->reliability)
++        + eigrp->k_values[3]);
++
++  if (temp_metric <= EIGRP_MAX_METRIC)
++    return (u_int32_t) temp_metric;
++  else
++    return EIGRP_MAX_METRIC;
++}
++
++u_int32_t
++eigrp_calculate_total_metrics(struct eigrp *eigrp,
++    struct eigrp_neighbor_entry *entry)
++{
++  entry->total_metric = entry->reported_metric;
++  u_int64_t temp_delay = (u_int64_t) entry->total_metric.delay
++      + (u_int64_t) EIGRP_IF_PARAM (entry->ei, delay);
++  entry->total_metric.delay =
++      temp_delay > EIGRP_MAX_METRIC ? EIGRP_MAX_METRIC : (u_int32_t) temp_delay;
++
++  u_int32_t bw = EIGRP_IF_PARAM (entry->ei,bandwidth);
++  entry->total_metric.bandwith =
++      entry->total_metric.bandwith > bw ? bw : entry->total_metric.bandwith;
++
++  return eigrp_calculate_metrics(eigrp, &entry->total_metric);
++}
++
++u_char
++eigrp_metrics_is_same(struct eigrp_metrics *metric1,
++    struct eigrp_metrics *metric2)
++{
++  if ((metric1->bandwith = metric2->bandwith)
++      && (metric1->delay == metric2->delay)
++      && (metric1->hop_count == metric2->hop_count)
++      && (metric1->load == metric2->load)
++      && (metric1->reliability == metric2->reliability)
++      && (metric1->mtu[0] == metric2->mtu[0])
++      && (metric1->mtu[1] == metric2->mtu[1])
++      && (metric1->mtu[2] == metric2->mtu[2]))
++      return 1;
++
++    return 0; // if different
++}
++void
++eigrp_external_routes_refresh (struct eigrp *eigrp, int type)
++{
++
++
++}
++
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_network.h eigrp/eigrpd/eigrp_network.h
+--- a/eigrpd/eigrp_network.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_network.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,52 @@
++/*
++ * EIGRP Network Related Functions.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRP_NETWORK_H
++#define _ZEBRA_EIGRP_NETWORK_H
++
++/* Prototypes */
++
++extern int eigrp_sock_init (void);
++extern int eigrp_if_ipmulticast (struct eigrp *, struct prefix *, unsigned int);
++extern int eigrp_network_set (struct eigrp *, struct prefix_ipv4 *);
++extern int eigrp_network_unset (struct eigrp *eigrp, struct prefix_ipv4 *p);
++
++extern int eigrp_hello_timer (struct thread *);
++extern void eigrp_if_update (struct interface *);
++extern int eigrp_if_add_allspfrouters (struct eigrp *, struct prefix *,
++                                       unsigned int);
++extern int eigrp_if_drop_allspfrouters (struct eigrp *top, struct prefix *p,
++                                        unsigned int ifindex);
++extern void eigrp_adjust_sndbuflen (struct eigrp *, unsigned int);
++
++extern u_int32_t eigrp_calculate_metrics (struct eigrp *, struct eigrp_metrics *);
++extern u_int32_t eigrp_calculate_total_metrics (struct eigrp *, struct eigrp_neighbor_entry *);
++extern u_char eigrp_metrics_is_same(struct eigrp_metrics *,struct eigrp_metrics *);
++extern void eigrp_external_routes_refresh (struct eigrp *, int);
++
++#endif /* EIGRP_NETWORK_H_ */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_packet.c eigrp/eigrpd/eigrp_packet.c
+--- a/eigrpd/eigrp_packet.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_packet.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,1455 @@
++/*
++ * EIGRP General Sending and Receiving of EIGRP Packets.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "thread.h"
++#include "memory.h"
++#include "linklist.h"
++#include "keychain.h"
++#include "prefix.h"
++#include "if.h"
++#include "table.h"
++#include "sockunion.h"
++#include "stream.h"
++#include "log.h"
++#include "sockopt.h"
++#include "checksum.h"
++#include "md5.h"
++#include "sha256.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_network.h"
++#include "eigrpd/eigrp_topology.h"
++#include "eigrpd/eigrp_fsm.h"
++
++/* Packet Type String. */
++const struct message eigrp_packet_type_str[] =
++{
++  { EIGRP_OPC_UPDATE,	"Update"		},
++  { EIGRP_OPC_REQUEST,	"Request"		},
++  { EIGRP_OPC_QUERY,	"Query"			},
++  { EIGRP_OPC_REPLY,	"Reply"			},
++  { EIGRP_OPC_HELLO,	"Hello"			},
++  { EIGRP_OPC_IPXSAP,	"IPX-SAP"		},
++  { EIGRP_OPC_PROBE,	"Probe"			},
++  { EIGRP_OPC_ACK,		"Ack"			},
++  { EIGRP_OPC_SIAQUERY,	"SIAQuery"		},
++  { EIGRP_OPC_SIAREPLY,	"SIAReply"		},
++};
++const size_t eigrp_packet_type_str_max = sizeof(eigrp_packet_type_str) /
++  sizeof(eigrp_packet_type_str[0]);
++
++static unsigned char zeropad[16] = {0};
++
++/* Forward function reference*/
++static struct stream * eigrp_recv_packet (int, struct interface **, struct stream *);
++static int eigrp_verify_header (struct stream *, struct eigrp_interface *, struct ip *,
++				struct eigrp_header *);
++static int eigrp_check_network_mask (struct eigrp_interface *, struct in_addr);
++
++
++static int eigrp_retrans_count_exceeded(struct eigrp_packet *ep, struct eigrp_neighbor *nbr)
++{
++  return 1;
++}
++
++int
++eigrp_make_md5_digest (struct eigrp_interface *ei, struct stream *s, u_char flags)
++{
++
++  struct key *key;
++  struct keychain *keychain;
++
++  unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN];
++  MD5_CTX ctx;
++  void *ibuf;
++  size_t backup_get, backup_end;
++  struct TLV_MD5_Authentication_Type *auth_TLV;
++
++  ibuf = s->data;
++  backup_end = s->endp;
++  backup_get = s->getp;
++
++  auth_TLV = eigrp_authTLV_MD5_new();
++
++  stream_set_getp(s,EIGRP_HEADER_LEN);
++  stream_get(auth_TLV,s,EIGRP_AUTH_MD5_TLV_SIZE);
++  stream_set_getp(s, backup_get);
++
++  keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
++   if(keychain)
++     key = key_lookup_for_send(keychain);
++
++   memset(&ctx, 0, sizeof(ctx));
++   MD5Init(&ctx);
++
++   /* Generate a digest. Each situation needs different handling */
++   if(flags & EIGRP_AUTH_BASIC_HELLO_FLAG)
++     {
++       MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
++       MD5Update(&ctx, key->string, strlen(key->string));
++       if(strlen(key->string) < 16)
++         MD5Update(&ctx, zeropad, 16 - strlen(key->string));
++     }
++   else if(flags & EIGRP_AUTH_UPDATE_INIT_FLAG)
++     {
++       MD5Update(&ctx, ibuf, EIGRP_MD5_UPDATE_INIT_COMPUTE);
++     }
++   else if(flags & EIGRP_AUTH_UPDATE_FLAG)
++     {
++       MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
++       MD5Update(&ctx, key->string, strlen(key->string));
++       if(strlen(key->string) < 16)
++         MD5Update(&ctx, zeropad, 16 - strlen(key->string));
++       if(backup_end > (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE))
++         {
++           MD5Update(&ctx, ibuf + (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE),
++               backup_end - 20 - (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE));
++         }
++     }
++
++   MD5Final(digest, &ctx);
++
++  /* Append md5 digest to the end of the stream. */
++  memcpy(auth_TLV->digest,digest,EIGRP_AUTH_TYPE_MD5_LEN);
++
++  stream_set_endp(s,EIGRP_HEADER_LEN);
++  stream_put(s,auth_TLV,EIGRP_AUTH_MD5_TLV_SIZE);
++  stream_set_endp(s, backup_end);
++
++  eigrp_authTLV_MD5_free(auth_TLV);
++  return EIGRP_AUTH_TYPE_MD5_LEN;
++}
++
++int
++eigrp_check_md5_digest (struct stream *s, struct TLV_MD5_Authentication_Type *authTLV,struct eigrp_neighbor *nbr, u_char flags)
++{
++  MD5_CTX ctx;
++  unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN];
++  struct key *key;
++  struct keychain *keychain;
++  void *ibuf;
++  size_t backup_end;
++  struct TLV_MD5_Authentication_Type *auth_TLV;
++  struct eigrp_header *eigrph;
++
++
++  if (nbr && ntohl(nbr->crypt_seqnum) > ntohl(authTLV->key_sequence))
++    {
++      zlog_warn ("interface %s: eigrp_check_md5 bad sequence %d (expect %d)",
++                 IF_NAME (nbr->ei),
++                 ntohl(authTLV->key_sequence),
++                 ntohl(nbr->crypt_seqnum));
++      return 0;
++    }
++
++  eigrph = (struct eigrp_header *) s->data;
++  eigrph->checksum = 0;
++
++  auth_TLV =(struct TLV_MD5_Authentication_Type *) (s->data + EIGRP_HEADER_LEN);
++  memcpy(auth_TLV->digest, "0", sizeof(auth_TLV->digest));
++
++  ibuf = s->data;
++  backup_end = s->endp;
++
++  keychain = keychain_lookup(IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain);
++     if(keychain)
++       key = key_lookup_for_send(keychain);
++
++  memset(&ctx, 0, sizeof(ctx));
++  MD5Init(&ctx);
++
++  /* Generate a digest. Each situation needs different handling */
++  if(flags & EIGRP_AUTH_BASIC_HELLO_FLAG)
++    {
++      MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
++      MD5Update(&ctx, key->string, strlen(key->string));
++      if(strlen(key->string) < 16)
++        MD5Update(&ctx, zeropad, 16 - strlen(key->string));
++    }
++  else if(flags & EIGRP_AUTH_UPDATE_INIT_FLAG)
++    {
++      MD5Update(&ctx, ibuf, EIGRP_MD5_UPDATE_INIT_COMPUTE);
++    }
++  else if(flags & EIGRP_AUTH_UPDATE_FLAG)
++    {
++      MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
++      MD5Update(&ctx, key->string, strlen(key->string));
++      if(strlen(key->string) < 16)
++        MD5Update(&ctx, zeropad, 16 - strlen(key->string));
++      if(backup_end > (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE))
++        {
++          MD5Update(&ctx, ibuf + (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE),
++              backup_end - 20 - (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE));
++        }
++    }
++
++  MD5Final(digest, &ctx);
++
++  /* compare the two */
++  if (memcmp (authTLV->digest, digest, EIGRP_AUTH_TYPE_MD5_LEN) == 0)
++    {
++      zlog_debug("VSETKO OK");
++    }
++  else
++    {
++      zlog_warn ("interface %s: eigrp_check_md5 checksum mismatch",
++                       IF_NAME (nbr->ei));
++      return 0;
++    }
++
++  /* save neighbor's crypt_seqnum */
++  if (nbr)
++    nbr->crypt_seqnum = authTLV->key_sequence;
++
++  return 1;
++}
++
++static int
++strnzcpyn(char *dst, const char *src, int size)
++{
++        char *dptr;
++        if (!size) return 0;
++
++        dptr = dst;
++
++        while (--size)
++                if (!(*dptr++ = *src++)) return (dptr-dst)-1;
++        *dptr = 0;
++
++        return (dptr-dst)-1;
++}
++
++int
++eigrp_make_sha256_digest (struct eigrp_interface *ei, struct stream *s, u_char flags)
++{
++    struct key *key;
++    struct keychain *keychain;
++    char *source_ip;
++    int saved_len;
++    char saved_key[PLAINTEXT_LENGTH + 1];
++
++
++    unsigned char digest[EIGRP_AUTH_TYPE_SHA256_LEN];
++    unsigned char buffer[1 + PLAINTEXT_LENGTH + 45 + 1] = { 0 };
++    HMAC_SHA256_CTX ctx;
++    void *ibuf;
++    size_t backup_get, backup_end;
++    struct TLV_SHA256_Authentication_Type *auth_TLV;
++
++    ibuf = s->data;
++    backup_end = s->endp;
++    backup_get = s->getp;
++
++    auth_TLV = eigrp_authTLV_SHA256_new ();
++
++    stream_set_getp(s,EIGRP_HEADER_LEN);
++    stream_get(auth_TLV,s,EIGRP_AUTH_SHA256_TLV_SIZE);
++    stream_set_getp(s, backup_get);
++
++    keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
++     if(keychain)
++       key = key_lookup_for_send(keychain);
++
++//     saved_len[index] = strnzcpyn(saved_key[index], key,
++//                             PLAINTEXT_LENGTH + 1);
++
++     source_ip = calloc(16, sizeof(char));
++     inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, 16);
++
++     memset(&ctx, 0, sizeof(ctx));
++     buffer[0] = '\n';
++     memcpy(buffer + 1, key, strlen (key->string));
++     memcpy(buffer + 1 + strlen(key->string), source_ip, strlen(source_ip));
++     HMAC__SHA256_Init(&ctx, buffer, 1 + strlen (key->string) + strlen(source_ip));
++     HMAC__SHA256_Update(&ctx, ibuf, strlen(ibuf));
++     HMAC__SHA256_Final(digest, &ctx);
++
++
++     /* Put hmac-sha256 digest to it's place */
++     memcpy(auth_TLV->digest,digest,EIGRP_AUTH_TYPE_SHA256_LEN);
++
++     stream_set_endp(s,EIGRP_HEADER_LEN);
++     stream_put(s,auth_TLV,EIGRP_AUTH_SHA256_TLV_SIZE);
++     stream_set_endp(s, backup_end);
++
++     eigrp_authTLV_SHA256_free(auth_TLV);
++     free(source_ip);
++
++    return EIGRP_AUTH_TYPE_SHA256_LEN;
++}
++
++int
++eigrp_check_sha256_digest (struct stream *s, struct TLV_SHA256_Authentication_Type *authTLV,struct eigrp_neighbor *nbr, u_char flags)
++{
++
++  return 1;
++}
++/*
++ * eigrp_packet_dump
++ *
++ * This routing dumps the contents of the IP packet either received or
++ * built by EIGRP.
++ */
++static void
++eigrp_packet_dump (struct stream *s)
++{
++    // not yet...
++    return;
++}
++
++/*
++ * Converts a 24-bit integer represented as an unsigned char[3] *value
++ * in network byte order into uint32_t in host byte order
++ */
++//static uint32_t u24_32 (const unsigned char *value)
++//{
++//  return (value[0] << 16) + (value[1] << 8) + value[2];
++//}
++//
++///*
++// * Converts an uint32_t value in host byte order into a 24-bit integer
++// * in network byte order represented by unsigned char[3] *result
++// */
++//static unsigned char * u32_24 (uint32_t value, unsigned char *result)
++//{
++//  value = htonl(value & 0x00FFFFFF);
++//  memcpy (result, (unsigned char *) &value + 1, 3);
++//
++//  return result;
++//}
++
++int
++eigrp_write (struct thread *thread)
++{
++  struct eigrp *eigrp = THREAD_ARG(thread);
++  struct eigrp_header *eigrph;
++  struct eigrp_interface *ei;
++  struct eigrp_packet *ep;
++  struct sockaddr_in sa_dst;
++  struct ip iph;
++  struct msghdr msg;
++  struct iovec iov[2];
++  u_int16_t opcode = 0;
++
++  int ret;
++  int flags = 0;
++  struct listnode *node;
++#ifdef WANT_EIGRP_WRITE_FRAGMENT
++  static u_int16_t ipid = 0;
++#endif /* WANT_EIGRP_WRITE_FRAGMENT */
++#define EIGRP_WRITE_IPHL_SHIFT 2
++
++  eigrp->t_write = NULL;
++
++  node = listhead(eigrp->oi_write_q);
++  assert(node);
++  ei = listgetdata(node);
++  assert(ei);
++
++#ifdef WANT_EIGRP_WRITE_FRAGMENT
++  /* seed ipid static with low order bits of time */
++  if (ipid == 0)
++  ipid = (time(NULL) & 0xffff);
++#endif /* WANT_EIGRP_WRITE_FRAGMENT */
++
++  /* Get one packet from queue. */
++  ep = eigrp_fifo_head(ei->obuf);
++  assert(ep);
++  assert(ep->length >= EIGRP_HEADER_LEN);
++
++  if (ep->dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS))
++    eigrp_if_ipmulticast(eigrp, ei->address, ei->ifp->ifindex);
++
++  memset(&iph, 0, sizeof(struct ip));
++  memset(&sa_dst, 0, sizeof(sa_dst));
++
++  sa_dst.sin_family = AF_INET;
++#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
++  sa_dst.sin_len = sizeof(sa_dst);
++#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
++  sa_dst.sin_addr = ep->dst;
++  sa_dst.sin_port = htons(0);
++
++  /* Set DONTROUTE flag if dst is unicast. */
++  if (!IN_MULTICAST(htonl(ep->dst.s_addr)))
++    flags = MSG_DONTROUTE;
++
++  iph.ip_hl = sizeof(struct ip) >> EIGRP_WRITE_IPHL_SHIFT;
++  /* it'd be very strange for header to not be 4byte-word aligned but.. */
++  if (sizeof(struct ip) > (unsigned int)(iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT))
++    iph.ip_hl++; /* we presume sizeof struct ip cant overflow ip_hl.. */
++
++  iph.ip_v = IPVERSION;
++  iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
++  iph.ip_len = (iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT) + ep->length;
++
++#if defined (__DragonFly__)
++  /*
++   * DragonFly's raw socket expects ip_len/ip_off in network byte order.
++   */
++  iph.ip_len = htons(iph.ip_len);
++#endif
++
++  iph.ip_off = 0;
++  iph.ip_ttl = EIGRP_IP_TTL;
++  iph.ip_p = IPPROTO_EIGRPIGP;
++  iph.ip_sum = 0;
++  iph.ip_src.s_addr = ei->address->u.prefix4.s_addr;
++  iph.ip_dst.s_addr = ep->dst.s_addr;
++
++  memset(&msg, 0, sizeof(msg));
++  msg.msg_name = (caddr_t) &sa_dst;
++  msg.msg_namelen = sizeof(sa_dst);
++  msg.msg_iov = iov;
++  msg.msg_iovlen = 2;
++
++  iov[0].iov_base = (char*)&iph;
++  iov[0].iov_len = iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT;
++  iov[1].iov_base = STREAM_PNT(ep->s);
++  iov[1].iov_len = ep->length;
++
++  /* send final fragment (could be first) */
++  sockopt_iphdrincl_swab_htosys(&iph);
++  ret = sendmsg(eigrp->fd, &msg, flags);
++  sockopt_iphdrincl_swab_systoh(&iph);
++
++  if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND))
++    {
++      eigrph = (struct eigrp_header *) STREAM_DATA(ep->s);
++      opcode = eigrph->opcode;
++      zlog_debug("Sending [%s] to [%s] via [%s] ret [%d].",
++		 LOOKUP(eigrp_packet_type_str, opcode), inet_ntoa(ep->dst),
++		 IF_NAME(ei), ret);
++    }
++
++  if (ret < 0)
++    zlog_warn("*** sendmsg in eigrp_write failed to %s, "
++	      "id %d, off %d, len %d, interface %s, mtu %u: %s",
++	      inet_ntoa(iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len, ei->ifp->name,
++	      ei->ifp->mtu, safe_strerror(errno));
++
++  /* Show debug sending packet. */
++  if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND) && (IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL)))
++    {
++      zlog_debug("-----------------------------------------------------");
++      eigrp_ip_header_dump(&iph);
++      stream_set_getp(ep->s, 0);
++      eigrp_packet_dump(ep->s);
++      zlog_debug("-----------------------------------------------------");
++    }
++
++  /* Now delete packet from queue. */
++  eigrp_packet_delete(ei);
++
++  if (eigrp_fifo_head(ei->obuf) == NULL)
++    {
++      ei->on_write_q = 0;
++      list_delete_node(eigrp->oi_write_q, node);
++    }
++
++  /* If packets still remain in queue, call write thread. */
++  if (!list_isempty(eigrp->oi_write_q))
++    eigrp->t_write = thread_add_write(master, eigrp_write, eigrp, eigrp->fd);
++
++  return 0;
++}
++
++/* Starting point of packet process function. */
++int
++eigrp_read (struct thread *thread)
++{
++  int ret;
++  struct stream *ibuf;
++  struct eigrp *eigrp;
++  struct eigrp_interface *ei;
++  struct ip *iph;
++  struct eigrp_header *eigrph;
++  struct interface *ifp;
++  struct eigrp_neighbor *nbr;
++
++  u_int16_t opcode = 0;
++  u_int16_t length = 0;
++
++  /* first of all get interface pointer. */
++  eigrp = THREAD_ARG(thread);
++
++  /* prepare for next packet. */
++  eigrp->t_read = thread_add_read(master, eigrp_read, eigrp, eigrp->fd);
++
++  stream_reset(eigrp->ibuf);
++  if (!(ibuf = eigrp_recv_packet(eigrp->fd, &ifp, eigrp->ibuf)))
++    {
++      /* This raw packet is known to be at least as big as its IP header. */
++      return -1;
++    }
++
++  /* Note that there should not be alignment problems with this assignment
++   because this is at the beginning of the stream data buffer. */
++  iph = (struct ip *)STREAM_DATA(ibuf);
++
++  //Substract IPv4 header size from EIGRP Packet itself
++  if(iph->ip_v == 4)
++  length = (iph->ip_len) - 20U;
++
++
++  /* IP Header dump. */
++  if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV) && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
++      eigrp_ip_header_dump(iph);
++
++  /* Note that sockopt_iphdrincl_swab_systoh was called in eigrp_recv_packet. */
++  if (ifp == NULL)
++    {
++      /* Handle cases where the platform does not support retrieving the ifindex,
++	 and also platforms (such as Solaris 8) that claim to support ifindex
++	 retrieval but do not. */
++      ifp = if_lookup_address(iph->ip_src);
++
++      if (ifp == NULL)
++	return 0;
++    }
++
++  /* associate packet with eigrp interface */
++  ei = eigrp_if_lookup_recv_if(eigrp, iph->ip_src, ifp);
++
++  /* eigrp_verify_header() relies on a valid "ei" and thus can be called only
++     after the checks below are passed. These checks in turn access the
++     fields of unverified "eigrph" structure for their own purposes and
++     must remain very accurate in doing this. 
++  */
++  if (!ei)
++    return 0;
++
++  /* Self-originated packet should be discarded silently. */
++  if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src) ||
++      (IPV4_ADDR_SAME(&iph->ip_src.s_addr, &ei->address->u.prefix4)))
++    {
++      if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
++	zlog_debug("eigrp_read[%s]: Dropping self-originated packet",
++		   inet_ntoa(iph->ip_src));
++      return 0;
++    }
++
++  /* Advance from IP header to EIGRP header (iph->ip_hl has been verified
++   by eigrp_recv_packet() to be correct). */
++
++  stream_forward_getp(ibuf, (iph->ip_hl * 4));
++  eigrph = (struct eigrp_header *) STREAM_PNT(ibuf);
++
++  if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV) && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
++    eigrp_header_dump(eigrph);
++
++//  if (MSG_OK != eigrp_packet_examin(eigrph, stream_get_endp(ibuf) - stream_get_getp(ibuf)))
++//    return -1;
++
++  /* Now it is safe to access all fields of EIGRP packet header. */
++  /* associate packet with eigrp interface */
++  ei = eigrp_if_lookup_recv_if(eigrp, iph->ip_src, ifp);
++
++  /* eigrp_verify_header() relies on a valid "ei" and thus can be called only
++    after the checks below are passed. These checks in turn access the
++    fields of unverified "eigrph" structure for their own purposes and
++    must remain very accurate in doing this.
++   */
++  if (!ei)
++    return 0;
++
++  /* If incoming interface is passive one, ignore it. */
++  if (ei && EIGRP_IF_PASSIVE_STATUS(ei) == EIGRP_IF_PASSIVE)
++    {
++      char buf[3][INET_ADDRSTRLEN];
++
++      if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
++	zlog_debug("ignoring packet from router %s sent to %s, "
++		   "received on a passive interface, %s",
++		   inet_ntop(AF_INET, &eigrph->vrid, buf[0], sizeof(buf[0])),
++		   inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])),
++		   inet_ntop(AF_INET, &ei->address->u.prefix4,
++			     buf[2], sizeof(buf[2])));
++
++      if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS))
++        {
++	  /* Try to fix multicast membership.
++	   * Some OS:es may have problems in this area,
++	   * make sure it is removed.
++	   */
++	  EI_MEMBER_JOINED(ei, MEMBER_ALLROUTERS);
++	  eigrp_if_set_multicast(ei);
++	}
++      return 0;
++    }
++
++  /* else it must be a local eigrp interface, check it was received on
++   * correct link
++   */
++  else if (ei->ifp != ifp)
++    {
++      if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
++        zlog_warn("Packet from [%s] received on wrong link %s",
++		   inet_ntoa(iph->ip_src), ifp->name);
++      return 0;
++    }
++
++  /* Verify more EIGRP header fields. */
++  ret = eigrp_verify_header(ibuf, ei, iph, eigrph);
++  if (ret < 0)
++    {
++      if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
++        zlog_debug("eigrp_read[%s]: Header check failed, dropping.",
++                   inet_ntoa(iph->ip_src));
++      return ret;
++    }
++
++  /* calcualte the eigrp packet length, and move the pounter to the
++     start of the eigrp TLVs */
++  opcode = eigrph->opcode;
++
++  if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
++    zlog_debug("Received [%s] length [%u] via [%s] src [%s] dst [%s]",
++	       LOOKUP(eigrp_packet_type_str, opcode), length,
++	       IF_NAME(ei), inet_ntoa(iph->ip_src), inet_ntoa(iph->ip_dst));
++
++  /* Read rest of the packet and call each sort of packet routine. */
++  stream_forward_getp(ibuf, EIGRP_HEADER_LEN);
++
++
++  /* New testing block of code for handling Acks */
++  if (ntohl(eigrph->ack) != 0)
++    {
++      nbr = eigrp_nbr_get(ei, eigrph, iph);
++
++      /* neighbor must be valid, eigrp_nbr_get creates if none existed */
++      assert(nbr);
++
++     struct eigrp_packet *ep;
++
++     ep = eigrp_fifo_tail(nbr->retrans_queue);
++     if (ep != NULL)
++       {
++         if (ntohl(eigrph->ack) == ep->sequence_number)
++           {
++             if((nbr->state == EIGRP_NEIGHBOR_PENDING) && (ntohl(eigrph->ack) == nbr->init_sequence_number))
++               {
++                 eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_UP);
++                 zlog_info("Neighbor adjacency became full");
++                 nbr->init_sequence_number = 0;
++                 nbr->recv_sequence_number = ntohl(eigrph->sequence);
++                 eigrp_update_send_EOT(nbr);
++               }
++             ep = eigrp_fifo_pop_tail(nbr->retrans_queue);
++             /*eigrp_packet_free(ep);*/
++             if (nbr->retrans_queue->count > 0)
++               {
++                 eigrp_send_packet_reliably(nbr);
++               }
++           }
++       }
++     ep = eigrp_fifo_tail(nbr->multicast_queue);
++     if (ep != NULL)
++       {
++         if (ntohl(eigrph->ack) == ep->sequence_number)
++           {
++             ep = eigrp_fifo_pop_tail(nbr->multicast_queue);
++             eigrp_packet_free(ep);
++             if (nbr->multicast_queue->count > 0)
++               {
++                 eigrp_send_packet_reliably(nbr);
++               }
++           }
++       }
++    }
++
++
++  switch (opcode)
++    {
++    case EIGRP_OPC_HELLO:
++      eigrp_hello_receive(eigrp, iph, eigrph, ibuf, ei, length);
++      break;
++    case EIGRP_OPC_PROBE:
++      //      eigrp_probe_receive(eigrp, iph, eigrph, ibuf, ei, length);
++      break;
++    case EIGRP_OPC_QUERY:
++      eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length);
++      break;
++    case EIGRP_OPC_REPLY:
++      eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length);
++      break;
++    case EIGRP_OPC_REQUEST:
++      //      eigrp_request_receive(eigrp, iph, eigrph, ibuf, ei, length);
++      break;
++    case EIGRP_OPC_SIAQUERY:
++      eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length);
++      break;
++    case EIGRP_OPC_SIAREPLY:
++      eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length);
++      break;
++    case EIGRP_OPC_UPDATE:
++      eigrp_update_receive(eigrp, iph, eigrph, ibuf, ei, length);
++      break;
++    default:
++      zlog(NULL, LOG_WARNING,
++	    "interface %s: EIGRP packet header type %d unsupported",
++	    IF_NAME(ei), opcode);
++      break;
++    }
++
++  return 0;
++}
++
++static struct stream *
++eigrp_recv_packet (int fd, struct interface **ifp, struct stream *ibuf)
++{
++  int ret;
++  struct ip *iph;
++  u_int16_t ip_len;
++  unsigned int ifindex = 0;
++  struct iovec iov;
++  /* Header and data both require alignment. */
++  char buff[CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())];
++  struct msghdr msgh;
++
++  memset(&msgh, 0, sizeof(struct msghdr));
++  msgh.msg_iov = &iov;
++  msgh.msg_iovlen = 1;
++  msgh.msg_control = (caddr_t) buff;
++  msgh.msg_controllen = sizeof(buff);
++
++  ret = stream_recvmsg(ibuf, fd, &msgh, 0, (EIGRP_PACKET_MAX_LEN + 1));
++  if (ret < 0)
++    {
++      zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno));
++      return NULL;
++    }
++  if ((unsigned int) ret < sizeof(iph)) /* ret must be > 0 now */
++    {
++      zlog_warn("eigrp_recv_packet: discarding runt packet of length %d "
++          "(ip header size is %u)", ret, (u_int) sizeof(iph));
++      return NULL;
++    }
++
++  /* Note that there should not be alignment problems with this assignment
++   because this is at the beginning of the stream data buffer. */
++  iph = (struct ip *) STREAM_DATA(ibuf);
++  sockopt_iphdrincl_swab_systoh(iph);
++
++  ip_len = iph->ip_len;
++
++#if !defined (GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000)
++  /*
++   * Kernel network code touches incoming IP header parameters,
++   * before protocol specific processing.
++   *
++   *   1) Convert byteorder to host representation.
++   *      --> ip_len, ip_id, ip_off
++   *
++   *   2) Adjust ip_len to strip IP header size!
++   *      --> If user process receives entire IP packet via RAW
++   *          socket, it must consider adding IP header size to
++   *          the "ip_len" field of "ip" structure.
++   *
++   * For more details, see <netinet/ip_input.c>.
++   */
++  ip_len = ip_len + (iph->ip_hl << 2);
++#endif
++
++#if defined (__DragonFly__)
++  /*
++   * in DragonFly's raw socket, ip_len/ip_off are read
++   * in network byte order.
++   * As OpenBSD < 200311 adjust ip_len to strip IP header size!
++   */
++  ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2);
++#endif
++
++  ifindex = getsockopt_ifindex(AF_INET, &msgh);
++
++  *ifp = if_lookup_by_index(ifindex);
++
++  if (ret != ip_len)
++    {
++      zlog_warn("eigrp_recv_packet read length mismatch: ip_len is %d, "
++		"but recvmsg returned %d", ip_len, ret);
++      return NULL;
++    }
++
++  return ibuf;
++}
++
++struct eigrp_fifo *
++eigrp_fifo_new (void)
++{
++  struct eigrp_fifo *new;
++
++  new = XCALLOC(MTYPE_EIGRP_FIFO, sizeof(struct eigrp_fifo));
++  return new;
++}
++
++/* Free eigrp packet fifo. */
++void
++eigrp_fifo_free (struct eigrp_fifo *fifo)
++{
++  struct eigrp_packet *ep;
++  struct eigrp_packet *next;
++
++  for (ep = fifo->head; ep; ep = next)
++    {
++      next = ep->next;
++      eigrp_packet_free(ep);
++    }
++  fifo->head = fifo->tail = NULL;
++  fifo->count = 0;
++
++  XFREE(MTYPE_EIGRP_FIFO, fifo);
++}
++
++/* Free eigrp fifo entries without destroying fifo itself*/
++void
++eigrp_fifo_reset (struct eigrp_fifo *fifo)
++{
++  struct eigrp_packet *ep;
++  struct eigrp_packet *next;
++
++  for (ep = fifo->head; ep; ep = next)
++    {
++      next = ep->next;
++      eigrp_packet_free(ep);
++    }
++  fifo->head = fifo->tail = NULL;
++  fifo->count = 0;
++}
++
++struct eigrp_packet *
++eigrp_packet_new (size_t size)
++{
++  struct eigrp_packet *new;
++
++  new = XCALLOC(MTYPE_EIGRP_PACKET, sizeof(struct eigrp_packet));
++  new->s = stream_new(size);
++  new->retrans_counter = 0;
++
++  return new;
++}
++
++void
++eigrp_send_packet_reliably (struct eigrp_neighbor *nbr)
++{
++  struct eigrp_packet *ep;
++
++  ep = eigrp_fifo_tail(nbr->retrans_queue);
++
++  if (ep)
++    {
++      struct eigrp_packet *duplicate;
++      duplicate = eigrp_packet_duplicate(ep, nbr);
++      /* Add packet to the top of the interface output queue*/
++      eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
++
++      /*Start retransmission timer*/
++      THREAD_TIMER_ON(master, ep->t_retrans_timer, eigrp_unack_packet_retrans,
++          nbr, EIGRP_PACKET_RETRANS_TIME);
++
++      /*Increment sequence number counter*/
++      nbr->ei->eigrp->sequence_number++;
++
++      /* Hook thread to write packet. */
++      if (nbr->ei->on_write_q == 0)
++        {
++          listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
++          nbr->ei->on_write_q = 1;
++        }
++      if (nbr->ei->eigrp->t_write == NULL)
++        nbr->ei->eigrp->t_write =
++            thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
++    }
++}
++
++/* Calculate EIGRP checksum */
++void
++eigrp_packet_checksum (struct eigrp_interface *ei, struct stream *s,
++		       u_int16_t length)
++{
++  struct eigrp_header *eigrph;
++
++  eigrph = (struct eigrp_header *) STREAM_DATA(s);
++
++  /* Calculate checksum. */
++  eigrph->checksum = in_cksum(eigrph, length);
++}
++
++/* Make EIGRP header. */
++void
++eigrp_packet_header_init (int type, struct eigrp_interface *ei, struct stream *s,
++			  u_int32_t flags, u_int32_t sequence, u_int32_t ack)
++{
++  struct eigrp_header *eigrph;
++
++  eigrph = (struct eigrp_header *) STREAM_DATA(s);
++
++  eigrph->version = (u_char) EIGRP_HEADER_VERSION;
++  eigrph->opcode = (u_char) type;
++  eigrph->checksum = 0;
++
++  eigrph->vrid = htons(ei->eigrp->vrid);
++  eigrph->ASNumber = htons(ei->eigrp->AS);
++  eigrph->ack = htonl(ack);
++  eigrph->sequence = htonl(sequence);
++//  if(flags == EIGRP_INIT_FLAG)
++//    eigrph->sequence = htonl(3);
++  eigrph->flags = htonl(flags);
++
++  if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
++    zlog_debug("Packet Header Init Seq [%u] Ack [%u]",
++	       htonl(eigrph->sequence), htonl(eigrph->ack));
++
++  stream_forward_endp(s, EIGRP_HEADER_LEN);
++}
++
++/* Add new packet to head of fifo. */
++void
++eigrp_fifo_push_head (struct eigrp_fifo *fifo, struct eigrp_packet *ep)
++{
++  ep->next = fifo->head;
++  ep->previous = NULL;
++
++  if (fifo->tail == NULL)
++    fifo->tail = ep;
++
++  if (fifo->count != 0)
++    fifo->head->previous = ep;
++
++  fifo->head = ep;
++
++  fifo->count++;
++}
++
++/* Return first fifo entry. */
++struct eigrp_packet *
++eigrp_fifo_head (struct eigrp_fifo *fifo)
++{
++  return fifo->head;
++}
++
++/* Return last fifo entry. */
++struct eigrp_packet *
++eigrp_fifo_tail (struct eigrp_fifo *fifo)
++{
++  return fifo->tail;
++}
++
++void
++eigrp_packet_delete (struct eigrp_interface *ei)
++{
++  struct eigrp_packet *ep;
++
++  ep = eigrp_fifo_pop (ei->obuf);
++
++  if (ep)
++    eigrp_packet_free(ep);
++}
++
++/* Delete first packet from fifo. */
++struct eigrp_packet *
++eigrp_fifo_pop (struct eigrp_fifo *fifo)
++{
++  struct eigrp_packet *ep;
++
++  ep = fifo->head;
++
++  if (ep)
++    {
++      fifo->head = ep->next;
++
++      if (fifo->head == NULL)
++        fifo->tail = NULL;
++      else
++        fifo->head->previous = NULL;
++
++      fifo->count--;
++    }
++
++  return ep;
++}
++
++void
++eigrp_packet_free (struct eigrp_packet *ep)
++{
++  if (ep->s)
++    stream_free(ep->s);
++
++  THREAD_OFF(ep->t_retrans_timer);
++
++  XFREE(MTYPE_EIGRP_PACKET, ep);
++
++  ep = NULL;
++}
++
++/* EIGRP Header verification. */
++static int
++eigrp_verify_header (struct stream *ibuf, struct eigrp_interface *ei,
++    struct ip *iph, struct eigrp_header *eigrph)
++{
++
++  /* Check network mask, Silently discarded. */
++  if (!eigrp_check_network_mask(ei, iph->ip_src))
++    {
++      zlog_warn("interface %s: eigrp_read network address is not same [%s]",
++          IF_NAME(ei), inet_ntoa(iph->ip_src));
++      return -1;
++    }
++//
++//  /* Check authentication. The function handles logging actions, where required. */
++//  if (! eigrp_check_auth(ei, eigrph))
++//    return -1;
++
++  return 0;
++}
++
++/* Unbound socket will accept any Raw IP packets if proto is matched.
++ To prevent it, compare src IP address and i/f address with masking
++ i/f network mask. */
++static int
++eigrp_check_network_mask (struct eigrp_interface *ei, struct in_addr ip_src)
++{
++  struct in_addr mask, me, him;
++
++  if (ei->type == EIGRP_IFTYPE_POINTOPOINT)
++    return 1;
++
++  masklen2ip(ei->address->prefixlen, &mask);
++
++  me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr;
++  him.s_addr = ip_src.s_addr & mask.s_addr;
++
++  if (IPV4_ADDR_SAME(&me, &him))
++    return 1;
++
++  return 0;
++}
++
++int
++eigrp_unack_packet_retrans (struct thread *thread)
++{
++  struct eigrp_neighbor *nbr;
++  nbr = (struct eigrp_neighbor *) THREAD_ARG(thread);
++
++  struct eigrp_packet *ep;
++  ep = eigrp_fifo_tail(nbr->retrans_queue);
++
++  if (ep)
++    {
++      struct eigrp_packet *duplicate;
++      duplicate = eigrp_packet_duplicate(ep, nbr);
++
++      /* Add packet to the top of the interface output queue*/
++      eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
++
++      ep->retrans_counter++;
++      if(ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
++        return eigrp_retrans_count_exceeded(ep, nbr);
++
++      /*Start retransmission timer*/
++      ep->t_retrans_timer =
++          thread_add_timer(master, eigrp_unack_packet_retrans, nbr,EIGRP_PACKET_RETRANS_TIME);
++
++      /* Hook thread to write packet. */
++      if (nbr->ei->on_write_q == 0)
++        {
++          listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
++          nbr->ei->on_write_q = 1;
++        }
++      if (nbr->ei->eigrp->t_write == NULL)
++        nbr->ei->eigrp->t_write =
++            thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
++    }
++
++  return 0;
++}
++
++int
++eigrp_unack_multicast_packet_retrans (struct thread *thread)
++{
++  struct eigrp_neighbor *nbr;
++  nbr = (struct eigrp_neighbor *) THREAD_ARG(thread);
++
++  struct eigrp_packet *ep;
++  ep = eigrp_fifo_tail(nbr->multicast_queue);
++
++  if (ep)
++    {
++      struct eigrp_packet *duplicate;
++      duplicate = eigrp_packet_duplicate(ep, nbr);
++      /* Add packet to the top of the interface output queue*/
++      eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
++
++      ep->retrans_counter++;
++      if(ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
++        return eigrp_retrans_count_exceeded(ep, nbr);
++
++      /*Start retransmission timer*/
++      ep->t_retrans_timer =
++          thread_add_timer(master, eigrp_unack_multicast_packet_retrans, nbr,EIGRP_PACKET_RETRANS_TIME);
++
++      /* Hook thread to write packet. */
++      if (nbr->ei->on_write_q == 0)
++        {
++          listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
++          nbr->ei->on_write_q = 1;
++        }
++      if (nbr->ei->eigrp->t_write == NULL)
++        nbr->ei->eigrp->t_write =
++            thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
++    }
++
++  return 0;
++}
++
++/* Get packet from tail of fifo. */
++struct eigrp_packet *
++eigrp_fifo_pop_tail (struct eigrp_fifo *fifo)
++{
++  struct eigrp_packet *ep;
++
++  ep = fifo->tail;
++
++  if (ep)
++    {
++      fifo->tail = ep->previous;
++
++      if (fifo->tail == NULL)
++        fifo->head = NULL;
++      else
++        fifo->tail->next = NULL;
++
++      fifo->count--;
++    }
++
++  return ep;
++}
++
++struct eigrp_packet *
++eigrp_packet_duplicate (struct eigrp_packet *old, struct eigrp_neighbor *nbr)
++{
++  struct eigrp_packet *new;
++
++  new = eigrp_packet_new(nbr->ei->ifp->mtu);
++  new->length = old->length;
++  new->retrans_counter = old->retrans_counter;
++  new->dst = old->dst;
++  new->sequence_number = old->sequence_number;
++  stream_copy(new->s, old->s);
++
++  return new;
++}
++
++struct TLV_IPv4_Internal_type *
++eigrp_read_ipv4_tlv (struct stream *s)
++{
++  struct TLV_IPv4_Internal_type *tlv;
++
++  tlv = eigrp_IPv4_InternalTLV_new ();
++
++  tlv->type = stream_getw(s);
++  tlv->length = stream_getw(s);
++  tlv->forward.s_addr = stream_getl(s);
++  tlv->metric.delay = stream_getl(s);
++  tlv->metric.bandwith = stream_getl(s);
++  tlv->metric.mtu[0] = stream_getc(s);
++  tlv->metric.mtu[1] = stream_getc(s);
++  tlv->metric.mtu[2] = stream_getc(s);
++  tlv->metric.hop_count = stream_getc(s);
++  tlv->metric.reliability = stream_getc(s);
++  tlv->metric.load = stream_getc(s);
++  tlv->metric.tag = stream_getc(s);
++  tlv->metric.flags = stream_getc(s);
++
++  tlv->prefix_length = stream_getc(s);
++
++  if (tlv->prefix_length <= 8)
++    {
++      tlv->destination_part[0] = stream_getc(s);
++      tlv->destination.s_addr = (tlv->destination_part[0]);
++
++    }
++  else if (tlv->prefix_length > 8 && tlv->prefix_length <= 16)
++    {
++      tlv->destination_part[0] = stream_getc(s);
++      tlv->destination_part[1] = stream_getc(s);
++      tlv->destination.s_addr = ((tlv->destination_part[1] << 8)
++          + tlv->destination_part[0]);
++    }
++  else if (tlv->prefix_length > 16 && tlv->prefix_length <= 24)
++    {
++      tlv->destination_part[0] = stream_getc(s);
++      tlv->destination_part[1] = stream_getc(s);
++      tlv->destination_part[2] = stream_getc(s);
++      tlv->destination.s_addr = ((tlv->destination_part[2] << 16)
++          + (tlv->destination_part[1] << 8) + tlv->destination_part[0]);
++    }
++  else if (tlv->prefix_length > 24 && tlv->prefix_length <= 32)
++    {
++      tlv->destination_part[0] = stream_getc(s);
++      tlv->destination_part[1] = stream_getc(s);
++      tlv->destination_part[2] = stream_getc(s);
++      tlv->destination_part[3] = stream_getc(s);
++      tlv->destination.s_addr = ((tlv->destination_part[3] << 24)
++          + (tlv->destination_part[2] << 16) + (tlv->destination_part[1] << 8)
++          + tlv->destination_part[0]);
++    }
++  return tlv;
++}
++
++u_int16_t
++eigrp_add_internalTLV_to_stream (struct stream *s,
++    struct eigrp_prefix_entry *pe)
++{
++  u_int16_t length;
++
++  stream_putw(s, EIGRP_TLV_IPv4_INT);
++  if (pe->destination_ipv4->prefixlen <= 8)
++    {
++      stream_putw(s, 0x001A);
++      length = 0x001A;
++    }
++  if ((pe->destination_ipv4->prefixlen > 8)
++      && (pe->destination_ipv4->prefixlen <= 16))
++    {
++      stream_putw(s, 0x001B);
++      length = 0x001B;
++    }
++  if ((pe->destination_ipv4->prefixlen > 16)
++      && (pe->destination_ipv4->prefixlen <= 24))
++    {
++      stream_putw(s, 0x001C);
++      length = 0x001C;
++    }
++  if (pe->destination_ipv4->prefixlen > 24)
++    {
++      stream_putw(s, 0x001D);
++      length = 0x001D;
++    }
++
++  stream_putl(s, 0x00000000);
++
++  /*Metric*/
++  stream_putl(s, pe->reported_metric.delay);
++  stream_putl(s, pe->reported_metric.bandwith);
++  stream_putc(s, pe->reported_metric.mtu[2]);
++  stream_putc(s, pe->reported_metric.mtu[1]);
++  stream_putc(s, pe->reported_metric.mtu[0]);
++  stream_putc(s, pe->reported_metric.hop_count);
++  stream_putc(s, pe->reported_metric.reliability);
++  stream_putc(s, pe->reported_metric.load);
++  stream_putc(s, pe->reported_metric.tag);
++  stream_putc(s, pe->reported_metric.flags);
++
++  stream_putc(s, pe->destination_ipv4->prefixlen);
++
++  if (pe->destination_ipv4->prefixlen <= 8)
++    {
++      stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
++    }
++  if ((pe->destination_ipv4->prefixlen > 8)
++      && (pe->destination_ipv4->prefixlen <= 16))
++    {
++      stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
++      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
++    }
++  if ((pe->destination_ipv4->prefixlen > 16)
++      && (pe->destination_ipv4->prefixlen <= 24))
++    {
++      stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
++      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
++      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF);
++    }
++  if (pe->destination_ipv4->prefixlen > 24)
++    {
++      stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
++      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
++      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF);
++      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 24) & 0xFF);
++    }
++
++  return length;
++}
++
++u_int16_t
++eigrp_add_authTLV_MD5_to_stream (struct stream *s,
++    struct eigrp_interface *ei)
++{
++  struct key *key;
++  struct keychain *keychain;
++  struct TLV_MD5_Authentication_Type *authTLV;
++
++  authTLV = eigrp_authTLV_MD5_new();
++
++  authTLV->type = htons(EIGRP_TLV_AUTH);
++  authTLV->length = htons(EIGRP_AUTH_MD5_TLV_SIZE);
++  authTLV->auth_type = htons(EIGRP_AUTH_TYPE_MD5);
++  authTLV->auth_length = htons(EIGRP_AUTH_TYPE_MD5_LEN);
++  authTLV->key_sequence = 0;
++  memset(authTLV->Nullpad,0,sizeof(authTLV->Nullpad));
++
++
++  keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
++  if(keychain)
++    key = key_lookup_for_send(keychain);
++  else
++    {
++      free(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
++      IF_DEF_PARAMS (ei->ifp)->auth_keychain = NULL;
++      eigrp_authTLV_MD5_free(authTLV);
++      return 0;
++    }
++
++  if(key)
++    {
++      authTLV->key_id = htonl(key->index);
++      memset(authTLV->digest,0,EIGRP_AUTH_TYPE_MD5_LEN);
++      stream_put(s,authTLV, sizeof(struct TLV_MD5_Authentication_Type));
++      eigrp_authTLV_MD5_free(authTLV);
++      return EIGRP_AUTH_MD5_TLV_SIZE;
++    }
++
++  eigrp_authTLV_MD5_free(authTLV);
++
++  return 0;
++}
++
++u_int16_t
++eigrp_add_authTLV_SHA256_to_stream (struct stream *s,
++    struct eigrp_interface *ei)
++{
++  struct key *key;
++  struct keychain *keychain;
++  struct TLV_SHA256_Authentication_Type *authTLV;
++
++  authTLV = eigrp_authTLV_SHA256_new();
++
++  authTLV->type = htons(EIGRP_TLV_AUTH);
++  authTLV->length = htons(EIGRP_AUTH_SHA256_TLV_SIZE);
++  authTLV->auth_type = htons(EIGRP_AUTH_TYPE_SHA256);
++  authTLV->auth_length = htons(EIGRP_AUTH_TYPE_SHA256_LEN);
++  authTLV->key_sequence = 0;
++  memset(authTLV->Nullpad,0,sizeof(authTLV->Nullpad));
++
++
++  keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
++  if(keychain)
++    key = key_lookup_for_send(keychain);
++  else
++    {
++      free(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
++      IF_DEF_PARAMS (ei->ifp)->auth_keychain = NULL;
++      eigrp_authTLV_SHA256_free(authTLV);
++      return 0;
++    }
++
++  if(key)
++    {
++      authTLV->key_id = 0;
++      memset(authTLV->digest,0,EIGRP_AUTH_TYPE_SHA256_LEN);
++      stream_put(s,authTLV, sizeof(struct TLV_SHA256_Authentication_Type));
++      eigrp_authTLV_SHA256_free(authTLV);
++      return EIGRP_AUTH_SHA256_TLV_SIZE;
++    }
++
++  eigrp_authTLV_SHA256_free(authTLV);
++
++  return 0;
++
++}
++
++struct TLV_MD5_Authentication_Type *
++eigrp_authTLV_MD5_new ()
++{
++  struct TLV_MD5_Authentication_Type *new;
++
++  new = XCALLOC(MTYPE_EIGRP_AUTH_TLV, sizeof(struct TLV_MD5_Authentication_Type));
++
++  return new;
++}
++
++void
++eigrp_authTLV_MD5_free (struct TLV_MD5_Authentication_Type *authTLV)
++{
++
++  XFREE(MTYPE_EIGRP_AUTH_TLV, authTLV);
++}
++
++struct TLV_SHA256_Authentication_Type *
++eigrp_authTLV_SHA256_new ()
++{
++  struct TLV_SHA256_Authentication_Type *new;
++
++  new = XCALLOC(MTYPE_EIGRP_AUTH_SHA256_TLV, sizeof(struct TLV_SHA256_Authentication_Type));
++
++  return new;
++}
++
++void
++eigrp_authTLV_SHA256_free (struct TLV_SHA256_Authentication_Type *authTLV)
++{
++
++  XFREE(MTYPE_EIGRP_AUTH_SHA256_TLV, authTLV);
++}
++
++
++struct TLV_IPv4_Internal_type *
++eigrp_IPv4_InternalTLV_new ()
++{
++  struct TLV_IPv4_Internal_type *new;
++
++  new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV,sizeof(struct TLV_IPv4_Internal_type));
++
++  return new;
++}
++
++void
++eigrp_IPv4_InternalTLV_free (struct TLV_IPv4_Internal_type *IPv4_InternalTLV)
++{
++
++  XFREE(MTYPE_EIGRP_IPV4_INT_TLV, IPv4_InternalTLV);
++}
++
++struct TLV_Sequence_Type *
++eigrp_SequenceTLV_new ()
++{
++  struct TLV_Sequence_Type *new;
++
++  new = XCALLOC(MTYPE_EIGRP_SEQ_TLV,sizeof(struct TLV_Sequence_Type));
++
++  return new;
++}
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_packet.h eigrp/eigrpd/eigrp_packet.h
+--- a/eigrpd/eigrp_packet.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_packet.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,135 @@
++/*
++ * EIGRP General Sending and Receiving of EIGRP Packets.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRP_PACKET_H
++#define _ZEBRA_EIGRP_PACKET_H
++
++/*Prototypes*/
++extern int eigrp_read (struct thread *);
++extern int eigrp_write (struct thread *);
++
++extern struct eigrp_packet *eigrp_packet_new (size_t);
++extern struct eigrp_packet *eigrp_packet_duplicate (struct eigrp_packet *, struct eigrp_neighbor *);
++extern void eigrp_packet_free (struct eigrp_packet *);
++extern void eigrp_packet_delete (struct eigrp_interface *);
++extern void eigrp_packet_header_init (int, struct eigrp_interface *, struct stream *,
++				     u_int32_t, u_int32_t, u_int32_t);
++extern void eigrp_packet_checksum (struct eigrp_interface *, struct stream *, u_int16_t);
++
++extern struct eigrp_fifo *eigrp_fifo_new (void);
++extern struct eigrp_packet *eigrp_fifo_head (struct eigrp_fifo *);
++extern struct eigrp_packet *eigrp_fifo_tail (struct eigrp_fifo *);
++extern struct eigrp_packet *eigrp_fifo_pop (struct eigrp_fifo *);
++extern struct eigrp_packet *eigrp_fifo_pop_tail (struct eigrp_fifo *);
++extern void eigrp_fifo_push_head (struct eigrp_fifo *, struct eigrp_packet *);
++extern void eigrp_fifo_free (struct eigrp_fifo *);
++extern void eigrp_fifo_reset (struct eigrp_fifo *);
++
++extern void eigrp_send_packet_reliably (struct eigrp_neighbor *);
++
++extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv (struct stream *);
++extern u_int16_t eigrp_add_internalTLV_to_stream (struct stream *, struct eigrp_prefix_entry *);
++extern u_int16_t eigrp_add_authTLV_MD5_to_stream (struct stream *, struct eigrp_interface *);
++extern u_int16_t eigrp_add_authTLV_SHA256_to_stream (struct stream *, struct eigrp_interface *);
++
++extern int eigrp_unack_packet_retrans (struct thread *);
++extern int eigrp_unack_multicast_packet_retrans (struct thread *);
++
++/*
++ * untill there is reason to have their own header, these externs are found in
++ * eigrp_hello.c
++ */
++extern void eigrp_hello_send (struct eigrp_interface *, u_char);
++extern void eigrp_hello_send_ack (struct eigrp_neighbor *);
++extern void eigrp_hello_receive (struct eigrp *, struct ip *, struct eigrp_header *,
++				struct stream *, struct eigrp_interface *, int);
++extern int  eigrp_hello_timer (struct thread *);
++
++/*
++ * These externs are found in eigrp_update.c
++ */
++extern void eigrp_update_send (struct eigrp_interface *);
++extern void eigrp_update_receive (struct eigrp *, struct ip *, struct eigrp_header *,
++                                struct stream *, struct eigrp_interface *, int);
++extern void eigrp_update_send_all (struct eigrp *, struct eigrp_interface *);
++extern void eigrp_update_send_init (struct eigrp_neighbor *);
++extern void eigrp_update_send_EOT (struct eigrp_neighbor *);
++
++/*
++ * These externs are found in eigrp_query.c
++ */
++
++extern void eigrp_send_query (struct eigrp_interface *);
++extern void eigrp_query_receive (struct eigrp *, struct ip *, struct eigrp_header *,
++                                 struct stream *, struct eigrp_interface *, int);
++extern u_int32_t eigrp_query_send_all (struct eigrp *);
++
++/*
++ * These externs are found in eigrp_reply.c
++ */
++extern void eigrp_send_reply (struct eigrp_neighbor *, struct eigrp_prefix_entry *);
++extern void eigrp_reply_receive (struct eigrp *, struct ip *, struct eigrp_header *,
++                                 struct stream *, struct eigrp_interface *, int);
++
++/*
++ * These externs are found in eigrp_siaquery.c
++ */
++extern void eigrp_send_siaquery (struct eigrp_neighbor *, struct eigrp_prefix_entry *);
++extern void eigrp_siaquery_receive (struct eigrp *, struct ip *, struct eigrp_header *,
++                     struct stream *, struct eigrp_interface *, int);
++
++/*
++ * These externs are found in eigrp_siareply.c
++ */
++extern void eigrp_send_siareply (struct eigrp_neighbor *, struct eigrp_prefix_entry *);
++extern void eigrp_siareply_receive (struct eigrp *, struct ip *, struct eigrp_header *,
++                     struct stream *, struct eigrp_interface *, int);
++
++extern struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new (void);
++extern void eigrp_authTLV_MD5_free (struct TLV_MD5_Authentication_Type *);
++extern struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new (void);
++extern void eigrp_authTLV_SHA256_free (struct TLV_SHA256_Authentication_Type *);
++
++extern int eigrp_make_md5_digest (struct eigrp_interface *, struct stream *,
++                                  u_char);
++extern int eigrp_check_md5_digest (struct stream *, struct TLV_MD5_Authentication_Type *,
++                            struct eigrp_neighbor *, u_char);
++extern int eigrp_make_sha256_digest (struct eigrp_interface *, struct stream *, u_char);
++extern int eigrp_check_sha256_digest (struct stream *, struct TLV_SHA256_Authentication_Type *,
++                            struct eigrp_neighbor *, u_char );
++
++
++extern struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new (void);
++extern void eigrp_IPv4_InternalTLV_free (struct TLV_IPv4_Internal_type *);
++
++extern struct TLV_Sequence_Type *eigrp_SequenceTLV_new (void);
++
++extern const struct message eigrp_packet_type_str[];
++extern const size_t eigrp_packet_type_str_max;
++
++#endif /* _ZEBRA_EIGRP_PACKET_H */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_query.c eigrp/eigrpd/eigrp_query.c
+--- a/eigrpd/eigrp_query.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_query.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,228 @@
++/*
++ * EIGRP Sending and Receiving EIGRP Query Packets.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "thread.h"
++#include "memory.h"
++#include "linklist.h"
++#include "prefix.h"
++#include "if.h"
++#include "table.h"
++#include "sockunion.h"
++#include "stream.h"
++#include "log.h"
++#include "sockopt.h"
++#include "checksum.h"
++#include "md5.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_macros.h"
++#include "eigrpd/eigrp_topology.h"
++#include "eigrpd/eigrp_fsm.h"
++
++
++u_int32_t
++eigrp_query_send_all (struct eigrp *eigrp)
++{
++  struct eigrp_interface *iface;
++  struct listnode *node, *node2, *nnode2;
++  struct eigrp_neighbor *nbr;
++  struct eigrp_prefix_entry *pe;
++  u_int32_t counter;
++
++  if (eigrp == NULL)
++    {
++      zlog_debug("EIGRP Routing Process not enabled");
++      return 0;
++    }
++
++  counter=0;
++  for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface))
++    {
++      eigrp_send_query(iface);
++      counter++;
++    }
++
++  for (ALL_LIST_ELEMENTS(eigrp->topology_changes_internalIPV4, node2, nnode2, pe))
++    {
++      if(pe->req_action & EIGRP_FSM_NEED_QUERY)
++        {
++          pe->req_action &= ~EIGRP_FSM_NEED_QUERY;
++          listnode_delete(eigrp->topology_changes_internalIPV4, pe);
++        }
++    }
++
++  return counter;
++}
++
++/*EIGRP QUERY read function*/
++void
++eigrp_query_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
++                     struct stream * s, struct eigrp_interface *ei, int size)
++{
++  struct eigrp_neighbor *nbr;
++  struct TLV_IPv4_Internal_type *tlv;
++  struct eigrp_prefix_entry *temp_tn;
++  struct eigrp_neighbor_entry *temp_te;
++
++  u_int16_t type;
++
++  /* increment statistics. */
++  ei->query_in++;
++
++  /* get neighbor struct */
++  nbr = eigrp_nbr_get(ei, eigrph, iph);
++
++  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
++  assert(nbr);
++
++  nbr->recv_sequence_number = ntohl(eigrph->sequence);
++
++  while (s->endp > s->getp)
++    {
++      type = stream_getw(s);
++      if (type == EIGRP_TLV_IPv4_INT)
++        {
++          stream_set_getp(s, s->getp - sizeof(u_int16_t));
++
++          tlv = eigrp_read_ipv4_tlv(s);
++
++          struct prefix_ipv4 *dest_addr;
++          dest_addr = prefix_ipv4_new();
++          dest_addr->prefix = tlv->destination;
++          dest_addr->prefixlen = tlv->prefix_length;
++          struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
++              eigrp->topology_table, dest_addr);
++
++          /* If the destination exists (it should, but one never know)*/
++          if (dest != NULL)
++            {
++              struct eigrp_fsm_action_message *msg;
++              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
++                  sizeof(struct eigrp_fsm_action_message));
++              struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(
++                  dest->entries, nbr);
++              msg->packet_type = EIGRP_OPC_QUERY;
++              msg->eigrp = eigrp;
++              msg->data_type = EIGRP_TLV_IPv4_INT;
++              msg->adv_router = nbr;
++              msg->data.ipv4_int_type = tlv;
++              msg->entry = entry;
++              msg->prefix = dest;
++              int event = eigrp_get_fsm_event(msg);
++              eigrp_fsm_event(msg, event);
++            }
++          eigrp_IPv4_InternalTLV_free (tlv);
++        }
++    }
++  eigrp_hello_send_ack(nbr);
++  eigrp_query_send_all(eigrp);
++  eigrp_update_send_all(eigrp,nbr->ei);
++}
++
++void
++eigrp_send_query (struct eigrp_interface *ei)
++{
++  struct eigrp_packet *ep, *duplicate;
++  u_int16_t length = EIGRP_HEADER_LEN;
++  struct listnode *node, *nnode, *node2, *nnode2;
++  struct eigrp_neighbor *nbr;
++  struct eigrp_prefix_entry *pe;
++  char has_tlv;
++
++  ep = eigrp_packet_new(ei->ifp->mtu);
++
++  /* Prepare EIGRP INIT UPDATE header */
++  eigrp_packet_header_init(EIGRP_OPC_QUERY, ei, ep->s, 0,
++                           ei->eigrp->sequence_number, 0);
++
++  // encode Authentication TLV, if needed
++  if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
++    {
++      length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei);
++    }
++
++  has_tlv = 0;
++  for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe))
++    {
++      if(pe->req_action & EIGRP_FSM_NEED_QUERY)
++        {
++          length += eigrp_add_internalTLV_to_stream(ep->s, pe);
++          for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr))
++            {
++        	  if(nbr->state == EIGRP_NEIGHBOR_UP)
++        	  {
++        		  listnode_add(pe->rij, nbr);
++                  has_tlv = 1;
++        	  }
++            }
++        }
++    }
++
++  if(!has_tlv)
++    {
++      eigrp_packet_free(ep);
++      return;
++    }
++
++  if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
++    {
++      eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
++    }
++
++  /* EIGRP Checksum */
++    eigrp_packet_checksum(ei, ep->s, length);
++
++    ep->length = length;
++    ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS);
++
++    /*This ack number we await from neighbor*/
++    ep->sequence_number = ei->eigrp->sequence_number;
++
++    for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr))
++      {
++        if (nbr->state == EIGRP_NEIGHBOR_UP)
++          {
++            /*Put packet to retransmission queue*/
++            eigrp_fifo_push_head(nbr->retrans_queue, ep);
++
++            if (nbr->retrans_queue->count == 1)
++              {
++                eigrp_send_packet_reliably(nbr);
++              }
++          }
++      }
++}
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_reply.c eigrp/eigrpd/eigrp_reply.c
+--- a/eigrpd/eigrp_reply.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_reply.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,164 @@
++/*
++ * EIGRP Sending and Receiving EIGRP Reply Packets.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "thread.h"
++#include "memory.h"
++#include "linklist.h"
++#include "prefix.h"
++#include "if.h"
++#include "table.h"
++#include "sockunion.h"
++#include "stream.h"
++#include "log.h"
++#include "sockopt.h"
++#include "checksum.h"
++#include "md5.h"
++#include "keychain.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_macros.h"
++#include "eigrpd/eigrp_topology.h"
++#include "eigrpd/eigrp_fsm.h"
++
++void
++eigrp_send_reply (struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
++{
++  struct eigrp_packet *ep;
++  u_int16_t length = EIGRP_HEADER_LEN;
++
++  ep = eigrp_packet_new(nbr->ei->ifp->mtu);
++
++  /* Prepare EIGRP INIT UPDATE header */
++  eigrp_packet_header_init(EIGRP_OPC_REPLY, nbr->ei, ep->s, 0,
++                           nbr->ei->eigrp->sequence_number, 0);
++
++  // encode Authentication TLV, if needed
++  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
++    {
++      length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
++    }
++
++  length += eigrp_add_internalTLV_to_stream(ep->s, pe);
++
++  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
++    {
++      eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
++    }
++
++  /* EIGRP Checksum */
++  eigrp_packet_checksum(nbr->ei, ep->s, length);
++
++  ep->length = length;
++  ep->dst.s_addr = nbr->src.s_addr;
++
++  /*This ack number we await from neighbor*/
++  ep->sequence_number = nbr->ei->eigrp->sequence_number;
++
++  /*Put packet to retransmission queue*/
++  eigrp_fifo_push_head(nbr->retrans_queue, ep);
++
++  if (nbr->retrans_queue->count == 1)
++    {
++      eigrp_send_packet_reliably(nbr);
++    }
++}
++
++/*EIGRP REPLY read function*/
++void
++eigrp_reply_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
++                     struct stream * s, struct eigrp_interface *ei, int size)
++{
++  struct eigrp_neighbor *nbr;
++  struct TLV_IPv4_Internal_type *tlv;
++
++  u_int16_t type;
++
++  /* increment statistics. */
++  ei->reply_in++;
++
++  /* get neighbor struct */
++  nbr = eigrp_nbr_get(ei, eigrph, iph);
++
++  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
++  assert(nbr);
++
++  nbr->recv_sequence_number = ntohl(eigrph->sequence);
++
++  while (s->endp > s->getp)
++    {
++      type = stream_getw(s);
++      if (type == EIGRP_TLV_IPv4_INT)
++        {
++          stream_set_getp(s, s->getp - sizeof(u_int16_t));
++
++          tlv = eigrp_read_ipv4_tlv(s);
++
++          struct prefix_ipv4 *dest_addr;
++          dest_addr = prefix_ipv4_new();
++          dest_addr->prefix = tlv->destination;
++          dest_addr->prefixlen = tlv->prefix_length;
++          struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
++              eigrp->topology_table, dest_addr);
++          /*
++           * Destination must exists
++           */
++          assert(dest);
++
++          struct eigrp_fsm_action_message *msg;
++          msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
++              sizeof(struct eigrp_fsm_action_message));
++          struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(
++              dest->entries, nbr);
++
++          assert(entry); //testing
++
++          msg->packet_type = EIGRP_OPC_REPLY;
++          msg->eigrp = eigrp;
++          msg->data_type = EIGRP_TLV_IPv4_INT;
++          msg->adv_router = nbr;
++          msg->data.ipv4_int_type = tlv;
++          msg->entry = entry;
++          msg->prefix = dest;
++          int event = eigrp_get_fsm_event(msg);
++          eigrp_fsm_event(msg, event);
++
++          eigrp_IPv4_InternalTLV_free (tlv);
++        }
++    }
++  eigrp_hello_send_ack(nbr);
++}
++
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_siaquery.c eigrp/eigrpd/eigrp_siaquery.c
+--- a/eigrpd/eigrp_siaquery.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_siaquery.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,166 @@
++/*
++ * EIGRP Sending and Receiving EIGRP SIA-Query Packets.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "thread.h"
++#include "memory.h"
++#include "linklist.h"
++#include "prefix.h"
++#include "if.h"
++#include "table.h"
++#include "sockunion.h"
++#include "stream.h"
++#include "log.h"
++#include "sockopt.h"
++#include "checksum.h"
++#include "md5.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_macros.h"
++#include "eigrpd/eigrp_topology.h"
++#include "eigrpd/eigrp_fsm.h"
++
++
++/*EIGRP SIA-QUERY read function*/
++void
++eigrp_siaquery_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
++                     struct stream * s, struct eigrp_interface *ei, int size)
++{
++  struct eigrp_neighbor *nbr;
++  struct TLV_IPv4_Internal_type *tlv;
++  struct eigrp_prefix_entry *temp_tn;
++  struct eigrp_neighbor_entry *temp_te;
++
++  u_int16_t type;
++
++  /* increment statistics. */
++  ei->siaQuery_in++;
++
++  /* get neighbor struct */
++  nbr = eigrp_nbr_get(ei, eigrph, iph);
++
++  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
++  assert(nbr);
++
++  nbr->recv_sequence_number = ntohl(eigrph->sequence);
++
++  while (s->endp > s->getp)
++    {
++      type = stream_getw(s);
++      if (type == EIGRP_TLV_IPv4_INT)
++        {
++          stream_set_getp(s, s->getp - sizeof(u_int16_t));
++
++          tlv = eigrp_read_ipv4_tlv(s);
++
++          struct prefix_ipv4 *dest_addr;
++          dest_addr = prefix_ipv4_new();
++          dest_addr->prefix = tlv->destination;
++          dest_addr->prefixlen = tlv->prefix_length;
++          struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
++              eigrp->topology_table, dest_addr);
++
++          /* If the destination exists (it should, but one never know)*/
++          if (dest != NULL)
++            {
++              struct eigrp_fsm_action_message *msg;
++              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
++                  sizeof(struct eigrp_fsm_action_message));
++              struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(
++                  dest->entries, nbr);
++              msg->packet_type = EIGRP_OPC_SIAQUERY;
++              msg->eigrp = eigrp;
++              msg->data_type = EIGRP_TLV_IPv4_INT;
++              msg->adv_router = nbr;
++              msg->data.ipv4_int_type = tlv;
++              msg->entry = entry;
++              msg->prefix = dest;
++              int event = eigrp_get_fsm_event(msg);
++              eigrp_fsm_event(msg, event);
++            }
++          eigrp_IPv4_InternalTLV_free (tlv);
++        }
++    }
++  eigrp_hello_send_ack(nbr);
++}
++
++
++void
++eigrp_send_siaquery (struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
++{
++  struct eigrp_packet *ep, *duplicate;
++  u_int16_t length = EIGRP_HEADER_LEN;
++  struct listnode *node, *nnode, *node2, *nnode2;
++
++  ep = eigrp_packet_new(nbr->ei->ifp->mtu);
++
++  /* Prepare EIGRP INIT UPDATE header */
++  eigrp_packet_header_init(EIGRP_OPC_SIAQUERY, nbr->ei, ep->s, 0,
++                            nbr->ei->eigrp->sequence_number, 0);
++
++  // encode Authentication TLV, if needed
++  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
++    {
++      length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
++    }
++
++    length += eigrp_add_internalTLV_to_stream(ep->s, pe);
++
++  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
++    {
++      eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
++    }
++
++  /* EIGRP Checksum */
++    eigrp_packet_checksum(nbr->ei, ep->s, length);
++
++    ep->length = length;
++    ep->dst.s_addr = nbr->src.s_addr;
++
++    /*This ack number we await from neighbor*/
++    ep->sequence_number = nbr->ei->eigrp->sequence_number;
++
++    if (nbr->state == EIGRP_NEIGHBOR_UP)
++      {
++        /*Put packet to retransmission queue*/
++        eigrp_fifo_push_head(nbr->retrans_queue, ep);
++
++        if (nbr->retrans_queue->count == 1)
++          {
++            eigrp_send_packet_reliably(nbr);
++          }
++      }
++}
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_siareply.c eigrp/eigrpd/eigrp_siareply.c
+--- a/eigrpd/eigrp_siareply.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_siareply.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,167 @@
++/*
++ * EIGRP Sending and Receiving EIGRP SIA-Reply Packets.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "thread.h"
++#include "memory.h"
++#include "linklist.h"
++#include "prefix.h"
++#include "if.h"
++#include "table.h"
++#include "sockunion.h"
++#include "stream.h"
++#include "log.h"
++#include "sockopt.h"
++#include "checksum.h"
++#include "md5.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_macros.h"
++#include "eigrpd/eigrp_topology.h"
++#include "eigrpd/eigrp_fsm.h"
++
++
++/*EIGRP SIA-REPLY read function*/
++void
++eigrp_siareply_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
++                     struct stream * s, struct eigrp_interface *ei, int size)
++{
++  struct eigrp_neighbor *nbr;
++  struct TLV_IPv4_Internal_type *tlv;
++  struct eigrp_prefix_entry *temp_tn;
++  struct eigrp_neighbor_entry *temp_te;
++
++  u_int16_t type;
++
++  /* increment statistics. */
++  ei->siaReply_in++;
++
++  /* get neighbor struct */
++  nbr = eigrp_nbr_get(ei, eigrph, iph);
++
++  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
++  assert(nbr);
++
++  nbr->recv_sequence_number = ntohl(eigrph->sequence);
++
++  while (s->endp > s->getp)
++    {
++      type = stream_getw(s);
++      if (type == EIGRP_TLV_IPv4_INT)
++        {
++          stream_set_getp(s, s->getp - sizeof(u_int16_t));
++
++          tlv = eigrp_read_ipv4_tlv(s);
++
++          struct prefix_ipv4 *dest_addr;
++          dest_addr = prefix_ipv4_new();
++          dest_addr->prefix = tlv->destination;
++          dest_addr->prefixlen = tlv->prefix_length;
++          struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
++              eigrp->topology_table, dest_addr);
++
++          /* If the destination exists (it should, but one never know)*/
++          if (dest != NULL)
++            {
++              struct eigrp_fsm_action_message *msg;
++              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
++                  sizeof(struct eigrp_fsm_action_message));
++              struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(
++                  dest->entries, nbr);
++              msg->packet_type = EIGRP_OPC_SIAQUERY;
++              msg->eigrp = eigrp;
++              msg->data_type = EIGRP_TLV_IPv4_INT;
++              msg->adv_router = nbr;
++              msg->data.ipv4_int_type = tlv;
++              msg->entry = entry;
++              msg->prefix = dest;
++              int event = eigrp_get_fsm_event(msg);
++              eigrp_fsm_event(msg, event);
++            }
++          eigrp_IPv4_InternalTLV_free (tlv);
++        }
++    }
++  eigrp_hello_send_ack(nbr);
++}
++
++void
++eigrp_send_siareply (struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
++{
++  struct eigrp_packet *ep, *duplicate;
++  u_int16_t length = EIGRP_HEADER_LEN;
++  struct listnode *node, *nnode, *node2, *nnode2;
++
++  ep = eigrp_packet_new(nbr->ei->ifp->mtu);
++
++  /* Prepare EIGRP INIT UPDATE header */
++  eigrp_packet_header_init(EIGRP_OPC_SIAREPLY, nbr->ei, ep->s, 0,
++                            nbr->ei->eigrp->sequence_number, 0);
++
++  // encode Authentication TLV, if needed
++  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
++    {
++      length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
++    }
++
++    length += eigrp_add_internalTLV_to_stream(ep->s, pe);
++
++  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
++    {
++      eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
++    }
++
++  /* EIGRP Checksum */
++    eigrp_packet_checksum(nbr->ei, ep->s, length);
++
++    ep->length = length;
++    ep->dst.s_addr = nbr->src.s_addr;
++
++    /*This ack number we await from neighbor*/
++    ep->sequence_number = nbr->ei->eigrp->sequence_number;
++
++    if (nbr->state == EIGRP_NEIGHBOR_UP)
++      {
++        /*Put packet to retransmission queue*/
++        eigrp_fifo_push_head(nbr->retrans_queue, ep);
++
++        if (nbr->retrans_queue->count == 1)
++          {
++            eigrp_send_packet_reliably(nbr);
++          }
++      }
++}
++
++
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_snmp.c eigrp/eigrpd/eigrp_snmp.c
+--- a/eigrpd/eigrp_snmp.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_snmp.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,1395 @@
++/*
++ * EIGRP SNMP Support.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#ifdef HAVE_SNMP
++#include <net-snmp/net-snmp-config.h>
++#include <net-snmp/net-snmp-includes.h>
++
++#include "thread.h"
++#include "memory.h"
++#include "linklist.h"
++#include "prefix.h"
++#include "if.h"
++#include "table.h"
++#include "sockunion.h"
++#include "stream.h"
++#include "log.h"
++#include "sockopt.h"
++#include "checksum.h"
++#include "md5.h"
++#include "keychain.h"
++#include "smux.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_network.h"
++#include "eigrpd/eigrp_topology.h"
++#include "eigrpd/eigrp_fsm.h"
++#include "eigrpd/eigrp_snmp.h"
++
++
++struct list *eigrp_snmp_iflist;
++
++/* Declare static local variables for convenience. */
++SNMP_LOCAL_VARIABLES
++
++/* EIGRP-MIB - 1.3.6.1.4.1.9.9.449.1*/
++#define EIGRPMIB 1,3,6,1,4,1,9,9,449,1
++
++/* EIGRP-MIB instances. */
++oid eigrp_oid [] = { EIGRPMIB };
++
++/* EIGRP VPN entry */
++#define EIGRPVPNID							1
++#define EIGRPVPNNAME						2
++
++/* EIGRP Traffic statistics entry */
++#define EIGRPASNUMBER						1
++#define EIGRPNBRCOUNT						2
++#define EIGRPHELLOSSENT						3
++#define EIGRPHELLOSRCVD						4
++#define EIGRPUPDATESSENT					5
++#define EIGRPUPDATESRCVD					6
++#define EIGRPQUERIESSENT					7
++#define EIGRPQUERIESRCVD					8
++#define EIGRPREPLIESSENT					9
++#define EIGRPREPLIESRCVD					10
++#define EIGRPACKSSENT						11
++#define EIGRPACKSRCVD						12
++#define EIGRPINPUTQHIGHMARK					13
++#define EIGRPINPUTQDROPS					14
++#define EIGRPSIAQUERIESSENT					15
++#define EIGRPSIAQUERIESRCVD					16
++#define EIGRPASROUTERIDTYPE					17
++#define EIGRPASROUTERID						18
++#define EIGRPTOPOROUTES						19
++#define EIGRPHEADSERIAL						20
++#define EIGRPNEXTSERIAL						21
++#define EIGRPXMITPENDREPLIES				22
++#define EIGRPXMITDUMMIES					23
++
++/* EIGRP topology entry */
++#define EIGRPDESTNETTYPE					1
++#define EIGRPDESTNET						2
++#define EIGRPDESTNETPREFIXLEN				4
++#define EIGRPACTIVE							5
++#define EIGRPSTUCKINACTIVE					6
++#define EIGRPDESTSUCCESSORS					7
++#define EIGRPFDISTANCE						8
++#define EIGRPROUTEORIGINTYPE				9
++#define EIGRPROUTEORIGINADDRTYPE			10
++#define EIGRPROUTEORIGINADDR				11
++#define EIGRPNEXTHOPADDRESSTYPE				12
++#define EIGRPNEXTHOPADDRESS					13
++#define EIGRPNEXTHOPINTERFACE				14
++#define EIGRPDISTANCE						15
++#define EIGRPREPORTDISTANCE					16
++
++/* EIGRP peer entry */
++#define EIGRPHANDLE							1
++#define EIGRPPEERADDRTYPE					2
++#define EIGRPPEERADDR						3
++#define EIGRPPEERIFINDEX					4
++#define EIGRPHOLDTIME						5
++#define EIGRPUPTIME							6
++#define EIGRPSRTT							7
++#define EIGRPRTO							8
++#define EIGRPPKTSENQUEUED					9
++#define EIGRPLASTSEQ						10
++#define EIGRPVERSION						11
++#define EIGRPRETRANS						12
++#define EIGRPRETRIES						13
++
++/* EIGRP interface entry */
++#define EIGRPPEERCOUNT						3
++#define EIGRPXMITRELIABLEQ					4
++#define EIGRPXMITUNRELIABLEQ	        	5
++#define EIGRPMEANSRTT						6
++#define EIGRPPACINGRELIABLE					7
++#define EIGRPPACINGUNRELIABLE		        8
++#define EIGRPMFLOWTIMER						9
++#define EIGRPPENDINGROUTES					10
++#define EIGRPHELLOINTERVAL					11
++#define EIGRPXMITNEXTSERIAL					12
++#define EIGRPUMCASTS						13
++#define EIGRPRMCASTS						14
++#define EIGRPUUCASTS						15
++#define EIGRPRUCASTS						16
++#define EIGRPMCASTEXCEPTS					17
++#define EIGRPCRPKTS							18
++#define EIGRPACKSSUPPRESSED					19
++#define EIGRPRETRANSSENT					20
++#define EIGRPOOSRCVD						21
++#define EIGRPAUTHMODE						22
++#define EIGRPAUTHKEYCHAIN					23
++
++/* SNMP value hack. */
++#define COUNTER                 ASN_COUNTER
++#define INTEGER                 ASN_INTEGER
++#define GAUGE                   ASN_GAUGE
++#define TIMETICKS               ASN_TIMETICKS
++#define IPADDRESS               ASN_IPADDRESS
++#define STRING                  ASN_OCTET_STR
++#define IPADDRESSPREFIXLEN      ASN_INTEGER
++#define IPADDRESSTYPE           ASN_INTEGER
++#define INTERFACEINDEXORZERO    ASN_INTEGER
++#define UINTEGER                ASN_UNSIGNED
++
++
++
++
++/* Hook functions. */
++static u_char *eigrpVpnEntry (struct variable *, oid *, size_t *,
++				 int, size_t *, WriteMethod **);
++static u_char *eigrpTraffStatsEntry (struct variable *, oid *, size_t *, int,
++			      size_t *, WriteMethod **);
++static u_char *eigrpTopologyEntry (struct variable *, oid *, size_t *,
++				  int, size_t *, WriteMethod **);
++static u_char *eigrpPeerEntry (struct variable *, oid *, size_t *, int,
++			      size_t *, WriteMethod **);
++static u_char *eigrpInterfaceEntry (struct variable *, oid *, size_t *, int,
++				   size_t *, WriteMethod **);
++
++
++struct variable eigrp_variables[] =
++{
++  /* EIGRP vpn variables */
++  {EIGRPVPNID,              	INTEGER, NOACCESS, eigrpVpnEntry,
++   4, {1, 1, 1, 1}},
++  {EIGRPVPNNAME,            	STRING, RONLY, eigrpVpnEntry,
++   4, {1, 1, 1, 2}},
++
++  /* EIGRP traffic stats variables */
++  {EIGRPASNUMBER,              	UINTEGER, NOACCESS, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 1}},
++  {EIGRPNBRCOUNT,              	UINTEGER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 2}},
++  {EIGRPHELLOSSENT,            	COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 3}},
++  {EIGRPHELLOSRCVD,           	COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 4}},
++  {EIGRPUPDATESSENT,          	COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 5}},
++  {EIGRPUPDATESRCVD,           	COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 6}},
++  {EIGRPQUERIESSENT,            COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 7}},
++  {EIGRPQUERIESRCVD,            COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 8}},
++  {EIGRPREPLIESSENT,           	COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 9}},
++  {EIGRPREPLIESRCVD,            COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 10}},
++  {EIGRPACKSSENT,               COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 11}},
++  {EIGRPACKSRCVD,               COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 12}},
++  {EIGRPINPUTQHIGHMARK,         INTEGER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 13}},
++  {EIGRPINPUTQDROPS,           	COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 14}},
++  {EIGRPSIAQUERIESSENT,        	COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 15}},
++  {EIGRPSIAQUERIESRCVD,       	COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 16}},
++  {EIGRPASROUTERIDTYPE,         IPADDRESSTYPE, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 17}},
++  {EIGRPASROUTERID,       		IPADDRESS, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 18}},
++  {EIGRPTOPOROUTES,       		COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 19}},
++  {EIGRPHEADSERIAL,       		COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 20}},
++  {EIGRPNEXTSERIAL,            	COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 21}},
++  {EIGRPXMITPENDREPLIES,       	INTEGER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 22}},
++  {EIGRPXMITDUMMIES,       		COUNTER, RONLY, eigrpTraffStatsEntry,
++   4, {2, 1, 1, 23}},
++
++  /* EIGRP topology variables */
++  {EIGRPDESTNETTYPE,       		IPADDRESSTYPE, NOACCESS, eigrpTopologyEntry,
++   4, {3, 1, 1, 1}},
++  {EIGRPDESTNET,       	   		IPADDRESSPREFIXLEN, NOACCESS, eigrpTopologyEntry,
++   4, {3, 1, 1, 2}},
++  {EIGRPDESTNETPREFIXLEN,      	IPADDRESSTYPE, NOACCESS, eigrpTopologyEntry,
++   4, {3, 1, 1, 4}},
++  {EIGRPACTIVE,       	   		INTEGER, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 5}},
++  {EIGRPSTUCKINACTIVE,       	INTEGER, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 6}},
++  {EIGRPDESTSUCCESSORS,       	INTEGER, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 7}},
++  {EIGRPFDISTANCE,       		INTEGER, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 8}},
++  {EIGRPROUTEORIGINTYPE,       	STRING, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 9}},
++  {EIGRPROUTEORIGINADDRTYPE,    IPADDRESSTYPE, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 10}},
++  {EIGRPROUTEORIGINADDR,       	IPADDRESS, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 11}},
++  {EIGRPNEXTHOPADDRESSTYPE,     IPADDRESSTYPE, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 12}},
++  {EIGRPNEXTHOPADDRESS,       	IPADDRESS, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 13}},
++  {EIGRPNEXTHOPINTERFACE,       STRING, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 14}},
++  {EIGRPDISTANCE,       		INTEGER, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 15}},
++  {EIGRPREPORTDISTANCE,       	INTEGER, RONLY, eigrpTopologyEntry,
++   4, {3, 1, 1, 16}},
++
++  /* EIGRP peer variables */
++  {EIGRPHANDLE,       	    	INTEGER, NOACCESS, eigrpPeerEntry,
++   4, {4, 1, 1, 1}},
++  {EIGRPPEERADDRTYPE,       	IPADDRESSTYPE, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 2}},
++  {EIGRPPEERADDR,       		IPADDRESS, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 3}},
++  {EIGRPPEERIFINDEX,       		INTERFACEINDEXORZERO, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 4}},
++  {EIGRPHOLDTIME,       		INTEGER, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 5}},
++  {EIGRPUPTIME,       	    	STRING, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 6}},
++  {EIGRPSRTT,       	   		INTEGER, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 7}},
++  {EIGRPRTO,       	    		INTEGER, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 8}},
++  {EIGRPPKTSENQUEUED,			INTEGER, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 9}},
++  {EIGRPLASTSEQ,       	    	INTEGER, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 10}},
++  {EIGRPVERSION,       	    	STRING, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 11}},
++  {EIGRPRETRANS,       	    	COUNTER, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 12}},
++  {EIGRPRETRIES,       	    	INTEGER, RONLY, eigrpPeerEntry,
++   4, {4, 1, 1, 13}},
++
++  /* EIGRP interface variables */
++  {EIGRPPEERCOUNT,       		GAUGE, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 3}},
++  {EIGRPXMITRELIABLEQ,       	GAUGE, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 4}},
++  {EIGRPXMITUNRELIABLEQ,       	GAUGE, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 5}},
++  {EIGRPMEANSRTT,       		INTEGER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 6}},
++  {EIGRPPACINGRELIABLE,       	INTEGER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 7}},
++  {EIGRPPACINGUNRELIABLE,       INTEGER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 8}},
++  {EIGRPMFLOWTIMER,       		INTEGER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 9}},
++  {EIGRPPENDINGROUTES,       	GAUGE, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 10}},
++  {EIGRPHELLOINTERVAL,       	INTEGER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 11}},
++  {EIGRPXMITNEXTSERIAL,       	COUNTER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 12}},
++  {EIGRPUMCASTS,       	    	COUNTER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 13}},
++  {EIGRPRMCASTS,       	    	COUNTER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 14}},
++  {EIGRPUUCASTS,       	    	COUNTER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 15}},
++  {EIGRPRUCASTS,       	    	COUNTER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 16}},
++  {EIGRPMCASTEXCEPTS,       	COUNTER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 17}},
++  {EIGRPCRPKTS,       	   		COUNTER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 18}},
++  {EIGRPACKSSUPPRESSED,       	COUNTER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 19}},
++  {EIGRPRETRANSSENT,       		COUNTER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 20}},
++  {EIGRPOOSRCVD,       	    	COUNTER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 21}},
++  {EIGRPAUTHMODE,       		INTEGER, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 22}},
++  {EIGRPAUTHKEYCHAIN,       	STRING, RONLY, eigrpInterfaceEntry,
++   4, {5, 1, 1, 23}}
++};
++
++static struct eigrp_neighbor *
++eigrp_snmp_nbr_lookup (struct eigrp *eigrp, struct in_addr *nbr_addr,
++		      unsigned int *ifindex)
++{
++  struct listnode *node, *nnode, *node2, *nnode2;
++  struct eigrp_interface *ei;
++  struct eigrp_neighbor *nbr;
++
++  for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++    {
++      for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
++	  {
++	    if (IPV4_ADDR_SAME (&nbr->src, nbr_addr))
++	      {
++			return nbr;
++	      }
++	  }
++    }
++  return NULL;
++}
++
++static struct eigrp_neighbor *
++eigrp_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex,
++			   int first)
++{
++  struct listnode *node, *nnode, *node2, *nnode2;
++  struct eigrp_interface *ei;
++  struct eigrp_neighbor *nbr;
++  struct route_node *rn;
++  struct eigrp_neighbor *min = NULL;
++  struct eigrp *eigrp = eigrp;
++
++  eigrp = eigrp_lookup ();
++
++  for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++    {
++      for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
++	    {
++			if (first)
++			  {
++				if (! min)
++				  min = nbr;
++				else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr))
++					min = nbr;
++			  }
++			else if (ntohl (nbr->src.s_addr) > ntohl (nbr_addr->s_addr))
++			  {
++				if (! min)
++				  min = nbr;
++				else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr))
++				  min = nbr;
++			  }
++	    }
++    }
++  if (min)
++    {
++      *nbr_addr = min->src;
++      *ifindex = 0;
++      return min;
++    }
++  return NULL;
++}
++
++static struct eigrp_neighbor *
++eigrpNbrLookup (struct variable *v, oid *name, size_t *length,
++	       struct in_addr *nbr_addr, unsigned int *ifindex, int exact)
++{
++  unsigned int len;
++  int first;
++  struct eigrp_neighbor *nbr;
++  struct eigrp *eigrp;
++
++  eigrp = eigrp_lookup ();
++
++  if (! eigrp)
++    return NULL;
++
++  if (exact)
++    {
++      if (*length != v->namelen + IN_ADDR_SIZE + 1)
++	return NULL;
++
++      oid2in_addr (name + v->namelen, IN_ADDR_SIZE, nbr_addr);
++      *ifindex = name[v->namelen + IN_ADDR_SIZE];
++
++      return eigrp_snmp_nbr_lookup (eigrp, nbr_addr, ifindex);
++    }
++  else
++    {
++      first = 0;
++      len = *length - v->namelen;
++
++      if (len <= 0)
++	first = 1;
++
++      if (len > IN_ADDR_SIZE)
++	len = IN_ADDR_SIZE;
++
++      oid2in_addr (name + v->namelen, len, nbr_addr);
++
++      len = *length - v->namelen - IN_ADDR_SIZE;
++      if (len >= 1)
++	*ifindex = name[v->namelen + IN_ADDR_SIZE];
++
++      nbr = eigrp_snmp_nbr_lookup_next (nbr_addr, ifindex, first);
++
++      if (nbr)
++	{
++	  *length = v->namelen + IN_ADDR_SIZE + 1;
++	  oid_copy_addr (name + v->namelen, nbr_addr, IN_ADDR_SIZE);
++	  name[v->namelen + IN_ADDR_SIZE] = *ifindex;
++	  return nbr;
++	}
++    }
++  return NULL;
++}
++
++
++  static u_char *
++  eigrpVpnEntry (struct variable *v, oid *name, size_t *length,
++   				 int exact, size_t *var_len, WriteMethod **write_method)
++  {
++	  struct eigrp *eigrp;
++
++
++	  eigrp = eigrp_lookup ();
++
++	  /* Check whether the instance identifier is valid */
++	  if (smux_header_generic (v, name, length, exact, var_len, write_method)
++	    == MATCH_FAILED)
++	  return NULL;
++
++	  /* Return the current value of the variable */
++	  switch (v->magic)
++	  {
++	  case EIGRPVPNID:           /* 1 */
++	  /* The unique VPN identifier */
++	  		if (eigrp)
++	  		{
++	  			return SNMP_INTEGER(1);
++	  		}
++	  		else
++	  			return SNMP_INTEGER (0);
++	  		break;
++	  case EIGRPVPNNAME:           /* 2 */
++	  /* The name given to the VPN */
++	  	  	if (eigrp)
++	  	  	{
++	  	  		return SNMP_INTEGER(1);
++	  	  	}
++	  	  	else
++	  	  		return SNMP_INTEGER (0);
++	  	  	break;
++	  default:
++		  	return NULL;
++	  }
++	  return NULL;
++  }
++
++  static uint32_t
++  eigrp_neighbor_count(struct eigrp *eigrp)
++  {
++    uint32_t count;
++    struct eigrp_interface *ei;
++    struct listnode *node, *node2, *nnode2;
++    struct eigrp_neighbor *nbr;
++
++    if (eigrp == NULL)
++    {
++    	return 0;
++    }
++
++    count = 0;
++    for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
++    {
++    	for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
++        {
++              if (nbr->state == EIGRP_NEIGHBOR_UP)
++              count++;
++        }
++    }
++
++    return count;
++  }
++
++
++  static u_char *
++  eigrpTraffStatsEntry (struct variable *v, oid *name, size_t *length,
++			 	 int exact, size_t *var_len, WriteMethod **write_method)
++  {
++	struct eigrp *eigrp;
++	struct eigrp_interface *ei;
++	struct listnode *node, *nnode;
++	int counter;
++
++
++	eigrp = eigrp_lookup ();
++
++	/* Check whether the instance identifier is valid */
++	if (smux_header_generic (v, name, length, exact, var_len, write_method)
++	  == MATCH_FAILED)
++	return NULL;
++
++	/* Return the current value of the variable */
++	switch (v->magic)
++	{
++	case EIGRPASNUMBER:		/* 1 */
++    /* AS-number of this EIGRP instance. */
++            if (eigrp)
++            	return SNMP_INTEGER (eigrp->AS);
++            else
++            	return SNMP_INTEGER (0);
++            break;
++	case EIGRPNBRCOUNT:           /* 2 */
++    /* Neighbor count of this EIGRP instance */
++            if (eigrp)
++            	return SNMP_INTEGER (eigrp_neighbor_count (eigrp));
++            else
++            	return SNMP_INTEGER (0);
++            break;
++	case EIGRPHELLOSSENT:           /* 3 */
++	/* Hello packets output count */
++			if (eigrp)
++			{
++				counter = 0;
++				for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++				{
++					counter += ei->hello_out;
++				}
++					return SNMP_INTEGER (counter);
++				}
++		    else
++		        return SNMP_INTEGER (0);
++		    break;
++	case EIGRPHELLOSRCVD:           /* 4 */
++	/* Hello packets input count */
++			if (eigrp)
++			{
++				counter = 0;
++				for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++				 {
++					counter += ei->hello_in;
++				 }
++				return SNMP_INTEGER (counter);
++			}
++	        else
++	            return SNMP_INTEGER (0);
++	        break;
++	case EIGRPUPDATESSENT:           /* 5 */
++	/* Update packets output count */
++			if (eigrp)
++			{
++				counter = 0;
++				for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++				{
++				    counter += ei->update_out;
++				}
++				    return SNMP_INTEGER (counter);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPUPDATESRCVD:           /* 6 */
++	/* Update packets input count */
++		    if (eigrp)
++		    {
++		    	counter = 0;
++		    	for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++		    	{
++		    		counter += ei->update_in;
++		    	}
++		    	return SNMP_INTEGER (counter);
++		    }
++		    else
++		    	return SNMP_INTEGER (0);
++		    break;
++	case EIGRPQUERIESSENT:           /* 7 */
++	/* Querry packets output count */
++			if (eigrp)
++			{
++				counter = 0;
++				for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++				{
++					counter += ei->query_out;
++				}
++				return SNMP_INTEGER (counter);
++			}
++			else
++			    return SNMP_INTEGER (0);
++			break;
++	case EIGRPQUERIESRCVD:           /* 8 */
++	/* Querry packets input count */
++			if (eigrp)
++			{
++				counter = 0;
++				for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++				{
++					counter += ei->query_in;
++				}
++				return SNMP_INTEGER (counter);
++			}
++		    else
++		        return SNMP_INTEGER (0);
++		    break;
++	case EIGRPREPLIESSENT:           /* 9 */
++	/* Reply packets output count */
++			if (eigrp)
++			{
++				counter = 0;
++				for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++				{
++					counter += ei->reply_out;
++				}
++				return SNMP_INTEGER (counter);
++			}
++			else
++			    return SNMP_INTEGER (0);
++			break;
++	case EIGRPREPLIESRCVD:           /* 10 */
++	/* Reply packets input count */
++			if (eigrp)
++			{
++				counter = 0;
++				for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++				{
++					counter += ei->reply_in;
++				}
++				return SNMP_INTEGER (counter);
++			}
++		    else
++		        return SNMP_INTEGER (0);
++		    break;
++	case EIGRPACKSSENT:           /* 11 */
++	/* Acknowledgement packets output count */
++			if (eigrp)
++			{
++				counter = 0;
++				for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++				{
++					counter += ei->ack_out;
++				}
++				return SNMP_INTEGER (counter);
++			}
++			else
++			    return SNMP_INTEGER (0);
++			break;
++	case EIGRPACKSRCVD:           /* 12 */
++	/* Acknowledgement packets input count */
++			if (eigrp)
++			{
++				counter = 0;
++				for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++				{
++					counter += ei->ack_in;
++				}
++				return SNMP_INTEGER (counter);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPINPUTQHIGHMARK:           /* 13 */
++	/* The highest number of EIGRP packets in the input queue */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPINPUTQDROPS:           /* 14 */
++	/* The number of EIGRP packets dropped from the input queue */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPSIAQUERIESSENT:           /* 15 */
++	/* SIA querry packets output count */
++			if (eigrp)
++			{
++				counter = 0;
++				for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++				{
++					counter += ei->siaQuery_out;
++				}
++				return SNMP_INTEGER (counter);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPSIAQUERIESRCVD:           /* 16 */
++	/* SIA querry packets input count */
++			if (eigrp)
++			{
++				counter = 0;
++				for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++				{
++					counter += ei->siaQuery_in;
++				}
++				return SNMP_INTEGER (counter);
++			}
++			else
++			    return SNMP_INTEGER (0);
++		    break;
++	case EIGRPASROUTERIDTYPE:           /* 17 */
++	/* Whether the router ID is set manually or automatically */
++	        if (eigrp)
++	        	if(eigrp->router_id_static!=0)
++	        		 return SNMP_INTEGER(1);
++	        	else
++					 return SNMP_INTEGER(1);
++	        else
++	        	return SNMP_INTEGER (0);
++	        break;
++	case EIGRPASROUTERID:           /* 18 */
++	/* Router ID for this EIGRP AS */
++	        if (eigrp)
++	        	if(eigrp->router_id_static!=0)
++	        		return  SNMP_INTEGER (eigrp->router_id_static);
++	        	else
++					return  SNMP_INTEGER (eigrp->router_id);
++	        else
++				return  SNMP_INTEGER (0);
++	        break;
++	case EIGRPTOPOROUTES:           /* 19 */
++	/* The total number of EIGRP derived routes currently existing
++       in the topology table for the AS */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPHEADSERIAL:           /* 20 */
++	/* The serial number of the first route in the internal
++	   sequence for an AS*/
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPNEXTSERIAL:           /* 21 */
++	/* The serial number that would be assigned to the next new
++       or changed route in the topology table for the AS*/
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPXMITPENDREPLIES:           /* 22 */
++	/* Total number of outstanding replies expected to queries
++	   that have been sent to peers in the current AS*/
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPXMITDUMMIES:           /* 23 */
++	/* Total number of currently existing dummies associated with the AS*/
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	default:
++		return NULL;
++	}
++	return NULL;
++  }
++  static u_char *
++  eigrpTopologyEntry (struct variable *v, oid *name, size_t *length,
++			 	 int exact, size_t *var_len, WriteMethod **write_method)
++  {
++	  struct eigrp *eigrp;
++	  struct eigrp_interface *ei;
++	  struct listnode *node, *nnode;
++
++
++	  eigrp = eigrp_lookup ();
++
++	  /* Check whether the instance identifier is valid */
++	  if (smux_header_generic (v, name, length, exact, var_len, write_method)
++	    == MATCH_FAILED)
++	  return NULL;
++
++	/* Return the current value of the variable */
++	switch (v->magic)
++	{
++	case EIGRPDESTNETTYPE:           /* 1 */
++	/* The format of the destination IP network number for a single
++	   route in the topology table*/
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPDESTNET:           /* 2 */
++	/* The destination IP network number for a single route in the topology table*/
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPDESTNETPREFIXLEN:           /* 4 */
++	/* The prefix length associated with the destination IP network address
++	   for a single route in the topology table in the AS*/
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPACTIVE:           /* 5 */
++	/* A value of true(1) indicates the route to the destination network has failed
++	   A value of false(2) indicates the route is stable (passive).*/
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPSTUCKINACTIVE:           /* 6 */
++	/* A value of true(1) indicates that that this route which is in active state
++	   has not received any replies to queries for alternate paths */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPDESTSUCCESSORS:           /* 7 */
++	/* Next routing hop for a path to the destination IP network */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPFDISTANCE:           /* 8 */
++	/* Minimum distance from this router to the destination IP network */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPROUTEORIGINTYPE:           /* 9 */
++	/* Text string describing the internal origin of the EIGRP route */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPROUTEORIGINADDRTYPE:           /* 10 */
++	/* The format of the IP address defined as the origin of this
++	   topology route entry */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPROUTEORIGINADDR:           /* 11 */
++	/* If the origin of the topology route entry is external to this router,
++	   then this object is the IP address of the router from which it originated */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPNEXTHOPADDRESSTYPE:           /* 12 */
++	/* The format of the next hop IP address */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPNEXTHOPADDRESS:           /* 13 */
++	/* Next hop IP address for the route */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPNEXTHOPINTERFACE:           /* 14 */
++	/* The interface through which the next hop IP address is reached */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPDISTANCE:           /* 15 */
++	/* The computed distance to the destination network entry from this router */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	case EIGRPREPORTDISTANCE:           /* 16 */
++	/* The computed distance to the destination network in the topology entry
++	   reported to this router by the originator of this route */
++			if (eigrp)
++			{
++				return SNMP_INTEGER(1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++	default:
++		return NULL;
++	}
++	return NULL;
++  }
++
++  static u_char *
++  eigrpPeerEntry (struct variable *v, oid *name, size_t *length,
++			 	 int exact, size_t *var_len, WriteMethod **write_method)
++  {
++	  struct eigrp *eigrp;
++	  struct eigrp_interface *ei;
++	  struct listnode *node, *nnode;
++	  struct eigrp_neighbor *nbr;
++	  struct in_addr nbr_addr;
++	  unsigned int ifindex;
++
++	  eigrp = eigrp_lookup ();
++
++	  /* Check whether the instance identifier is valid */
++	  if (smux_header_generic (v, name, length, exact, var_len, write_method)
++	  	 == MATCH_FAILED)
++	  return NULL;
++
++	  memset (&nbr_addr, 0, sizeof (struct in_addr));
++	  ifindex = 0;
++
++	  nbr = eigrpNbrLookup (v, name, length, &nbr_addr, &ifindex, exact);
++	    if (! nbr)
++	      return NULL;
++	    ei = nbr->ei;
++	    if (! ei)
++	      return NULL;
++
++	  /* Return the current value of the variable */
++	  switch (v->magic)
++	  {
++	  case EIGRPHANDLE:           /* 1 */
++	  /* The unique internal identifier for the peer in the AS */
++	  		if (eigrp)
++	  		{
++	  			return SNMP_INTEGER(1);
++	  		}
++	  		else
++	  			return SNMP_INTEGER (0);
++	  		break;
++	  case EIGRPPEERADDRTYPE:           /* 2 */
++	  /* The format of the remote source IP address used by the peer */
++	  	  	if (eigrp)
++	  	  	{
++	  	  		return SNMP_INTEGER(1);
++	  	  	}
++	  	  	else
++	  	  		return SNMP_INTEGER (0);
++	  	  	break;
++	  case EIGRPPEERADDR:           /* 3 */
++	  /* The source IP address used by the peer */
++	  	  	if (eigrp)
++	  	  	{
++	  	  	  	return SNMP_INTEGER(1);
++	  	  	}
++	  	  	else
++	  	  	    return SNMP_INTEGER (0);
++	  	  	break;
++	  case EIGRPPEERIFINDEX:           /* 4 */
++	  /* The ifIndex of the interface on this router */
++	  		if (eigrp)
++	  		{
++	  			return SNMP_INTEGER(1);
++	  		}
++	  		else
++	  			return SNMP_INTEGER (0);
++	  		break;
++	  case EIGRPHOLDTIME:           /* 5 */
++	  /* How much time must pass without receiving a hello packet from this
++	     EIGRP peer before this router declares the peer down */
++	  	  	if (eigrp)
++	  	  	{
++	  	  		return SNMP_INTEGER(1);
++	  	  	}
++	  	  	else
++	  	  		return SNMP_INTEGER (0);
++	  	  	break;
++	  case EIGRPUPTIME:           /* 6 */
++	  /* The elapsed time since the EIGRP adjacency was first established */
++	  	  	if (eigrp)
++	  	  	{
++	  	  		return SNMP_INTEGER(1);
++	  	  	}
++	  	  	else
++	  	  		return SNMP_INTEGER (0);
++	  	  	break;
++	  case EIGRPSRTT:           /* 7 */
++	  /* The computed smooth round trip time for packets to and from the peer */
++	  	  	if (eigrp)
++	  	  	{
++	  	  		return SNMP_INTEGER(1);
++	  	  	}
++	  	  	else
++	  	  	    return SNMP_INTEGER (0);
++	  	  	break;
++	  case EIGRPRTO:           /* 8 */
++	  /* The computed retransmission timeout for the peer */
++	  	  	if (eigrp)
++	  	  	{
++	  	  		return SNMP_INTEGER(1);
++	  	  	}
++	  	  	else
++	  	  		return SNMP_INTEGER (0);
++	  	  	break;
++	  case EIGRPPKTSENQUEUED:           /* 9 */
++	  /* The number of any EIGRP packets currently enqueued */
++	  	  	if (eigrp)
++	  	  	{
++	  	  	  	return SNMP_INTEGER(1);
++	  	  	}
++	  	  	else
++	  	  	    return SNMP_INTEGER (0);
++	  	  	break;
++	  case EIGRPLASTSEQ:           /* 10 */
++	  /* sequence number of the last EIGRP packet sent to this peer */
++	  	  	if (eigrp)
++	  	  	{
++	  	  	  	return SNMP_INTEGER(1);
++	  	  	}
++	  	  	else
++	  	  	    return SNMP_INTEGER (0);
++	  	  	break;
++	  case EIGRPVERSION:           /* 11 */
++	  /* The EIGRP version information reported by the remote peer */
++	  		if (eigrp)
++	  		{
++	  			return SNMP_INTEGER(1);
++	  		}
++	  		else
++	  			return SNMP_INTEGER (0);
++	  		break;
++	  case EIGRPRETRANS:           /* 12 */
++	  /* The cumulative number of retransmissions to this peer */
++	  	  	if (eigrp)
++	  	  	{
++	  	  		return SNMP_INTEGER(1);
++	  	  	}
++	  	  	else
++	  	  		return SNMP_INTEGER (0);
++	  	  	break;
++	  case EIGRPRETRIES:           /* 13 */
++	  /* The number of times the current unacknowledged packet has been retried */
++	  	  	if (eigrp)
++	  	  	{
++	  	  		return SNMP_INTEGER(1);
++	  	  	}
++	  	  	else
++	  	  		return SNMP_INTEGER (0);
++	  	  	break;
++	  default:
++	  		return NULL;
++	  }
++	  return NULL;
++  }
++  static u_char *
++  eigrpInterfaceEntry (struct variable *v, oid *name, size_t *length,
++			 	 int exact, size_t *var_len, WriteMethod **write_method)
++  {
++	struct eigrp *eigrp;
++	struct eigrp_interface *ei;
++	struct listnode *node, *nnode;
++	struct keychain *keychain;
++	struct list *keylist;
++	int counter;
++
++
++	eigrp = eigrp_lookup ();
++
++	/* Check whether the instance identifier is valid */
++	if (smux_header_generic (v, name, length, exact, var_len, write_method)
++	  == MATCH_FAILED)
++	return NULL;
++
++	/* Return the current value of the variable */
++	switch (v->magic)
++	{
++		case EIGRPPEERCOUNT:           /* 3 */
++		/* The number of EIGRP adjacencies currently formed with
++           peers reached through this interface */
++		  	if (eigrp)
++		  	{
++		  		return SNMP_INTEGER (eigrp_neighbor_count (eigrp));
++		  	}
++		  	else
++		  		return SNMP_INTEGER (0);
++		  	break;
++		case EIGRPXMITRELIABLEQ:           /* 4 */
++		/* The number of EIGRP packets currently waiting in the reliable
++		   transport transmission queue */
++			if (eigrp)
++			{
++				return SNMP_INTEGER (1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++		case EIGRPXMITUNRELIABLEQ:           /* 5 */
++		/* The number of EIGRP packets currently waiting in the unreliable
++		   transport transmission queue */
++			if (eigrp)
++			{
++				return SNMP_INTEGER (1);
++			}
++			else
++				return SNMP_INTEGER (0);
++			break;
++		case EIGRPMEANSRTT:           /* 6 */
++		/* The average of all the computed smooth round trip time values
++		   for a packet to and from all peers established on this interface */
++			  	if (eigrp)
++			  	{
++			  		return SNMP_INTEGER(1);
++			  	}
++			  	else
++			  		return SNMP_INTEGER (0);
++			  	break;
++		case EIGRPPACINGRELIABLE:           /* 7 */
++		/* The configured time interval between EIGRP packet transmissions */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPPACINGUNRELIABLE:           /* 8 */
++		/* The configured time interval between EIGRP packet transmissions
++		   on the interface when the unreliable transport method is used */
++				if (eigrp)
++				{
++				    return SNMP_INTEGER (1);
++				}
++				else
++				    return SNMP_INTEGER (0);
++				break;
++		case EIGRPMFLOWTIMER:           /* 9 */
++		/* The configured multicast flow control timer value */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPPENDINGROUTES:           /* 10 */
++		/* The number of queued EIGRP routing updates awaiting transmission */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPHELLOINTERVAL:           /* 11 */
++		/* The configured time interval between Hello packet transmissions */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPXMITNEXTSERIAL:           /* 12 */
++		/* The serial number of the next EIGRP packet that is to be queued
++		   for transmission */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPUMCASTS:           /* 13 */
++		/* The total number of unreliable EIGRP multicast packets sent
++		   on this interface */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPRMCASTS:           /* 14 */
++		/* The total number of reliable EIGRP multicast packets sent
++		   on this interface */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPUUCASTS:           /* 15 */
++		/* The total number of unreliable EIGRP unicast packets sent
++		   on this interface */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPRUCASTS:           /* 16 */
++		/* The total number of reliable EIGRP unicast packets sent
++		   on this interface */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPMCASTEXCEPTS:           /* 17 */
++		/* The total number of EIGRP multicast exception transmissions */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPCRPKTS:           /* 18 */
++		/* The total number EIGRP Conditional-Receive packets sent on this interface */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPACKSSUPPRESSED:           /* 19 */
++		/* The total number of individual EIGRP acknowledgement packets that have been
++		   suppressed and combined in an already enqueued outbound reliable packet on this interface */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPRETRANSSENT:           /* 20 */
++		/* The total number EIGRP packet retransmissions sent on the interface */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPOOSRCVD:           /* 21 */
++		/* The total number of out-of-sequence EIGRP packets received */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPAUTHMODE:           /* 22 */
++		/* The EIGRP authentication mode of the interface */
++				if (eigrp)
++				{
++					return SNMP_INTEGER(1);
++				}
++				else
++					return SNMP_INTEGER (0);
++				break;
++		case EIGRPAUTHKEYCHAIN:		/* 23 */
++		/* The name of the authentication key-chain configured
++           on this interface. */
++			  keylist = keychain_list_get();
++			  for (ALL_LIST_ELEMENTS (keylist, node, nnode, keychain))
++			  {
++				  return (u_char *) keychain->name;
++			  }
++			  if (eigrp && keychain)
++			  {
++				  *var_len = str_len (keychain->name);
++				  return (u_char *) keychain->name;
++			  }
++			  else
++				  return (u_char *) "TEST";
++			  break;
++		default:
++			 return NULL;
++	}
++	  return NULL;
++  }
++
++
++  /* Register EIGRP-MIB. */
++  void
++  eigrp_snmp_init ()
++  {
++    eigrp_snmp_iflist = list_new ();
++    smux_init (eigrp_om->master);
++    REGISTER_MIB("ciscoEigrpMIB", eigrp_variables, variable, eigrp_oid);
++  }
++
++
++#endif
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_snmp.h eigrp/eigrpd/eigrp_snmp.h
+--- a/eigrpd/eigrp_snmp.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_snmp.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,36 @@
++/*
++ * EIGRP SNMP Support.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++
++#ifndef _ZEBRA_EIGRP_SNMP_H
++#define _ZEBRA_EIGRP_SNMP_H
++
++extern void eigrp_snmp_init (void);
++
++
++#endif /* _ZEBRA_EIGRP_SNMP_H */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_structs.h eigrp/eigrpd/eigrp_structs.h
+--- a/eigrpd/eigrp_structs.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_structs.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,481 @@
++/*
++ * EIGRP Definition of Data Structures.
++ * Copyright (C) 2013-2015
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *   Frantisek Gazo
++ *   Tomas Hvorkovy
++ *   Martin Kontsek
++ *   Lukas Koribsky
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRP_STRUCTS_H_
++#define _ZEBRA_EIGRP_STRUCTS_H_
++
++#include "filter.h"
++
++#include "eigrpd/eigrp_const.h"
++#include "eigrpd/eigrp_macros.h"
++
++/* EIGRP master for system wide configuration and variables. */
++struct eigrp_master
++{
++  /* EIGRP instance. */
++  struct list *eigrp;
++
++  /* EIGRP thread master. */
++  struct thread_master *master;
++
++  /* Zebra interface list. */
++  struct list *iflist;
++
++  /* EIGRP start time. */
++  time_t start_time;
++
++  /* Various EIGRP global configuration. */
++  u_char options;
++
++#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */
++};
++
++struct eigrp_metrics
++{
++  u_int32_t delay;
++  u_int32_t bandwith;
++  unsigned char mtu[3];
++  u_char hop_count;
++  u_char reliability;
++  u_char load;
++  u_char tag;
++  u_char flags;
++};
++
++struct eigrp
++{
++  u_int16_t AS;			/* Autonomous system number */
++  u_int16_t vrid;		/* Virtual Router ID */
++  u_char    k_values[6];	/*Array for K values configuration*/
++  u_char variance;              /*Metric variance multiplier*/
++  u_char max_paths;             /*Maximum allowed paths for 1 prefix*/
++
++  /*Name of this EIGRP instance*/
++  char *name;
++
++  /* EIGRP Router ID. */
++  u_int32_t router_id; /* Configured automatically. */
++  u_int32_t router_id_static; /* Configured manually. */
++
++  struct list *eiflist; /* eigrp interfaces */
++  u_char passive_interface_default; /* passive-interface default */
++
++  unsigned int fd;
++  unsigned int maxsndbuflen;
++
++  u_int32_t sequence_number; /*Global EIGRP sequence number*/
++
++  struct stream *ibuf;
++  struct list *oi_write_q;
++
++  /*Threads*/
++  struct thread *t_write;
++  struct thread *t_read;
++
++  struct route_table *networks; /* EIGRP config networks. */
++
++  struct list *topology_table;
++
++  u_int64_t serno; /* Global serial number counter for topology entry changes*/
++  u_int64_t serno_last_update; /* Highest serial number of information send by last update*/
++  struct list *topology_changes_internalIPV4;
++  struct list *topology_changes_externalIPV4;
++
++  /*Neighbor self*/
++  struct eigrp_neighbor *neighbor_self;
++
++  /*Configured metric for redistributed routes*/
++  struct eigrp_metrics dmetric[ZEBRA_ROUTE_MAX + 1];
++  int redistribute;           /* Num of redistributed protocols. */
++
++};
++
++//------------------------------------------------------------------------------------------------------------------------------------------
++
++/*EIGRP interface structure*/
++struct eigrp_interface
++{
++  /* This interface's parent eigrp instance. */
++  struct eigrp *eigrp;
++
++  /* Interface data from zebra. */
++  struct interface *ifp;
++
++  /* Packet send buffer. */
++  struct eigrp_fifo *obuf; /* Output queue */
++
++  /* To which multicast groups do we currently belong? */
++
++  /* Configured varables. */
++  struct eigrp_if_params *params;
++
++  u_char multicast_memberships;
++
++  /* EIGRP Network Type. */
++  u_char type;
++
++  struct prefix *address; /* Interface prefix */
++  struct connected *connected; /* Pointer to connected */
++
++  /* Neighbor information. */
++  struct list *nbrs; /* EIGRP Neighbor List */
++
++  /* Threads. */
++  struct thread *t_hello; /* timer */
++
++  int on_write_q;
++
++  /* Access-list. */
++  struct access_list *list[EIGRP_FILTER_MAX];
++
++  /* Prefix-list. */
++  struct prefix_list *prefix[EIGRP_FILTER_MAX];
++
++  /* Route-map. */
++  struct route_map *routemap[EIGRP_FILTER_MAX];
++
++  /* Statistics fields. */
++  u_int32_t hello_in; /* Hello message input count. */
++  u_int32_t update_in; /* Update message input count. */
++  u_int32_t query_in; /* Querry message input count. */
++  u_int32_t reply_in; /* Reply message input count. */
++  u_int32_t hello_out; /* Hello message output count. */
++  u_int32_t update_out; /* Update message output count. */
++  u_int32_t query_out; /* Query message output count. */
++  u_int32_t reply_out; /* Reply message output count. */
++  u_int32_t siaQuery_in;
++  u_int32_t siaQuery_out;
++  u_int32_t siaReply_in;
++  u_int32_t siaReply_out;
++  u_int32_t ack_out;
++  u_int32_t ack_in;
++
++  u_int32_t crypt_seqnum;             /* Cryptographic Sequence Number */
++};
++
++struct eigrp_if_params
++{
++  DECLARE_IF_PARAM (u_char, passive_interface); /* EIGRP Interface is passive: no sending or receiving (no need to join multicast groups) */
++  DECLARE_IF_PARAM (u_int32_t, v_hello); /* Hello Interval */
++  DECLARE_IF_PARAM (u_int16_t, v_wait); /* Router Hold Time Interval */
++  DECLARE_IF_PARAM (u_char, type); /* type of interface */
++  DECLARE_IF_PARAM (u_int32_t, bandwidth);
++  DECLARE_IF_PARAM (u_int32_t, delay);
++  DECLARE_IF_PARAM (u_char, reliability);
++  DECLARE_IF_PARAM (u_char, load);
++
++  DECLARE_IF_PARAM (char *, auth_keychain );    /* Associated keychain with interface*/
++  DECLARE_IF_PARAM (int, auth_type);         /* EIGRP authentication type */
++};
++
++enum
++{
++  MEMBER_ALLROUTERS = 0, MEMBER_MAX,
++};
++
++struct eigrp_if_info
++{
++  struct eigrp_if_params *def_params;
++  struct route_table *params;
++  struct route_table *eifs;
++  unsigned int membership_counts[MEMBER_MAX]; /* multicast group refcnts */
++};
++
++//------------------------------------------------------------------------------------------------------------------------------------------
++
++/* Neighbor Data Structure */
++struct eigrp_neighbor
++{
++  /* This neighbor's parent eigrp interface. */
++  struct eigrp_interface *ei;
++
++  /* EIGRP neighbor Information */
++  u_char state; /* neigbor status. */
++
++  u_int32_t recv_sequence_number; /* Last received sequence Number. */
++  u_int32_t init_sequence_number;
++
++  /*If packet is unacknowledged, we try to send it again 16 times*/
++  u_char retrans_counter;
++
++  struct in_addr src; /* Neighbor Src address. */
++
++  u_char os_rel_major;		// system version - just for show
++  u_char os_rel_minor;		// system version - just for show
++  u_char tlv_rel_major;		// eigrp version - tells us what TLV format to use
++  u_char tlv_rel_minor;		// eigrp version - tells us what TLV format to use
++
++  u_char K1;
++  u_char K2;
++  u_char K3;
++  u_char K4;
++  u_char K5;
++  u_char K6;
++
++  /* Timer values. */
++  u_int16_t v_holddown;
++
++  /* Threads. */
++  struct thread *t_holddown;
++
++  struct eigrp_fifo *retrans_queue;
++  struct eigrp_fifo *multicast_queue;
++
++  u_int32_t crypt_seqnum;           /* Cryptographic Sequence Number. */
++};
++
++//---------------------------------------------------------------------------------------------------------------------------------------------
++
++
++struct eigrp_packet
++{
++  struct eigrp_packet *next;
++  struct eigrp_packet *previous;
++
++  /* Pointer to data stream. */
++  struct stream *s;
++
++  /* IP destination address. */
++  struct in_addr dst;
++
++  /*Packet retransmission thread*/
++  struct thread *t_retrans_timer;
++
++  /*Packet retransmission counter*/
++  u_char retrans_counter;
++
++  u_int32_t sequence_number;
++
++  /* EIGRP packet length. */
++  u_int16_t length;
++};
++
++struct eigrp_fifo
++{
++  struct eigrp_packet *head;
++  struct eigrp_packet *tail;
++
++  unsigned long count;
++};
++
++struct eigrp_header
++{
++  u_char version;
++  u_char opcode;
++  u_int16_t checksum;
++  u_int32_t flags;
++  u_int32_t sequence;
++  u_int32_t ack;
++  u_int16_t vrid;
++  u_int16_t ASNumber;
++  char *tlv[0];
++
++}__attribute__((packed));
++
++
++/**
++ * Generic TLV type used for packet decoding.
++ *
++ *      +-----+------------------+
++ *      |     |     |            |
++ *      | Type| Len |    Vector  |
++ *      |     |     |            |
++ *      +-----+------------------+
++ */
++struct eigrp_tlv_hdr_type
++{
++  u_int16_t type;
++  u_int16_t length;
++  uint8_t  value[0];
++}__attribute__((packed));
++
++struct TLV_Parameter_Type
++{
++  u_int16_t type;
++  u_int16_t length;
++  u_char K1;
++  u_char K2;
++  u_char K3;
++  u_char K4;
++  u_char K5;
++  u_char K6;
++  u_int16_t hold_time;
++}__attribute__((packed));
++
++struct TLV_MD5_Authentication_Type
++{
++  u_int16_t type;
++  u_int16_t length;
++  u_int16_t auth_type;
++  u_int16_t auth_length;
++  u_int32_t key_id;
++  u_int32_t key_sequence;
++  u_char Nullpad[8];
++  u_char digest[EIGRP_AUTH_TYPE_MD5_LEN];
++
++}__attribute__((packed));
++
++struct TLV_SHA256_Authentication_Type
++{
++  u_int16_t type;
++  u_int16_t length;
++  u_int16_t auth_type;
++  u_int16_t auth_length;
++  u_int32_t key_id;
++  u_int32_t key_sequence;
++  u_char Nullpad[8];
++  u_char digest[EIGRP_AUTH_TYPE_SHA256_LEN];
++
++}__attribute__((packed));
++
++struct TLV_Sequence_Type
++{
++  u_int16_t type;
++  u_int16_t length;
++  u_char addr_length;
++  struct in_addr *addresses;
++}__attribute__((packed));
++
++struct TLV_Next_Multicast_Sequence
++{
++  u_int16_t type;
++  u_int16_t length;
++  u_int32_t multicast_sequence;
++}__attribute__((packed));
++
++struct TLV_Software_Type
++{
++  u_int16_t type;
++  u_int16_t length;
++  u_char vender_major;
++  u_char vender_minor;
++  u_char eigrp_major;
++  u_char eigrp_minor;
++}__attribute__((packed));
++
++struct TLV_IPv4_Internal_type
++{
++  u_int16_t type;
++  u_int16_t length;
++  struct in_addr forward;
++
++  /*Metrics*/
++  struct eigrp_metrics metric;
++
++  u_char prefix_length;
++
++  unsigned char destination_part[4];
++  struct in_addr destination;
++}__attribute__((packed));
++
++struct TLV_IPv4_External_type
++{
++  u_int16_t type;
++  u_int16_t length;
++  struct in_addr next_hop;
++  struct in_addr originating_router;
++  u_int32_t originating_as;
++  u_int32_t administrative_tag;
++  u_int32_t external_metric;
++  u_int16_t reserved;
++  u_char external_protocol;
++  u_char external_flags;
++
++  /*Metrics*/
++  struct eigrp_metrics metric;
++
++  u_char prefix_length;
++  unsigned char destination_part[4];
++  struct in_addr destination;
++}__attribute__((packed));
++
++//---------------------------------------------------------------------------------------------------------------------------------------------
++
++/* EIGRP Topology table node structure */
++struct eigrp_prefix_entry
++{
++  struct list *entries, *rij;
++  u_int32_t fdistance;						// FD
++  u_int32_t rdistance;						// RD
++  u_int32_t distance;						// D
++  struct eigrp_metrics reported_metric;		// RD for sending
++
++  u_char nt;                                //network type
++  u_char state; 							//route fsm state
++  u_char af;								// address family
++  u_char req_action;						// required action
++
++  struct prefix_ipv4 *destination_ipv4;		// pointer to struct with ipv4 address
++  struct prefix_ipv6 *destination_ipv6;		// pointer to struct with ipv6 address
++
++  //If network type is REMOTE_EXTERNAL, pointer will have reference to its external TLV
++  struct TLV_IPv4_External_type *extTLV;
++
++  u_int64_t serno; /*Serial number for this entry. Increased with each change of entry*/
++};
++
++/* EIGRP Topology table record structure */
++struct eigrp_neighbor_entry
++{
++  struct eigrp_prefix_entry *prefix;
++  u_int32_t reported_distance; 				//distance reported by neighbor
++  u_int32_t distance; 						//sum of reported distance and link cost to advertised neighbor
++
++  struct eigrp_metrics reported_metric;
++  struct eigrp_metrics total_metric;
++
++  struct eigrp_neighbor *adv_router; 		//ip address of advertising neighbor
++  u_char flags; 							//used for marking successor and FS
++
++  struct eigrp_interface *ei; 				//pointer for case of connected entry
++
++};
++
++//---------------------------------------------------------------------------------------------------------------------------------------------
++
++/* EIGRP Finite State Machine */
++
++struct eigrp_fsm_action_message
++{
++  u_char packet_type; 					//UPDATE, QUERY, SIAQUERY, SIAREPLY
++  struct eigrp *eigrp;					// which thread sent mesg
++  struct eigrp_neighbor *adv_router; 	//advertising neighbor
++  struct eigrp_neighbor_entry *entry;
++  struct eigrp_prefix_entry *prefix;
++  int data_type; // internal or external tlv type
++  union{
++    struct TLV_IPv4_External_type *ipv4_ext_data;
++    struct TLV_IPv4_Internal_type *ipv4_int_type;
++  }data;
++};
++
++#endif /* _ZEBRA_EIGRP_STRUCTURES_H_ */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_topology.c eigrp/eigrpd/eigrp_topology.c
+--- a/eigrpd/eigrp_topology.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_topology.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,549 @@
++/*
++ * EIGRP Topology Table.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "prefix.h"
++#include "table.h"
++#include "memory.h"
++#include "log.h"
++#include "linklist.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_network.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_topology.h"
++#include "eigrpd/eigrp_fsm.h"
++
++static int
++eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *, struct eigrp_prefix_entry *);
++static void
++eigrp_prefix_entry_del(struct eigrp_prefix_entry *);
++static int
++eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *,
++    struct eigrp_neighbor_entry *);
++
++/*
++ * asdf;laksdjf;lajsdf;kasdjf;asdjf;
++ * asdfaskdjfa;sdkjf;adlskj
++ * Returns linkedlist used as topology table
++ * cmp - assigned function for comparing topology nodes
++ * del - assigned function executed before deleting topology node by list function
++ */
++struct list *
++eigrp_topology_new()
++{
++  struct list* new = list_new();
++  new->cmp = (int
++  (*)(void *, void *)) eigrp_prefix_entry_cmp;
++  new->del = (void
++  (*)(void *)) eigrp_prefix_entry_del;
++
++  return new;
++}
++
++/*
++ * Topology node comparison
++ */
++
++static int
++eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *node1,
++    struct eigrp_prefix_entry *node2)
++{
++  if (node1->af == AF_INET)
++    {
++      if (node2->af == AF_INET)
++        {
++          if (node1->destination_ipv4->prefix.s_addr
++              < node2->destination_ipv4->prefix.s_addr)
++            {
++              return -1; // if it belong above node2
++            }
++          else
++            {
++              if (node1->destination_ipv4->prefix.s_addr
++                  > node2->destination_ipv4->prefix.s_addr)
++                {
++                  return 1; //if it belongs under node2
++                }
++              else
++                {
++                  return 0; // same value... ERROR...in case of adding same prefix again
++                }
++            }
++        }
++      else
++        {
++          return 1;
++        }
++    }
++  else
++    { // TODO check if the prefix dont exists
++      return 1; // add to end
++    }
++}
++
++/*
++ * Topology node delete
++ */
++
++static void
++eigrp_prefix_entry_del(struct eigrp_prefix_entry *node)
++{
++  list_delete_all_node(node->entries);
++  list_free(node->entries);
++}
++
++/*
++ * Returns new created toplogy node
++ * cmp - assigned function for comparing topology entry
++ */
++
++struct eigrp_prefix_entry *
++eigrp_prefix_entry_new()
++{
++  struct eigrp_prefix_entry *new;
++  new = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY, sizeof(struct eigrp_prefix_entry));
++  new->entries = list_new();
++  new->rij = list_new();
++  new->entries->cmp = (int
++  (*)(void *, void *)) eigrp_neighbor_entry_cmp;
++  new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC;
++  new->destination_ipv4 = NULL;
++  new->destination_ipv6 = NULL;
++
++  return new;
++}
++
++/*
++ * Topology entry comparison
++ */
++
++static int
++eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *entry1,
++    struct eigrp_neighbor_entry *entry2)
++{
++  if (entry1->distance < entry2->distance) // parameter used in list_add_sort ()
++    return -1; // actually set to sort by distance
++  if (entry1->distance > entry2->distance)
++    return 1;
++
++  return 0;
++}
++
++/*
++ * Returns new topology entry
++ */
++
++struct eigrp_neighbor_entry *
++eigrp_neighbor_entry_new()
++{
++  struct eigrp_neighbor_entry *new;
++
++  new = XCALLOC(MTYPE_EIGRP_NEIGHBOR_ENTRY,
++      sizeof(struct eigrp_neighbor_entry));
++  new->reported_distance = EIGRP_MAX_METRIC;
++  new->distance = EIGRP_MAX_METRIC;
++
++  return new;
++}
++
++/*
++ * Freeing topology table list
++ */
++
++void
++eigrp_topology_free(struct list *list)
++{
++  list_free(list);
++}
++
++/*
++ * Deleting all topology nodes in table
++ */
++
++void
++eigrp_topology_cleanup(struct list *topology)
++{
++  assert(topology);
++
++  eigrp_topology_delete_all(topology);
++}
++
++/*
++ * Adding topology node to topology table
++ */
++
++void
++eigrp_prefix_entry_add(struct list *topology, struct eigrp_prefix_entry *node)
++{
++  if (listnode_lookup(topology, node) == NULL)
++    {
++      listnode_add_sort(topology, node);
++    }
++}
++
++/*
++ * Adding topology entry to topology node
++ */
++
++void
++eigrp_neighbor_entry_add(struct eigrp_prefix_entry *node,
++    struct eigrp_neighbor_entry *entry)
++{
++  if (listnode_lookup(node->entries, entry) == NULL)
++    {
++      listnode_add_sort(node->entries, entry);
++      entry->prefix = node;
++    }
++}
++
++/*
++ * Deleting topology node from topology table
++ */
++
++void
++eigrp_prefix_entry_delete(struct list *topology,
++    struct eigrp_prefix_entry *node)
++{
++  if (listnode_lookup(topology, node) != NULL)
++    {
++      list_delete_all_node(node->entries);
++      list_free(node->entries);
++      list_free(node->rij);
++      listnode_delete(topology, node);
++      XFREE(MTYPE_EIGRP_PREFIX_ENTRY,node);
++    }
++}
++
++/*
++ * Deleting topology entry from topology node
++ */
++
++void
++eigrp_neighbor_entry_delete(struct eigrp_prefix_entry *node,
++    struct eigrp_neighbor_entry *entry)
++{
++  if (listnode_lookup(node->entries, entry) != NULL)
++    {
++      listnode_delete(node->entries, entry);
++      XFREE(MTYPE_EIGRP_NEIGHBOR_ENTRY,entry);
++    }
++}
++
++/*
++ * Deleting all nodes from topology table
++ */
++
++void
++eigrp_topology_delete_all(struct list *topology)
++{
++  list_delete_all_node(topology);
++}
++
++/*
++ * Return 0 if topology is not empty
++ * otherwise return 1
++ */
++
++unsigned int
++eigrp_topology_table_isempty(struct list *topology)
++{
++  if (topology->count)
++    return 1;
++  else
++    return 0;
++}
++
++struct eigrp_prefix_entry *
++eigrp_topology_table_lookup_ipv4(struct list *topology_table,
++    struct prefix_ipv4 * address)
++{
++  struct eigrp_prefix_entry *data;
++  struct listnode *node;
++  for (ALL_LIST_ELEMENTS_RO(topology_table, node, data))
++    {
++
++      if ((data->af == AF_INET)
++          && (data->destination_ipv4->prefix.s_addr == address->prefix.s_addr)
++          && (data->destination_ipv4->prefixlen == address->prefixlen))
++        return data;
++    }
++
++  return NULL;
++}
++/* TODO
++ struct eigrp_prefix_entry *
++ eigrp_topology_table_lookup_ipv6 (struct list *topology_table,
++ struct prefix_ipv6 * address)
++ {
++ struct eigrp_prefix_entry *data;
++ struct listnode *node, *nnode;
++ for (ALL_LIST_ELEMENTS (topology_table, node, nnode, data))
++ {
++
++ if (comparison)
++ return data;
++ }
++
++ return NULL;
++ }
++ */
++struct list *
++eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
++{
++  struct list *successors = list_new();
++  ;
++  struct eigrp_neighbor_entry *data;
++  struct listnode *node1, *node2;
++  for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data))
++    {
++      if (data->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)
++        {
++          listnode_add(successors, data);
++        }
++    }
++
++  return successors;
++}
++
++/*extern struct eigrp_neighbor_entry *
++ eigrp_topology_get_fsuccessor (struct eigrp_prefix_entry *table_node)
++ {
++ struct eigrp_neighbor_entry *data;
++ struct listnode *node, *nnode;
++ for (ALL_LIST_ELEMENTS (table_node->entries, node, nnode, data))
++ {
++ if ((data->flags & EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG) == 1)
++ {
++ return data;
++ }
++ }
++
++ return NULL;
++ }*/
++
++struct eigrp_neighbor_entry *
++eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr)
++{
++  struct eigrp_neighbor_entry *data;
++  struct listnode *node, *nnode;
++  for (ALL_LIST_ELEMENTS(entries, node, nnode, data))
++    {
++      if (data->adv_router == nbr)
++        {
++          return data;
++        }
++    }
++
++  return NULL;
++}
++
++int
++eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg)
++{
++  struct eigrp *eigrp = msg->eigrp;
++  struct eigrp_prefix_entry *prefix = msg->prefix;
++  struct eigrp_neighbor_entry *entry = msg->entry;
++  int change = 0;
++  assert(entry);
++
++  struct TLV_IPv4_External_type *ext_data = NULL;
++  struct TLV_IPv4_Internal_type *int_data = NULL;
++  if (msg->data_type == EIGRP_TLV_IPv4_INT)
++    {
++      int_data = msg->data.ipv4_int_type;
++      if (eigrp_metrics_is_same(&int_data->metric,&entry->reported_metric))
++        {
++          return 0; // No change
++        }
++      change =
++          entry->reported_distance
++              < eigrp_calculate_metrics(eigrp, &int_data->metric) ? 1 :
++          entry->reported_distance
++              > eigrp_calculate_metrics(eigrp, &int_data->metric) ? 2 : 3; // Increase : Decrease : No change
++      entry->reported_metric = int_data->metric;
++      entry->reported_distance = eigrp_calculate_metrics(eigrp,
++          &int_data->metric);
++      entry->distance = eigrp_calculate_total_metrics(eigrp, entry);
++    }
++  else
++    {
++      ext_data = msg->data.ipv4_ext_data;
++    }
++  /*
++   * Move to correct position in list according to new distance
++   */
++  listnode_delete(prefix->entries, entry);
++  listnode_add_sort(prefix->entries, entry);
++
++  return change;
++}
++
++void
++eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
++{
++  struct list *table = eigrp->topology_table;
++  struct eigrp_prefix_entry *data;
++  struct listnode *node, *nnode;
++  for (ALL_LIST_ELEMENTS(table, node, nnode, data))
++    {
++      eigrp_topology_update_node_flags(data);
++    }
++}
++
++void
++eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
++{
++  struct listnode *node;
++  struct eigrp_neighbor_entry *entry;
++  struct eigrp *eigrp = eigrp_lookup();
++
++  for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry))
++    {
++      if ((entry->distance <= (u_int64_t)(dest->distance*eigrp->variance)) && entry->distance != EIGRP_MAX_METRIC) // is successor
++        {
++          entry->flags |= EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
++          entry->flags &= 0xfd; // 1111 1101 set fs flag to zero
++        }
++      else if (entry->reported_distance < dest->fdistance) // is feasible successor
++        {
++          entry->flags |= EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG;
++          entry->flags &= 0xfe; // 1111 1110 set successor flag to zero
++        }
++      else
++        {
++          entry->flags &= 0xfc; // 1111 1100 set successor and fs flag to zero
++        }
++    }
++}
++
++void
++eigrp_update_routing_table(struct eigrp_prefix_entry * prefix)
++{
++  struct listnode *node;
++  struct eigrp_neighbor_entry *entry;
++
++  for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry))
++    {
++      if (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)
++        {
++          if (!(entry->flags & EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG))
++            {
++              eigrp_zebra_route_add(prefix->destination_ipv4, entry);
++              entry->flags += EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG;
++            }
++        }
++      else if (entry->flags & EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG)
++        {
++          eigrp_zebra_route_delete(prefix->destination_ipv4, entry);
++          entry->flags -= EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG;
++        }
++    }
++}
++
++void
++eigrp_topology_neighbor_down(struct eigrp *eigrp, struct eigrp_neighbor * nbr)
++{
++  struct listnode *node1, *node11, *node2, *node22;
++  struct eigrp_prefix_entry *prefix;
++  struct eigrp_neighbor_entry *entry;
++
++  for (ALL_LIST_ELEMENTS(eigrp->topology_table, node1, node11, prefix))
++    {
++      for (ALL_LIST_ELEMENTS(prefix->entries, node2, node22, entry))
++        {
++          if (entry->adv_router == nbr)
++            {
++              struct eigrp_fsm_action_message *msg;
++              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
++                  sizeof(struct eigrp_fsm_action_message));
++              struct TLV_IPv4_Internal_type * tlv = eigrp_IPv4_InternalTLV_new();
++              tlv->metric.delay = EIGRP_MAX_METRIC;
++              msg->packet_type = EIGRP_OPC_UPDATE;
++              msg->eigrp = eigrp;
++              msg->data_type = EIGRP_TLV_IPv4_INT;
++              msg->adv_router = nbr;
++              msg->data.ipv4_int_type = tlv;
++              msg->entry = entry;
++              msg->prefix = prefix;
++              int event = eigrp_get_fsm_event(msg);
++              eigrp_fsm_event(msg, event);
++            }
++        }
++    }
++
++  eigrp_query_send_all(eigrp);
++  eigrp_update_send_all(eigrp,nbr->ei);
++
++}
++
++void
++eigrp_update_topology_table_prefix(struct list * table, struct eigrp_prefix_entry * prefix)
++{
++	struct listnode *node1, *node2;
++
++	  struct eigrp_neighbor_entry *entry;
++	      for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry))
++	        {
++	    	  if(entry->distance == EIGRP_MAX_METRIC)
++	    	  {
++	    		  eigrp_neighbor_entry_delete(prefix,entry);
++	    	  }
++	        }
++	      if(prefix->distance == EIGRP_MAX_METRIC && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED)
++	      {
++	    	  eigrp_prefix_entry_delete(table,prefix);
++	      }
++}
++/*int
++ eigrp_topology_get_successor_count (struct eigrp_prefix_entry *prefix)
++ {
++
++ struct listnode *node;
++ struct eigrp_neighbor_entry *entry;
++
++ int count = 0;
++
++ for (ALL_LIST_ELEMENTS_RO (prefix->entries,node,entry))
++ {
++ if ((entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) == EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)
++ {
++ count ++;
++ }
++ }
++
++ return count;
++ }
++ */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_topology.h eigrp/eigrpd/eigrp_topology.h
+--- a/eigrpd/eigrp_topology.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_topology.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,70 @@
++/*
++ * EIGRP Topology Table.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRP_TOPOLOGY_H
++#define _ZEBRA_EIGRP_TOPOLOGY_H
++
++
++/* EIGRP Topology table related functions. */
++extern struct list *eigrp_topology_new (void);
++extern void eigrp_topology_init (struct list*);
++extern struct eigrp_prefix_entry *eigrp_prefix_entry_new (void);
++extern struct eigrp_neighbor_entry *eigrp_neighbor_entry_new (void);
++extern void eigrp_topology_free (struct list *);
++extern void eigrp_topology_cleanup (struct list *);
++extern void eigrp_prefix_entry_add (struct list *, struct eigrp_prefix_entry *);
++extern void eigrp_neighbor_entry_add (struct eigrp_prefix_entry *, struct eigrp_neighbor_entry *);
++extern void eigrp_prefix_entry_delete (struct list *, struct eigrp_prefix_entry *);
++extern void eigrp_neighbor_entry_delete (struct eigrp_prefix_entry *, struct eigrp_neighbor_entry *);
++extern void eigrp_topology_delete_all (struct list *);
++extern unsigned int eigrp_topology_table_isempty (struct list *);
++extern struct eigrp_prefix_entry *eigrp_topology_table_lookup_ipv4 (struct list *, struct prefix_ipv4 *);
++extern struct list *eigrp_topology_get_successor (struct eigrp_prefix_entry *);
++//extern struct eigrp_neighbor_entry *eigrp_topology_get_fsuccessor (struct eigrp_prefix_entry *);
++extern struct eigrp_neighbor_entry *eigrp_prefix_entry_lookup (struct list *, struct eigrp_neighbor *);
++extern void eigrp_topology_update_all_node_flags (struct eigrp *);
++extern void eigrp_topology_update_node_flags (struct eigrp_prefix_entry *);
++extern int eigrp_topology_update_distance ( struct eigrp_fsm_action_message *);
++extern void eigrp_update_routing_table(struct eigrp_prefix_entry *);
++extern void eigrp_topology_neighbor_down(struct eigrp *, struct eigrp_neighbor *);
++extern void eigrp_update_topology_table_prefix(struct list *, struct eigrp_prefix_entry * );
++//extern int eigrp_topology_get_successor_count (struct eigrp_prefix_entry *);
++/* Set all stats to -1 (LSA_SPF_NOT_EXPLORED). */
++/*extern void eigrp_lsdb_clean_stat (struct eigrp_lsdb *lsdb);
++extern struct eigrp_lsa *eigrp_lsdb_lookup_by_id (struct eigrp_lsdb *, u_char,
++                                        struct in_addr, struct in_addr);
++extern struct eigrp_lsa *eigrp_lsdb_lookup_by_id_next (struct eigrp_lsdb *, u_char,
++                                             struct in_addr, struct in_addr,
++                                             int);
++extern unsigned long eigrp_lsdb_count_all (struct eigrp_lsdb *);
++extern unsigned long eigrp_lsdb_count (struct eigrp_lsdb *, int);
++extern unsigned long eigrp_lsdb_count_self (struct eigrp_lsdb *, int);
++extern unsigned int eigrp_lsdb_checksum (struct eigrp_lsdb *, int);
++extern unsigned long eigrp_lsdb_isempty (struct eigrp_lsdb *);
++*/
++#endif
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_update.c eigrp/eigrpd/eigrp_update.c
+--- a/eigrpd/eigrp_update.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_update.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,442 @@
++/*
++ * EIGRP Sending and Receiving EIGRP Update Packets.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "thread.h"
++#include "memory.h"
++#include "linklist.h"
++#include "prefix.h"
++#include "if.h"
++#include "table.h"
++#include "sockunion.h"
++#include "stream.h"
++#include "log.h"
++#include "sockopt.h"
++#include "checksum.h"
++#include "md5.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_macros.h"
++#include "eigrpd/eigrp_topology.h"
++#include "eigrpd/eigrp_fsm.h"
++
++
++/*
++ * EIGRP UPDATE read function
++ */
++void
++eigrp_update_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
++                      struct stream * s, struct eigrp_interface *ei, int size)
++{
++  struct eigrp_neighbor *nbr;
++  struct TLV_IPv4_Internal_type *tlv;
++  struct eigrp_prefix_entry *pe;
++  struct eigrp_neighbor_entry *ne;
++  u_int32_t flags;
++  u_int16_t type;
++  uint16_t  length;
++  u_char same;
++  struct access_list *alist;
++
++  /* increment statistics. */
++  ei->update_in++;
++
++  /* get neighbor struct */
++  nbr = eigrp_nbr_get(ei, eigrph, iph);
++
++  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
++  assert(nbr);
++
++  flags = ntohl(eigrph->flags);
++
++  if (flags & EIGRP_CR_FLAG)
++    {
++      return;
++    }
++
++  same = 0;
++  if((nbr->recv_sequence_number) == (ntohl(eigrph->sequence)))
++      same = 1;
++
++  nbr->recv_sequence_number = ntohl(eigrph->sequence);
++
++  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
++    zlog_debug("Processing Update size[%u] int(%s) nbr(%s) seq [%u] flags [%0x]",
++               size, ifindex2ifname(nbr->ei->ifp->ifindex),
++               inet_ntoa(nbr->src),
++               nbr->recv_sequence_number, flags);
++
++    if((flags & EIGRP_INIT_FLAG) && (!same))
++    {   /* When in pending state, send INIT update only if it wasn't
++        already sent before (only if init_sequence is 0) */
++        if((nbr->state == EIGRP_NEIGHBOR_PENDING) && (nbr->init_sequence_number == 0))
++          eigrp_update_send_init(nbr);
++
++        if (nbr->state == EIGRP_NEIGHBOR_UP)
++          {
++            eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
++            eigrp_topology_neighbor_down(nbr->ei->eigrp,nbr);
++            nbr->recv_sequence_number = ntohl(eigrph->sequence);
++            zlog_info("Neighbor %s (%s) is down: peer restarted",
++                      inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
++            eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING);
++            zlog_info("Neighbor %s (%s) is pending: new adjacency",
++                      inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
++            eigrp_update_send_init(nbr);
++          }
++    }
++
++  /*If there is topology information*/
++  while (s->endp > s->getp)
++    {
++      type = stream_getw(s);
++      if (type == EIGRP_TLV_IPv4_INT)
++        {
++          stream_set_getp(s, s->getp - sizeof(u_int16_t));
++
++          tlv = eigrp_read_ipv4_tlv(s);
++
++          /*searching if destination exists */
++          struct prefix_ipv4 *dest_addr;
++          dest_addr = prefix_ipv4_new();
++          dest_addr->prefix = tlv->destination;
++          dest_addr->prefixlen = tlv->prefix_length;
++          struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
++              eigrp->topology_table, dest_addr);
++
++          /*if exists it comes to DUAL*/
++          if (dest != NULL)
++            {
++              struct eigrp_fsm_action_message *msg;
++              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
++                  sizeof(struct eigrp_fsm_action_message));
++              struct eigrp_neighbor_entry *entry =
++                  eigrp_prefix_entry_lookup(dest->entries, nbr);
++
++              msg->packet_type = EIGRP_OPC_UPDATE;
++              msg->eigrp = eigrp;
++              msg->data_type = EIGRP_TLV_IPv4_INT;
++              msg->adv_router = nbr;
++              msg->data.ipv4_int_type = tlv;
++              msg->entry = entry;
++              msg->prefix = dest;
++              int event = eigrp_get_fsm_event(msg);
++              eigrp_fsm_event(msg, event);
++            }
++          else
++            {
++              /*Here comes topology information save*/
++              pe = eigrp_prefix_entry_new();
++              pe->serno = eigrp->serno;
++              pe->destination_ipv4 = dest_addr;
++              pe->af = AF_INET;
++              pe->state = EIGRP_FSM_STATE_PASSIVE;
++              pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE;
++
++              ne = eigrp_neighbor_entry_new();
++              ne->ei = ei;
++              ne->adv_router = nbr;
++              ne->reported_metric = tlv->metric;
++              ne->reported_distance = eigrp_calculate_metrics(eigrp,
++                  &tlv->metric);
++
++
++              /*
++			   * Check if there is any access-list on interface (IN direction)
++			   *  and set distance to max
++			   */
++			  alist = ei->list[EIGRP_FILTER_IN];
++
++			  if (alist) {
++				  zlog_info ("ALIST:");
++				  zlog_info (alist->name);
++			  } else {
++				  zlog_info("ALIST je prazdny");
++			  }
++
++			  if (alist && access_list_apply (alist,
++						 (struct prefix *) dest_addr) == FILTER_DENY)
++			  {
++				  zlog_info("Nastavujem metriku na MAX");
++				  ne->distance = 1600000;
++			  } else {
++				  zlog_info("NENastavujem metriku ");
++				  ne->distance = eigrp_calculate_total_metrics(eigrp, ne);
++			  }
++			  zlog_info("Distance: %d", ne->distance);
++
++              pe->fdistance = pe->distance = pe->rdistance =
++                  ne->distance;
++              ne->prefix = pe;
++              ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
++
++              eigrp_prefix_entry_add(eigrp->topology_table, pe);
++              eigrp_neighbor_entry_add(pe, ne);
++              pe->distance = pe->fdistance = pe->rdistance =
++                  ne->distance;
++              pe->reported_metric = ne->total_metric;
++              eigrp_topology_update_node_flags(pe);
++
++              pe->req_action |= EIGRP_FSM_NEED_UPDATE;
++              listnode_add(eigrp->topology_changes_internalIPV4, pe);
++            }
++          eigrp_IPv4_InternalTLV_free (tlv);
++        }
++    }
++
++  /*
++   * We don't need to send separate Ack for INIT Update. INIT will be acked in EOT Update.
++   */
++  if ((nbr->state == EIGRP_NEIGHBOR_UP) && !(flags & EIGRP_INIT_FLAG))
++    {
++      eigrp_hello_send_ack(nbr);
++    }
++
++  eigrp_query_send_all(eigrp);
++  eigrp_update_send_all(eigrp, ei);
++}
++
++/*send EIGRP Update packet*/
++void
++eigrp_update_send_init (struct eigrp_neighbor *nbr)
++{
++  struct eigrp_packet *ep;
++  u_int16_t length = EIGRP_HEADER_LEN;
++
++  ep = eigrp_packet_new(nbr->ei->ifp->mtu);
++
++  /* Prepare EIGRP INIT UPDATE header */
++  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
++    zlog_debug("Enqueuing Update Init Seq [%u] Ack [%u]",
++               nbr->ei->eigrp->sequence_number,
++               nbr->recv_sequence_number);
++
++  eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_INIT_FLAG,
++                           nbr->ei->eigrp->sequence_number,
++                           nbr->recv_sequence_number);
++
++  // encode Authentication TLV, if needed
++  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
++    {
++      length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
++      eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_INIT_FLAG);
++    }
++
++  /* EIGRP Checksum */
++  eigrp_packet_checksum(nbr->ei, ep->s, length);
++
++  ep->length = length;
++  ep->dst.s_addr = nbr->src.s_addr;
++
++  /*This ack number we await from neighbor*/
++  nbr->init_sequence_number = nbr->ei->eigrp->sequence_number;
++  ep->sequence_number = nbr->ei->eigrp->sequence_number;
++  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
++    zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
++               ep->length, ep->sequence_number, inet_ntoa(ep->dst));
++
++  /*Put packet to retransmission queue*/
++  eigrp_fifo_push_head(nbr->retrans_queue, ep);
++
++  if (nbr->retrans_queue->count == 1)
++    {
++      eigrp_send_packet_reliably(nbr);
++    }
++}
++
++void
++eigrp_update_send_EOT (struct eigrp_neighbor *nbr)
++{
++  struct eigrp_packet *ep;
++//  struct eigrp_packet *ep_multicast;
++  u_int16_t length = EIGRP_HEADER_LEN;
++  struct eigrp_neighbor_entry *te;
++  struct eigrp_prefix_entry *pe;
++  struct listnode *node, *node2, *nnode, *nnode2;
++
++  ep = eigrp_packet_new(nbr->ei->ifp->mtu);
++
++  /* Prepare EIGRP EOT UPDATE header */
++  eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG,
++                           nbr->ei->eigrp->sequence_number,
++                           nbr->recv_sequence_number);
++
++  // encode Authentication TLV, if needed
++  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
++    {
++      length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
++    }
++
++  for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe))
++    {
++      for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te))
++        {
++          if ((te->ei == nbr->ei)
++              && (te->prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE))
++            continue;
++
++          length += eigrp_add_internalTLV_to_stream(ep->s, pe);
++        }
++    }
++
++  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
++    {
++      eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
++    }
++
++  /* EIGRP Checksum */
++  eigrp_packet_checksum(nbr->ei, ep->s, length);
++
++  ep->length = length;
++  ep->dst.s_addr = nbr->src.s_addr;
++
++  /*This ack number we await from neighbor*/
++  ep->sequence_number = nbr->ei->eigrp->sequence_number;
++
++  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
++    zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
++               ep->length, ep->sequence_number, inet_ntoa(ep->dst));
++
++  /*Put packet to retransmission queue*/
++  eigrp_fifo_push_head(nbr->retrans_queue, ep);
++
++  if (nbr->retrans_queue->count == 1)
++    {
++      eigrp_send_packet_reliably(nbr);
++    }
++
++}
++
++void
++eigrp_update_send (struct eigrp_interface *ei)
++{
++  struct eigrp_packet *ep, *duplicate;
++  struct listnode *node, *nnode, *node2, *nnode2;
++  struct eigrp_neighbor *nbr;
++  struct eigrp_prefix_entry *pe;
++  u_char has_tlv;
++
++  u_int16_t length = EIGRP_HEADER_LEN;
++
++  ep = eigrp_packet_new(ei->ifp->mtu);
++
++  /* Prepare EIGRP INIT UPDATE header */
++  eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei, ep->s, 0,
++                           ei->eigrp->sequence_number, 0);
++
++  // encode Authentication TLV, if needed
++  if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
++    {
++      length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei);
++    }
++
++  has_tlv = 0;
++  for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe))
++    {
++      if(pe->req_action & EIGRP_FSM_NEED_UPDATE)
++        {
++    	  // TODO : ditribute-list <ACL> out should be checked here
++
++          length += eigrp_add_internalTLV_to_stream(ep->s, pe);
++          has_tlv = 1;
++        }
++    }
++
++  if(!has_tlv)
++    {
++      eigrp_packet_free(ep);
++      return;
++    }
++
++  if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
++    {
++      eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
++    }
++
++  /* EIGRP Checksum */
++  eigrp_packet_checksum(ei, ep->s, length);
++  ep->length = length;
++
++  ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS);
++
++  /*This ack number we await from neighbor*/
++  ep->sequence_number = ei->eigrp->sequence_number;
++
++  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
++    zlog_debug("Enqueuing Update length[%u] Seq [%u]",
++               length, ep->sequence_number);
++
++  for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr))
++    {
++      if (nbr->state == EIGRP_NEIGHBOR_UP)
++        {
++          /*Put packet to retransmission queue*/
++          eigrp_fifo_push_head(nbr->retrans_queue, ep);
++
++          if (nbr->retrans_queue->count == 1)
++            {
++              eigrp_send_packet_reliably(nbr);
++            }
++        }
++    }
++}
++
++void
++eigrp_update_send_all (struct eigrp *eigrp, struct eigrp_interface *exception)
++{
++
++  struct eigrp_interface *iface;
++  struct listnode *node, *node2, *nnode2;
++  struct eigrp_prefix_entry *pe;
++
++  for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface))
++    {
++      if (iface != exception)
++        {
++          eigrp_update_send(iface);
++        }
++    }
++
++  for (ALL_LIST_ELEMENTS(eigrp->topology_changes_internalIPV4, node2, nnode2, pe))
++    {
++      if(pe->req_action & EIGRP_FSM_NEED_UPDATE)
++        {
++          pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
++          listnode_delete(eigrp->topology_changes_internalIPV4, pe);
++          zlog_debug("UPDATE COUNT: %d", eigrp->topology_changes_internalIPV4->count);
++        }
++    }
++}
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_vty.c eigrp/eigrpd/eigrp_vty.c
+--- a/eigrpd/eigrp_vty.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_vty.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,1363 @@
++/*
++ * EIGRP VTY Interface.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "memory.h"
++#include "thread.h"
++#include "prefix.h"
++#include "table.h"
++#include "vty.h"
++#include "command.h"
++#include "plist.h"
++#include "log.h"
++#include "zclient.h"
++#include "keychain.h"
++#include "linklist.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_network.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_const.h"
++
++
++static int
++config_write_network (struct vty *vty, struct eigrp *eigrp)
++{
++  struct route_node *rn;
++
++  /* `network area' print. */
++  for (rn = route_top (eigrp->networks); rn; rn = route_next (rn))
++    if (rn->info)
++      {
++        /* Network print. */
++        vty_out (vty, " network %s/%d %s",
++                 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, VTY_NEWLINE);
++      }
++  /*Separate EIGRP configuration from the rest of the config*/
++  vty_out (vty, "!%s", VTY_NEWLINE);
++
++  return 0;
++}
++
++static int
++config_write_interfaces (struct vty *vty, struct eigrp *eigrp)
++{
++  struct eigrp_interface *ei;
++  struct listnode *node;
++
++  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
++    {
++      vty_out (vty, "interface %s%s", ei->ifp->name, VTY_NEWLINE);
++
++      if ((IF_DEF_PARAMS (ei->ifp)->auth_type) == EIGRP_AUTH_TYPE_MD5)
++        {
++          vty_out (vty, " ip authentication mode eigrp %d md5%s", eigrp->AS, VTY_NEWLINE);
++        }
++
++      if ((IF_DEF_PARAMS (ei->ifp)->auth_type) == EIGRP_AUTH_TYPE_SHA256)
++        {
++          vty_out (vty, " ip authentication mode eigrp %d hmac-sha-256%s", eigrp->AS, VTY_NEWLINE);
++        }
++
++      if(IF_DEF_PARAMS (ei->ifp)->auth_keychain)
++        {
++          vty_out (vty, " ip authentication key-chain eigrp %d %s%s",eigrp->AS,IF_DEF_PARAMS (ei->ifp)->auth_keychain, VTY_NEWLINE);
++        }
++
++      if ((IF_DEF_PARAMS (ei->ifp)->v_hello) != EIGRP_HELLO_INTERVAL_DEFAULT)
++        {
++          vty_out (vty, " ip hello-interval eigrp %d%s", IF_DEF_PARAMS (ei->ifp)->v_hello, VTY_NEWLINE);
++        }
++
++      if ((IF_DEF_PARAMS (ei->ifp)->v_wait) != EIGRP_HOLD_INTERVAL_DEFAULT)
++        {
++          vty_out (vty, " ip hold-time eigrp %d%s", IF_DEF_PARAMS (ei->ifp)->v_wait, VTY_NEWLINE);
++        }
++
++      /*Separate this EIGRP interface configuration from the others*/
++        vty_out (vty, "!%s", VTY_NEWLINE);
++    }
++
++  return 0;
++}
++
++static int
++eigrp_write_interface (struct vty *vty)
++{
++  int write=0;
++
++  return write;
++}
++
++DEFUN (router_eigrp,
++       router_eigrp_cmd,
++       "router eigrp <1-65535>",
++       "Enable a routing process\n"
++       "Start EIGRP configuration\n")
++{
++  vty->node = EIGRP_NODE;
++  vty->index = eigrp_get (argv[0]);
++
++  return CMD_SUCCESS;
++}
++
++
++DEFUN (no_router_eigrp,
++       no_router_eigrp_cmd,
++       "no router eigrp <1-65535>",
++       NO_STR
++       "Routing process\n"
++       "EIGRP configuration\n")
++{
++  vty->node = EIGRP_NODE;
++
++  /*TODO: */
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (eigrp_router_id,
++       eigrp_router_id_cmd,
++       "eigrp router-id A.B.C.D",
++       "EIGRP specific commands\n"
++       "Router ID for this EIGRP process\n"
++       "EIGRP Router-ID in IP address format\n")
++{
++  struct eigrp *eigrp = vty->index;
++  /*TODO: */
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (no_eigrp_router_id,
++       no_eigrp_router_id_cmd,
++       "no eigrp router-id A.B.C.D",
++       NO_STR
++       "EIGRP specific commands\n"
++       "Router ID for this EIGRP process\n"
++       "EIGRP Router-ID in IP address format\n")
++{
++  struct eigrp *eigrp = vty->index;
++  /*TODO: */
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (eigrp_passive_interface,
++       eigrp_passive_interface_cmd,
++       "passive-interface (" INT_TYPES_CMD_STR ")",
++       "Suppress routing updates on an interface\n"
++       INT_TYPES_DESC)
++{
++  struct eigrp *eigrp = vty->index;
++  /*TODO: */
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (no_eigrp_passive_interface,
++       no_eigrp_passive_interface_cmd,
++       "no passive-interface (" INT_TYPES_CMD_STR ")",
++       NO_STR
++       "Suppress routing updates on an interface\n"
++       INT_TYPES_DESC)
++{
++  struct eigrp *eigrp = vty->index;
++  /*TODO: */
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (eigrp_timers_active,
++       eigrp_timers_active_cmd,
++       "timers active-time (<1-65535> | disabled)",
++       "Adjust routing timers\n"
++       "Time limit for active state\n"
++       "Active state time limit in minutes\n"
++       "Disable time limit for active state\n")
++{
++  struct eigrp *eigrp = vty->index;
++  /*TODO: */
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (no_eigrp_timers_active,
++       no_eigrp_timers_active_cmd,
++       "no timers active-time (<1-65535> | disabled)",
++       NO_STR
++       "Adjust routing timers\n"
++       "Time limit for active state\n"
++       "Active state time limit in minutes\n"
++       "Disable time limit for active state\n")
++{
++  struct eigrp *eigrp = vty->index;
++  /*TODO: */
++
++  return CMD_SUCCESS;
++}
++
++
++DEFUN (eigrp_metric_weights,
++       eigrp_metric_weights_cmd,
++       "metric weights <0-255> <0-255> <0-255> <0-255> <0-255> ",
++       "Modify metrics and parameters for advertisement\n"
++       "Modify metric coefficients\n"
++       "K1\n"
++       "K2\n"
++       "K3\n"
++       "K4\n"
++       "K5\n")
++{
++  struct eigrp *eigrp = vty->index;
++  /*TODO: */
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (no_eigrp_metric_weights,
++       no_eigrp_metric_weights_cmd,
++       "no metric weights <0-255> <0-255> <0-255> <0-255> <0-255>",
++       "Modify metrics and parameters for advertisement\n"
++       "Modify metric coefficients\n"
++       "K1\n"
++       "K2\n"
++       "K3\n"
++       "K4\n"
++       "K5\n")
++{
++  struct eigrp *eigrp = vty->index;
++  /*TODO: */
++
++  return CMD_SUCCESS;
++}
++
++
++DEFUN (eigrp_network,
++       eigrp_network_cmd,
++       "network A.B.C.D/M",
++       "Enable routing on an IP network\n"
++       "EIGRP network prefix\n")
++{
++  struct eigrp *eigrp = vty->index;
++  struct prefix_ipv4 p;
++  int ret;
++
++  VTY_GET_IPV4_PREFIX ("network prefix", p, argv[0]);
++
++  ret = eigrp_network_set (eigrp, &p);
++
++  if (ret == 0)
++    {
++      vty_out (vty, "There is already same network statement.%s", VTY_NEWLINE);
++      return CMD_WARNING;
++    }
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (no_eigrp_network,
++       no_eigrp_network_cmd,
++       "no network A.B.C.D/M",
++       "Disable routing on an IP network\n"
++       "EIGRP network prefix\n")
++{
++  struct eigrp *eigrp = vty->index;
++  struct prefix_ipv4 p;
++  int ret;
++
++  VTY_GET_IPV4_PREFIX ("network prefix", p, argv[0]);
++
++  ret = eigrp_network_unset (eigrp, &p);
++
++  if (ret == 0)
++  {
++    vty_out (vty,"Can't find specified network configuration.%s", VTY_NEWLINE);
++    return CMD_WARNING;
++  }
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (eigrp_neighbor,
++       eigrp_neighbor_cmd,
++       "neighbor A.B.C.D (" INT_TYPES_CMD_STR ")",
++       "Specify a neighbor router\n"
++       "Neighbor address\n"
++       INT_TYPES_DESC)
++{
++  struct eigrp *eigrp = vty->index;
++  struct prefix_ipv4 p;
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (no_eigrp_neighbor,
++       no_eigrp_neighbor_cmd,
++       "no neighbor A.B.C.D (" INT_TYPES_CMD_STR ")",
++       NO_STR
++       "Specify a neighbor router\n"
++       "Neighbor address\n"
++       INT_TYPES_DESC)
++{
++  struct eigrp *eigrp = vty->index;
++  struct prefix_ipv4 p;
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (show_ip_eigrp_topology,
++       show_ip_eigrp_topology_cmd,
++       "show ip eigrp topology",
++       SHOW_STR
++       IP_STR
++       "IP-EIGRP show commands\n"
++       "IP-EIGRP topology\n")
++{
++  struct eigrp *eigrp;
++  struct listnode *node, *nnode, *node2, *nnode2;
++  struct eigrp_prefix_entry *tn;
++  struct eigrp_neighbor_entry *te;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++  {
++    vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++    return CMD_SUCCESS;
++  }
++
++  show_ip_eigrp_topology_header (vty, eigrp);
++
++  for (ALL_LIST_ELEMENTS (eigrp->topology_table, node, nnode, tn))
++  {
++    show_ip_eigrp_prefix_entry (vty,tn);
++    for (ALL_LIST_ELEMENTS (tn->entries, node2, nnode2, te))
++      {
++        if (((te->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) == EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)||
++            ((te->flags & EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG) == EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG))
++          show_ip_eigrp_neighbor_entry (vty, eigrp, te);
++      }
++    }
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (show_ip_eigrp_topology_all_links,
++       show_ip_eigrp_topology_all_links_cmd,
++       "show ip eigrp topology all-links",
++       SHOW_STR
++       IP_STR
++       "IP-EIGRP show commands\n"
++       "IP-EIGRP topology\n"
++       "Show all links in topology table\n")
++{
++  struct eigrp *eigrp;
++  struct listnode *node, *nnode, *node2, *nnode2;
++  struct eigrp_prefix_entry *tn;
++  struct eigrp_neighbor_entry *te;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  show_ip_eigrp_topology_header (vty, eigrp);
++
++  for (ALL_LIST_ELEMENTS (eigrp->topology_table, node, nnode, tn))
++    {
++      show_ip_eigrp_prefix_entry (vty,tn);
++      for (ALL_LIST_ELEMENTS (tn->entries, node2, nnode2, te))
++        {
++          show_ip_eigrp_neighbor_entry (vty, eigrp, te);
++        }
++    }
++
++  return CMD_SUCCESS;
++}
++
++ALIAS (show_ip_eigrp_topology,
++       show_ip_eigrp_topology_detail_cmd,
++       "show ip eigrp topology (A.B.C.D|A.B.C.D/nn|detail|summary)",
++       SHOW_STR
++       IP_STR
++       "IP-EIGRP show commands\n"
++       "IP-EIGRP topology\n"
++       "Netwok to display information about\n"
++       "IP prefix <network>/<length>, e.g., 192.168.0.0/16\n"
++       "Show all links in topology table\n"
++       "Show a summary of the topology table\n")
++
++DEFUN (show_ip_eigrp_interfaces,
++       show_ip_eigrp_interfaces_cmd,
++       "show ip eigrp interfaces",
++       SHOW_STR
++       IP_STR
++       "IP-EIGRP show commands\n"
++       "IP-EIGRP interfaces\n")
++{
++  struct eigrp_interface *ei;
++  struct eigrp *eigrp;
++  struct listnode *node;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  if (!argc)
++    {
++        show_ip_eigrp_interface_header (vty, eigrp);
++    }
++
++  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
++  {
++    if ((argc > 0) && ( strncmp (argv[0], "d", 1) == 0))
++      {
++        show_ip_eigrp_interface_header (vty, eigrp);
++      }
++
++  //	if ((strncmp (argv[1], "f", 1) == 0 && strncmp (eigrp_if_name_string (ei), "F",1) == 0) ||
++  //		(strncmp (argv[1], "l", 1) == 0 && strncmp (eigrp_if_name_string (ei), "L",1) == 0) ||
++  //		(strncmp (argv[1], "s", 1) == 0 && strncmp (eigrp_if_name_string (ei), "S",1) == 0))
++  //	{
++        show_ip_eigrp_interface_sub (vty, eigrp, ei);
++    //}
++
++    if ((argc > 0) && ( strncmp (argv[0], "d", 1) == 0))
++      {
++        show_ip_eigrp_interface_detail (vty, eigrp, ei);
++      }
++  }
++
++  return CMD_SUCCESS;
++}
++
++ALIAS (show_ip_eigrp_interfaces,
++	   show_ip_eigrp_interfaces_detail_cmd,
++	   "show ip eigrp interfaces (" INT_TYPES_CMD_STR ")",
++	   SHOW_STR
++	   IP_STR
++	   "IP-EIGRP show commands\n"
++	   "IP-EIGRP interfaces\n"
++	   INT_TYPES_DESC)
++
++DEFUN (show_ip_eigrp_neighbors,
++       show_ip_eigrp_neighbors_cmd,
++       "show ip eigrp neighbors",
++       SHOW_STR
++       IP_STR
++       "IP-EIGRP show commands\n"
++       "IP-EIGRP neighbors\n")
++{
++  struct eigrp *eigrp;
++  struct eigrp_interface *ei;
++  struct listnode *node, *node2, *nnode2;
++  struct eigrp_neighbor *nbr;
++  int detail = FALSE;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  detail = ((argc > 0) && (strncmp(argv[0], "d", 1) == 0));
++  show_ip_eigrp_neighbor_header (vty, eigrp);
++
++  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
++    {
++      for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
++        {
++	  if (detail || (nbr->state == EIGRP_NEIGHBOR_UP))
++	    show_ip_eigrp_neighbor_sub (vty, nbr, detail);
++        }
++    }
++
++  return CMD_SUCCESS;
++}
++
++ALIAS (show_ip_eigrp_neighbors,
++	   show_ip_eigrp_neighbors_detail_cmd,
++	   "show ip eigrp neighbors (" INT_TYPES_CMD_STR ")",
++	   SHOW_STR
++	   IP_STR
++	   "IP-EIGRP show commands\n"
++	   "IP-EIGRP neighbors\n"
++	   INT_TYPES_DESC)
++
++DEFUN (eigrp_if_delay,
++       eigrp_if_delay_cmd,
++       "delay <1-16777215>",
++       "Specify interface throughput delay\n"
++       "Throughput delay (tens of microseconds)\n")
++{
++  struct eigrp *eigrp;
++  u_int32_t delay;
++  struct listnode *node, *nnode, *node2, *nnode2;
++  struct eigrp_interface *ei;
++  struct interface *ifp;
++  struct eigrp_prefix_entry *pe;
++  struct eigrp_neighbor_entry *ne;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++
++      return CMD_SUCCESS;
++    }
++
++  delay = atoi (argv[0]);
++
++  /* delay range is <1-16777215>. */
++  if ((delay < 1 )|| (delay > 16777215))
++    {
++      vty_out (vty, "Interface delay is invalid%s", VTY_NEWLINE);
++
++      return CMD_WARNING;
++    }
++
++  ifp = vty->index;
++  IF_DEF_PARAMS (ifp)->delay = delay;
++
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (no_eigrp_if_delay,
++       no_eigrp_if_delay_cmd,
++       "no delay",
++       "No"
++       "Specify interface throughput delay\n")
++{
++  struct eigrp *eigrp;
++  struct listnode *node, *nnode, *node2, *nnode2;
++  struct eigrp_interface *ei;
++  struct interface *ifp;
++  struct eigrp_prefix_entry *pe;
++  struct eigrp_neighbor_entry *ne;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++
++      return CMD_SUCCESS;
++    }
++
++  ifp = vty->index;
++  IF_DEF_PARAMS (ifp)->delay = EIGRP_DELAY_DEFAULT;
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (eigrp_if_bandwidth,
++       eigrp_if_bandwidth_cmd,
++       "bandwidth <1-10000000>",
++       "Set bandwidth informational parameter\n"
++       "Bandwidth in kilobits\n")
++{
++  u_int32_t bandwidth;
++  struct eigrp *eigrp;
++  struct eigrp_interface *ei;
++  struct listnode *node, *nnode, *node2, *nnode2;
++  struct interface *ifp;
++  struct eigrp_prefix_entry *pe;
++  struct eigrp_neighbor_entry *ne;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  bandwidth = atoi (argv[0]);
++
++  /* bandwidth range is <1-10000000>. */
++  if ((bandwidth < 1) || (bandwidth > 10000000))
++    {
++      vty_out (vty, "Interface bandwidth is invalid%s", VTY_NEWLINE);
++      return CMD_WARNING;
++    }
++
++  ifp = vty->index;
++  IF_DEF_PARAMS (ifp)->bandwidth = bandwidth;
++
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (no_eigrp_if_bandwidth,
++       no_eigrp_if_bandwidth_cmd,
++       "bandwidth <1-10000000>",
++       "Set bandwidth informational parameter\n"
++       "Bandwidth in kilobits\n")
++{
++  u_int32_t bandwidth;
++  struct eigrp *eigrp;
++  struct eigrp_interface *ei;
++  struct listnode *node, *nnode, *node2, *nnode2;
++  struct interface *ifp;
++  struct eigrp_prefix_entry *pe;
++  struct eigrp_neighbor_entry *ne;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  bandwidth = atoi (argv[0]);
++
++  /* bandwidth range is <1-10000000>. */
++  if ((bandwidth < 1) || (bandwidth > 10000000))
++    {
++      vty_out (vty, "Interface bandwidth is invalid%s", VTY_NEWLINE);
++      return CMD_WARNING;
++    }
++
++  ifp = vty->index;
++  IF_DEF_PARAMS (ifp)->bandwidth = bandwidth;
++
++  for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
++    {
++      if (ei->ifp == ifp)
++        break;
++    }
++
++  for (ALL_LIST_ELEMENTS (eigrp->topology_table, node, nnode, pe))
++    {
++      for (ALL_LIST_ELEMENTS (pe->entries, node2, nnode2, ne))
++        {
++          /*TODO: */
++        }
++    }
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (eigrp_if_ip_hellointerval,
++       eigrp_if_ip_hellointerval_cmd,
++       "ip hello-interval eigrp <1-65535>",
++       "Interface Internet Protocol config commands\n"
++       "Configures EIGRP hello interval\n"
++       "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
++       "Seconds between hello transmissions\n")
++{
++  u_int32_t hello;
++  struct eigrp *eigrp;
++  struct interface *ifp;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  hello = atoi (argv[0]);
++
++  /* hello range is <1-65535> */
++  if ((hello < 1) || (hello > 65535))
++    {
++      vty_out (vty, "Hello-interval value is invalid%s", VTY_NEWLINE);
++      return CMD_WARNING;
++    }
++
++  ifp = vty->index;
++  IF_DEF_PARAMS (ifp)->v_hello = hello;
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (no_eigrp_if_ip_hellointerval,
++       no_eigrp_if_ip_hellointerval_cmd,
++       "no ip hello-interval eigrp",
++       "No"
++       "Interface Internet Protocol config commands\n"
++       "Configures EIGRP hello interval\n"
++       "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
++       "Seconds between hello transmissions\n")
++{
++  struct eigrp *eigrp;
++  struct interface *ifp;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  ifp = vty->index;
++  IF_DEF_PARAMS (ifp)->v_hello = EIGRP_HELLO_INTERVAL_DEFAULT;
++
++  return CMD_SUCCESS;
++}
++
++
++
++DEFUN (eigrp_if_ip_holdinterval,
++       eigrp_if_ip_holdinterval_cmd,
++       "ip hold-time eigrp <1-65535>",
++       "Interface Internet Protocol config commands\n"
++       "Configures EIGRP hello interval\n"
++       "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
++       "Seconds before neighbor is considered down\n")
++{
++  u_int32_t hold;
++  struct eigrp *eigrp;
++  struct interface *ifp;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  hold = atoi (argv[0]);
++
++  /* hello range is <1-65535> */
++  if ((hold < 1) || (hold > 65535))
++    {
++      vty_out (vty, "Hello-interval value is invalid%s", VTY_NEWLINE);
++      return CMD_WARNING;
++    }
++
++  ifp = vty->index;
++  IF_DEF_PARAMS (ifp)->v_wait = hold;
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (eigrp_ip_summary_address,
++       eigrp_ip_summary_address_cmd,
++       "ip summary-address eigrp <1-65535> A.B.C.D/M",
++       "Interface Internet Protocol config commands\n"
++       "Perform address summarization\n"
++       "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
++       "AS number\n"
++       "Summary <network>/<length>, e.g. 192.168.0.0/16\n")
++{
++  u_int32_t AS;
++  struct eigrp *eigrp;
++  struct interface *ifp;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  AS = atoi (argv[0]);
++
++  /* hello range is <1-65535> */
++  if ((AS < 1) || (AS > 65535))
++    {
++      vty_out (vty, "AS value is invalid%s", VTY_NEWLINE);
++      return CMD_WARNING;
++    }
++
++  ifp = vty->index;
++
++  /*TODO: */
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (no_eigrp_ip_summary_address,
++       no_eigrp_ip_summary_address_cmd,
++       "no ip summary-address eigrp <1-65535> A.B.C.D/M",
++       NO_STR
++       "Interface Internet Protocol config commands\n"
++       "Perform address summarization\n"
++       "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
++       "AS number\n"
++       "Summary <network>/<length>, e.g. 192.168.0.0/16\n")
++{
++  u_int32_t AS;
++  struct eigrp *eigrp;
++  struct interface *ifp;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  AS = atoi (argv[0]);
++
++  /* hello range is <1-65535> */
++  if ((AS < 1) || (AS > 65535))
++    {
++      vty_out (vty, "AS value is invalid%s", VTY_NEWLINE);
++      return CMD_WARNING;
++    }
++
++  ifp = vty->index;
++
++  /*TODO: */
++
++  return CMD_SUCCESS;
++}
++
++
++
++DEFUN (no_eigrp_if_ip_holdinterval,
++       no_eigrp_if_ip_holdinterval_cmd,
++       "no ip hold-time eigrp",
++       "No"
++       "Interface Internet Protocol config commands\n"
++       "Configures EIGRP hello interval\n"
++       "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
++       "Seconds before neighbor is considered down\n")
++{
++  struct eigrp *eigrp;
++  struct interface *ifp;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  ifp = vty->index;
++  IF_DEF_PARAMS (ifp)->v_wait = EIGRP_HOLD_INTERVAL_DEFAULT;
++
++  return CMD_SUCCESS;
++}
++
++static int
++str2auth_type (const char *str, struct interface *ifp)
++{
++  /* Sanity check. */
++   if (str == NULL)
++     return CMD_WARNING;
++
++  if(strncmp(str, "md5",3) == 0)
++    {
++      IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_MD5;
++      return CMD_SUCCESS;
++    }
++  else if(strncmp(str, "hmac-sha-256",12) == 0)
++    {
++      IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_SHA256;
++      return CMD_SUCCESS;
++    }
++
++  return CMD_WARNING;
++
++}
++
++DEFUN (eigrp_authentication_mode,
++       eigrp_authentication_mode_cmd,
++       "ip authentication mode eigrp <1-65535> (md5|hmac-sha-256)",
++       "Interface Internet Protocol config commands\n"
++       "Authentication subcommands\n"
++       "Mode\n"
++       "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
++       "Autonomous system number\n"
++       "Keyed message digest\n"
++       "HMAC SHA256 algorithm \n")
++{
++  struct eigrp *eigrp;
++  struct interface *ifp;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  ifp = vty->index;
++//  if(strncmp(argv[2], "md5",3))
++//    IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_MD5;
++//  else if(strncmp(argv[2], "hmac-sha-256",12))
++//    IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_SHA256;
++
++  return str2auth_type(argv[1], ifp);
++}
++
++DEFUN (no_eigrp_authentication_mode,
++       no_eigrp_authentication_mode_cmd,
++       "no ip authentication mode eigrp <1-65535> (md5|hmac-sha-256)",
++       "Disable\n"
++       "Interface Internet Protocol config commands\n"
++       "Authentication subcommands\n"
++       "Mode\n"
++       "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
++       "Autonomous system number\n"
++       "Keyed message digest\n"
++       "HMAC SHA256 algorithm \n")
++{
++  struct eigrp *eigrp;
++  struct interface *ifp;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  ifp = vty->index;
++  IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_NONE;
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (eigrp_authentication_keychain,
++       eigrp_authentication_keychain_cmd,
++       "ip authentication key-chain eigrp <1-65535> WORD",
++       "Interface Internet Protocol config commands\n"
++       "Authentication subcommands\n"
++       "Key-chain\n"
++       "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
++       "Autonomous system number\n"
++       "Name of key-chain\n")
++{
++  struct eigrp *eigrp;
++  struct interface *ifp;
++  struct keychain *keychain;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  ifp = vty->index;
++  keychain = keychain_lookup (argv[1]);
++  if(keychain != NULL)
++    {
++      if(IF_DEF_PARAMS (ifp)->auth_keychain)
++        {
++          free (IF_DEF_PARAMS (ifp)->auth_keychain);
++          IF_DEF_PARAMS (ifp)->auth_keychain = strdup(keychain->name);
++        }
++      else
++        IF_DEF_PARAMS (ifp)->auth_keychain = strdup(keychain->name);
++    }
++  else
++    vty_out(vty,"Key chain with specified name not found%s", VTY_NEWLINE);
++
++  return CMD_SUCCESS;
++}
++
++DEFUN (no_eigrp_authentication_keychain,
++       no_eigrp_authentication_keychain_cmd,
++       "no ip authentication key-chain eigrp <1-65535> WORD",
++       "Disable\n"
++       "Interface Internet Protocol config commands\n"
++       "Authentication subcommands\n"
++       "Key-chain\n"
++       "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
++       "Autonomous system number\n"
++       "Name of key-chain\n")
++{
++  struct eigrp *eigrp;
++  struct interface *ifp;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    {
++      vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++      return CMD_SUCCESS;
++    }
++
++  ifp = vty->index;
++  if((IF_DEF_PARAMS (ifp)->auth_keychain != NULL) && (strcmp(IF_DEF_PARAMS (ifp)->auth_keychain,argv[1])==0))
++    {
++      free (IF_DEF_PARAMS (ifp)->auth_keychain);
++      IF_DEF_PARAMS (ifp)->auth_keychain = NULL;
++    }
++  else
++    vty_out(vty,"Key chain with specified name not configured on interface%s", VTY_NEWLINE);
++
++  return CMD_SUCCESS;
++}
++
++
++DEFUN (eigrp_redistribute_source_metric,
++    eigrp_redistribute_source_metric_cmd,
++       "redistribute " QUAGGA_REDIST_STR_EIGRPD
++         " metric <1-4294967295> <0-4294967295> <0-255> <1-255> <1-65535>",
++       REDIST_STR
++       QUAGGA_REDIST_HELP_STR_EIGRPD
++       "Metric for redistributed routes\n"
++       "Bandwidth metric in Kbits per second\n"
++       "EIGRP delay metric, in 10 microsecond units\n"
++       "EIGRP reliability metric where 255 is 100% reliable2 ?\n"
++       "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n"
++       "EIGRP MTU of the path\n")
++{
++  struct eigrp *eigrp = vty->index;
++  struct eigrp_metrics metrics_from_command;
++  int source;
++
++  /* Get distribute source. */
++  source = proto_redistnum(AFI_IP, argv[0]);
++  if (source < 0 )
++    return CMD_WARNING;
++
++  /* Get metrics values */
++
++  return eigrp_redistribute_set (eigrp, source, metrics_from_command);
++}
++
++
++DEFUN (no_eigrp_redistribute_source_metric,
++    no_eigrp_redistribute_source_metric_cmd,
++       "no redistribute " QUAGGA_REDIST_STR_EIGRPD
++         " metric <1-4294967295> <0-4294967295> <0-255> <1-255> <1-65535>",
++         "Disable\n"
++       REDIST_STR
++       QUAGGA_REDIST_HELP_STR_EIGRPD
++       "Metric for redistributed routes\n"
++       "Bandwidth metric in Kbits per second\n"
++       "EIGRP delay metric, in 10 microsecond units\n"
++       "EIGRP reliability metric where 255 is 100% reliable2 ?\n"
++       "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n"
++       "EIGRP MTU of the path\n")
++{
++  struct eigrp *eigrp = vty->index;
++  struct eigrp_metrics metrics_from_command;
++  int source;
++
++  /* Get distribute source. */
++  source = proto_redistnum(AFI_IP, argv[0]);
++  if (source < 0 )
++    return CMD_WARNING;
++
++  /* Get metrics values */
++
++  return eigrp_redistribute_unset (eigrp, source);
++}
++
++DEFUN (eigrp_variance,
++    eigrp_variance_cmd,
++    "variance <1-128>",
++     "Control load balancing variance\n"
++     "Metric variance multiplier\n")
++{
++
++    struct eigrp *eigrp;
++    u_char variance;
++
++    eigrp = eigrp_lookup ();
++    if (eigrp == NULL)
++      {
++        vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++        return CMD_SUCCESS;
++      }
++    variance = atoi(argv[0]);
++    /* hello range is <1-65535> */
++    if ((variance < 1) || (variance > 128))
++      {
++        vty_out (vty, "Variance value is invalid%s", VTY_NEWLINE);
++        return CMD_WARNING;
++      }
++
++      eigrp->variance = variance;
++
++    /*TODO: */
++
++    return CMD_SUCCESS;
++}
++
++
++DEFUN (no_eigrp_variance,
++    no_eigrp_variance_cmd,
++    "no variance <1-128>",
++    "Disable\n"
++     "Control load balancing variance\n"
++     "Metric variance multiplier\n")
++{
++
++    struct eigrp *eigrp;
++    eigrp = eigrp_lookup ();
++    if (eigrp == NULL)
++      {
++        vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++        return CMD_SUCCESS;
++      }
++
++    eigrp->variance = EIGRP_VARIANCE_DEFAULT;
++
++    /*TODO: */
++
++    return CMD_SUCCESS;
++}
++
++DEFUN (eigrp_maximum_paths,
++    eigrp_maximum_paths_cmd,
++    "maximum-paths  <1-32>",
++    "Forward packets over multiple paths\n"
++    "Number of paths\n")
++{
++
++    struct eigrp *eigrp;
++    u_char max;
++
++    eigrp = eigrp_lookup ();
++    if (eigrp == NULL)
++      {
++        vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++        return CMD_SUCCESS;
++      }
++
++    max = atoi(argv[0]);
++    /* hello range is <1-65535> */
++    if ((max < 1) || (max > 32))
++      {
++        vty_out (vty, "Maximum-paths value is invalid%s", VTY_NEWLINE);
++        return CMD_WARNING;
++      }
++
++      eigrp->max_paths = max;
++
++    /*TODO: */
++
++    return CMD_SUCCESS;
++}
++
++
++DEFUN (no_eigrp_maximum_paths,
++    no_eigrp_maximum_paths_cmd,
++    "no maximum-paths <1-32>",
++    NO_STR
++    "Forward packets over multiple paths\n"
++    "Number of paths\n")
++{
++
++    struct eigrp *eigrp;
++
++    eigrp = eigrp_lookup ();
++    if (eigrp == NULL)
++      {
++        vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
++        return CMD_SUCCESS;
++      }
++
++    eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT;
++
++    /*TODO: */
++
++    return CMD_SUCCESS;
++}
++
++
++
++static struct cmd_node eigrp_node =
++{
++  EIGRP_NODE,
++  "%s(config-router)# ",
++  1
++};
++
++/* Save EIGRP configuration */
++static int
++eigrp_config_write (struct vty *vty)
++{
++  struct eigrp *eigrp;
++
++  int write = 0;
++
++  eigrp = eigrp_lookup ();
++  if (eigrp != NULL)
++    {
++      /* `router eigrp' print. */
++      vty_out (vty, "router eigrp %d%s", eigrp->AS, VTY_NEWLINE);
++
++      write++;
++
++      if (!eigrp->networks)
++        return write;
++
++      /* Router ID print. */
++      if (eigrp->router_id_static != 0)
++      {
++	struct in_addr router_id_static;
++	router_id_static.s_addr = htonl(eigrp->router_id_static);
++        vty_out (vty, " eigrp router-id %s%s",
++                 inet_ntoa (router_id_static), VTY_NEWLINE);
++      }
++
++      /* Network area print. */
++      config_write_network (vty, eigrp);
++
++      /* Interface config print */
++      config_write_interfaces (vty, eigrp);
++//
++//      /* static neighbor print. */
++//      config_write_eigrp_nbr_nbma (vty, eigrp);
++//
++//      /* Virtual-Link print. */
++//      config_write_virtual_link (vty, eigrp);
++//
++//      /* Default metric configuration.  */
++//      config_write_eigrp_default_metric (vty, eigrp);
++//
++//      /* Distribute-list and default-information print. */
++//      config_write_eigrp_distribute (vty, eigrp);
++//
++//      /* Distance configuration. */
++//      config_write_eigrp_distance (vty, eigrp)
++    }
++
++  return write;
++}
++
++void
++eigrp_vty_show_init (void)
++{
++  install_element (ENABLE_NODE, &show_ip_eigrp_interfaces_cmd);
++  install_element (VIEW_NODE, &show_ip_eigrp_interfaces_cmd);
++
++  install_element (ENABLE_NODE, &show_ip_eigrp_neighbors_cmd);
++  install_element (VIEW_NODE, &show_ip_eigrp_neighbors_cmd);
++
++  install_element (ENABLE_NODE, &show_ip_eigrp_topology_cmd);
++  install_element (VIEW_NODE, &show_ip_eigrp_topology_cmd);
++
++  install_element (VIEW_NODE, &show_ip_eigrp_neighbors_detail_cmd);
++  install_element (ENABLE_NODE, &show_ip_eigrp_neighbors_detail_cmd);
++
++  install_element (VIEW_NODE, &show_ip_eigrp_interfaces_detail_cmd);
++  install_element (ENABLE_NODE, &show_ip_eigrp_interfaces_detail_cmd);
++
++  install_element (ENABLE_NODE, &show_ip_eigrp_topology_all_links_cmd);
++  install_element (VIEW_NODE, &show_ip_eigrp_topology_all_links_cmd);
++
++  install_element (ENABLE_NODE, &show_ip_eigrp_topology_detail_cmd);
++  install_element (VIEW_NODE, &show_ip_eigrp_topology_detail_cmd);
++
++}
++
++/* eigrpd's interface node. */
++static struct cmd_node eigrp_interface_node =
++{
++  INTERFACE_NODE,
++  "%s(config-if)# ",
++  1
++};
++
++void
++eigrp_vty_if_init (void)
++{
++  install_node (&eigrp_interface_node, eigrp_write_interface);
++  install_default (INTERFACE_NODE);
++  install_element (CONFIG_NODE, &interface_cmd);
++  install_element (CONFIG_NODE, &no_interface_cmd);
++
++  /* Delay and bandwidth configuration commands*/
++  install_element (INTERFACE_NODE, &eigrp_if_delay_cmd);
++  install_element (INTERFACE_NODE, &eigrp_if_bandwidth_cmd);
++
++  /*Hello-interval and hold-time interval configuration commands*/
++  install_element (INTERFACE_NODE, &eigrp_if_ip_holdinterval_cmd);
++  install_element (INTERFACE_NODE, &no_eigrp_if_ip_holdinterval_cmd);
++  install_element (INTERFACE_NODE, &eigrp_if_ip_hellointerval_cmd);
++  install_element (INTERFACE_NODE, &no_eigrp_if_ip_hellointerval_cmd);
++
++  /* "description" commands. */
++  install_element (INTERFACE_NODE, &interface_desc_cmd);
++  install_element (INTERFACE_NODE, &no_interface_desc_cmd);
++
++  /* "Authentication configuration commands */
++  install_element (INTERFACE_NODE, &eigrp_authentication_mode_cmd);
++  install_element (INTERFACE_NODE, &no_eigrp_authentication_mode_cmd);
++  install_element (INTERFACE_NODE, &eigrp_authentication_keychain_cmd);
++  install_element (INTERFACE_NODE, &no_eigrp_authentication_keychain_cmd);
++
++  /*EIGRP Summarization commands*/
++  install_element (INTERFACE_NODE, &eigrp_ip_summary_address_cmd);
++  install_element (INTERFACE_NODE, &no_eigrp_ip_summary_address_cmd);
++
++
++}
++
++static void
++eigrp_vty_zebra_init (void)
++{
++  install_element (EIGRP_NODE, &eigrp_redistribute_source_metric_cmd);
++  install_element (EIGRP_NODE, &no_eigrp_redistribute_source_metric_cmd);
++
++}
++
++/* Install EIGRP related vty commands. */
++void
++eigrp_vty_init (void)
++{
++  install_node (&eigrp_node, eigrp_config_write);
++
++  install_default (EIGRP_NODE);
++
++  install_element (CONFIG_NODE, &router_eigrp_cmd);
++  install_element (CONFIG_NODE, &no_router_eigrp_cmd);
++  install_element (EIGRP_NODE, &eigrp_network_cmd);
++  install_element (EIGRP_NODE, &no_eigrp_network_cmd);
++  install_element (EIGRP_NODE, &eigrp_variance_cmd);
++  install_element (EIGRP_NODE, &no_eigrp_variance_cmd);
++  install_element (EIGRP_NODE, &eigrp_router_id_cmd);
++  install_element (EIGRP_NODE, &no_eigrp_router_id_cmd);
++  install_element (EIGRP_NODE, &eigrp_passive_interface_cmd);
++  install_element (EIGRP_NODE, &no_eigrp_passive_interface_cmd);
++  install_element (EIGRP_NODE, &eigrp_timers_active_cmd);
++  install_element (EIGRP_NODE, &no_eigrp_timers_active_cmd);
++  install_element (EIGRP_NODE, &eigrp_metric_weights_cmd);
++  install_element (EIGRP_NODE, &no_eigrp_metric_weights_cmd);
++  install_element (EIGRP_NODE, &eigrp_maximum_paths_cmd);
++  install_element (EIGRP_NODE, &no_eigrp_maximum_paths_cmd);
++  install_element (EIGRP_NODE, &eigrp_neighbor_cmd);
++  install_element (EIGRP_NODE, &no_eigrp_neighbor_cmd);
++
++
++
++  eigrp_vty_zebra_init ();
++}
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_vty.h eigrp/eigrpd/eigrp_vty.h
+--- a/eigrpd/eigrp_vty.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_vty.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,38 @@
++/*
++ * EIGRP VTY interface.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#ifndef _QUAGGA_EIGRP_VTY_H
++#define _QUAGGA_EIGRP_VTY_H
++
++
++/* Prototypes. */
++extern void eigrp_vty_init (void);
++extern void eigrp_vty_show_init (void);
++extern void eigrp_vty_if_init (void);
++
++#endif /* _Quagga_EIGRP_VTY_H_ */
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_zebra.c eigrp/eigrpd/eigrp_zebra.c
+--- a/eigrpd/eigrp_zebra.c	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_zebra.c	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,579 @@
++/*
++ * Zebra connect library for EIGRP.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#include <zebra.h>
++
++#include "thread.h"
++#include "command.h"
++#include "network.h"
++#include "prefix.h"
++#include "routemap.h"
++#include "table.h"
++#include "stream.h"
++#include "memory.h"
++#include "zclient.h"
++#include "filter.h"
++#include "plist.h"
++#include "log.h"
++
++#include "eigrpd/eigrp_structs.h"
++#include "eigrpd/eigrpd.h"
++#include "eigrpd/eigrp_interface.h"
++#include "eigrpd/eigrp_neighbor.h"
++#include "eigrpd/eigrp_packet.h"
++#include "eigrpd/eigrp_zebra.h"
++#include "eigrpd/eigrp_vty.h"
++#include "eigrpd/eigrp_dump.h"
++#include "eigrpd/eigrp_network.h"
++#include "eigrpd/eigrp_topology.h"
++#include "eigrpd/eigrp_fsm.h"
++
++static int eigrp_interface_add (int , struct zclient *, zebra_size_t);
++static int eigrp_interface_delete (int , struct zclient *,
++                                   zebra_size_t );
++static int eigrp_interface_address_add (int, struct zclient *,
++                                        zebra_size_t);
++static int eigrp_interface_address_delete (int, struct zclient *,
++                                           zebra_size_t);
++static int eigrp_interface_state_up (int, struct zclient *,
++                                     zebra_size_t);
++static int eigrp_interface_state_down (int, struct zclient *,
++                                       zebra_size_t);
++static struct interface * zebra_interface_if_lookup (struct stream *);
++
++static int eigrp_zebra_read_ipv4 (int , struct zclient *,
++                      zebra_size_t );
++
++/* Zebra structure to hold current status. */
++struct zclient *zclient = NULL;
++
++/* For registering threads. */
++extern struct thread_master *master;
++struct in_addr router_id_zebra;
++
++/* Router-id update message from zebra. */
++static int
++eigrp_router_id_update_zebra (int command, struct zclient *zclient,
++                             zebra_size_t length)
++{
++  struct eigrp *eigrp;
++  struct prefix router_id;
++  zebra_router_id_update_read (zclient->ibuf,&router_id);
++
++  router_id_zebra = router_id.u.prefix4;
++
++  eigrp = eigrp_lookup ();
++
++  if (eigrp != NULL)
++    eigrp_router_id_update (eigrp);
++
++  return 0;
++}
++
++
++void
++eigrp_zebra_init (void)
++{
++  zclient = zclient_new ();
++
++  zclient_init (zclient, ZEBRA_ROUTE_EIGRP);
++  zclient->router_id_update = eigrp_router_id_update_zebra;
++  zclient->interface_add = eigrp_interface_add;
++  zclient->interface_delete = eigrp_interface_delete;
++  zclient->interface_up = eigrp_interface_state_up;
++  zclient->interface_down = eigrp_interface_state_down;
++  zclient->interface_address_add = eigrp_interface_address_add;
++  zclient->interface_address_delete = eigrp_interface_address_delete;
++  zclient->ipv4_route_add = eigrp_zebra_read_ipv4;
++  zclient->ipv4_route_delete = eigrp_zebra_read_ipv4;
++}
++
++
++/* Zebra route add and delete treatment. */
++static int
++eigrp_zebra_read_ipv4 (int command, struct zclient *zclient,
++                      zebra_size_t length)
++{
++  struct stream *s;
++  struct zapi_ipv4 api;
++  unsigned long ifindex;
++  struct in_addr nexthop;
++  struct prefix_ipv4 p;
++  struct TLV_IPv4_External_type *external_tlv;
++  struct eigrp *eigrp;
++
++  s = zclient->ibuf;
++  ifindex = 0;
++  nexthop.s_addr = 0;
++
++  /* Type, flags, message. */
++  api.type = stream_getc (s);
++  api.flags = stream_getc (s);
++  api.message = stream_getc (s);
++
++  /* IPv4 prefix. */
++  memset (&p, 0, sizeof (struct prefix_ipv4));
++  p.family = AF_INET;
++  p.prefixlen = stream_getc (s);
++  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
++
++  if (IPV4_NET127(ntohl(p.prefix.s_addr)))
++    return 0;
++
++  /* Nexthop, ifindex, distance, metric. */
++  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
++    {
++      api.nexthop_num = stream_getc (s);
++      nexthop.s_addr = stream_get_ipv4 (s);
++    }
++  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
++    {
++      api.ifindex_num = stream_getc (s);
++      /* XXX assert(api.ifindex_num == 1); */
++      ifindex = stream_getl (s);
++    }
++  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
++    api.distance = stream_getc (s);
++  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
++    api.metric = stream_getl (s);
++
++  eigrp = eigrp_lookup ();
++  if (eigrp == NULL)
++    return 0;
++
++  if (command == ZEBRA_IPV4_ROUTE_ADD)
++    {
++
++    }
++  else                          /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */
++    {
++
++    }
++
++  return 0;
++}
++
++/* Inteface addition message from zebra. */
++static int
++eigrp_interface_add (int command, struct zclient *zclient, zebra_size_t length)
++{
++  struct interface *ifp;
++
++  ifp = zebra_interface_add_read (zclient->ibuf);
++
++  assert (ifp->info);
++
++  if (!EIGRP_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type))
++    {
++      SET_IF_PARAM (IF_DEF_PARAMS (ifp), type);
++      IF_DEF_PARAMS (ifp)->type = eigrp_default_iftype (ifp);
++    }
++
++  eigrp_if_update (ifp);
++
++  return 0;
++}
++
++static int
++eigrp_interface_delete (int command, struct zclient *zclient,
++                       zebra_size_t length)
++{
++  struct interface *ifp;
++  struct stream *s;
++  struct route_node *rn;
++
++  s = zclient->ibuf;
++  /* zebra_interface_state_read () updates interface structure in iflist */
++  ifp = zebra_interface_state_read (s);
++
++  if (ifp == NULL)
++    return 0;
++
++  if (if_is_up (ifp))
++    zlog_warn ("Zebra: got delete of %s, but interface is still up",
++               ifp->name);
++
++  if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
++    zlog_debug("Zebra: interface delete %s index %d flags %llx metric %d mtu %d",
++       ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
++
++  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
++    if (rn->info)
++      eigrp_if_free ((struct eigrp_interface *) rn->info, INTERFACE_DOWN_BY_ZEBRA);
++
++  ifp->ifindex = IFINDEX_INTERNAL;
++  return 0;
++}
++
++static int
++eigrp_interface_address_add (int command, struct zclient *zclient,
++                            zebra_size_t length)
++{
++  struct connected *c;
++
++  c = zebra_interface_address_read (command, zclient->ibuf);
++
++  if (c == NULL)
++    return 0;
++
++  if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
++    {
++      char buf[128];
++      prefix2str (c->address, buf, sizeof (buf));
++      zlog_debug ("Zebra: interface %s address add %s", c->ifp->name, buf);
++    }
++
++  eigrp_if_update (c->ifp);
++
++  return 0;
++}
++
++static int
++eigrp_interface_address_delete (int command, struct zclient *zclient,
++                               zebra_size_t length)
++{
++  struct connected *c;
++  struct interface *ifp;
++  struct eigrp_interface *ei;
++  struct route_node *rn;
++  struct prefix p;
++
++  c = zebra_interface_address_read (command, zclient->ibuf);
++
++  if (c == NULL)
++    return 0;
++
++  if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
++    {
++      char buf[128];
++      prefix2str (c->address, buf, sizeof (buf));
++      zlog_debug ("Zebra: interface %s address delete %s", c->ifp->name, buf);
++    }
++
++  ifp = c->ifp;
++  p = *c->address;
++  p.prefixlen = IPV4_MAX_PREFIXLEN;
++
++  rn = route_node_lookup (IF_OIFS (ifp), &p);
++  if (!rn)
++    {
++      connected_free (c);
++      return 0;
++    }
++
++  assert (rn->info);
++  ei = rn->info;
++
++  /* Call interface hook functions to clean up */
++  eigrp_if_free (ei, INTERFACE_DOWN_BY_ZEBRA);
++
++  connected_free (c);
++
++  return 0;
++}
++
++static int
++eigrp_interface_state_up (int command, struct zclient *zclient,
++                         zebra_size_t length)
++{
++  struct interface *ifp;
++  struct eigrp_interface *ei;
++  struct route_node *rn;
++
++  ifp = zebra_interface_if_lookup (zclient->ibuf);
++
++  if (ifp == NULL)
++    return 0;
++
++  /* Interface is already up. */
++  if (if_is_operative (ifp))
++    {
++      /* Temporarily keep ifp values. */
++      struct interface if_tmp;
++      memcpy (&if_tmp, ifp, sizeof (struct interface));
++
++      zebra_interface_if_set_value (zclient->ibuf, ifp);
++
++      if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
++        zlog_debug ("Zebra: Interface[%s] state update.", ifp->name);
++
++      if (if_tmp.bandwidth != ifp->bandwidth)
++        {
++          if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
++            zlog_debug ("Zebra: Interface[%s] bandwidth change %d -> %d.",
++                       ifp->name, if_tmp.bandwidth, ifp->bandwidth);
++
++//          eigrp_if_recalculate_output_cost (ifp);
++        }
++
++      if (if_tmp.mtu != ifp->mtu)
++        {
++          if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
++            zlog_debug ("Zebra: Interface[%s] MTU change %u -> %u.",
++			ifp->name, if_tmp.mtu, ifp->mtu);
++
++          /* Must reset the interface (simulate down/up) when MTU changes. */
++          eigrp_if_reset (ifp);
++        }
++      return 0;
++    }
++
++  zebra_interface_if_set_value (zclient->ibuf, ifp);
++
++  if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
++    zlog_debug ("Zebra: Interface[%s] state change to up.", ifp->name);
++
++  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
++    {
++      if ((ei = rn->info) == NULL)
++        continue;
++
++      eigrp_if_up (ei);
++    }
++
++  return 0;
++}
++
++static int
++eigrp_interface_state_down (int command, struct zclient *zclient,
++                           zebra_size_t length)
++{
++  struct interface *ifp;
++  struct eigrp_interface *ei;
++  struct route_node *node;
++
++  ifp = zebra_interface_state_read (zclient->ibuf);
++
++  if (ifp == NULL)
++    return 0;
++
++  if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
++    zlog_debug ("Zebra: Interface[%s] state change to down.", ifp->name);
++
++  for (node = route_top (IF_OIFS (ifp)); node; node = route_next (node))
++    {
++      if ((ei = node->info) == NULL)
++        continue;
++      eigrp_if_down (ei);
++    }
++
++  return 0;
++}
++
++static struct interface *
++zebra_interface_if_lookup (struct stream *s)
++{
++  char ifname_tmp[INTERFACE_NAMSIZ];
++
++  /* Read interface name. */
++  stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
++
++  /* And look it up. */
++  return if_lookup_by_name_len (ifname_tmp,
++                               strnlen (ifname_tmp, INTERFACE_NAMSIZ));
++}
++
++void
++eigrp_zebra_route_add (struct prefix_ipv4 *p, struct eigrp_neighbor_entry *te)
++{
++  u_char message;
++  u_char flags;
++  int psize;
++  struct stream *s;
++
++  if (zclient->redist[ZEBRA_ROUTE_EIGRP])
++    {
++      message = 0;
++      flags = 0;
++
++      /* EIGRP pass nexthop and metric */
++      SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP);
++      SET_FLAG (message, ZAPI_MESSAGE_METRIC);
++
++      /* Distance value. */
++//      distance = eigrp_distance_apply (p, er);
++//      if (distance)
++//        SET_FLAG (message, ZAPI_MESSAGE_DISTANCE);
++
++      /* Make packet. */
++      s = zclient->obuf;
++      stream_reset (s);
++
++      /* Put command, type, flags, message. */
++      zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD);
++      stream_putc (s, ZEBRA_ROUTE_EIGRP);
++      stream_putc (s, flags);
++      stream_putc (s, message);
++      stream_putw (s, SAFI_UNICAST);
++
++      /* Put prefix information. */
++      psize = PSIZE (p->prefixlen);
++      stream_putc (s, p->prefixlen);
++      stream_write (s, (u_char *) & p->prefix, psize);
++
++      /* Nexthop count. */
++      stream_putc (s, 1);
++
++      /* Nexthop, ifindex, distance and metric information. */
++      stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX);
++      stream_put_in_addr (s, &te->adv_router->src);
++      stream_putl (s, te->ei->ifp->ifindex);
++
++      if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
++        {
++          char buf[2][INET_ADDRSTRLEN];
++          zlog_debug ("Zebra: Route add %s/%d nexthop %s",
++		      inet_ntop(AF_INET, &p->prefix, buf[0], sizeof (buf[0])),
++		      p->prefixlen,
++		      inet_ntop(AF_INET, 0 /*&p->nexthop*/, buf[1], sizeof (buf[1])));
++        }
++
++      stream_putl (s, te->distance);
++      stream_putw_at (s, 0, stream_get_endp (s));
++
++      zclient_send_message (zclient);
++    }
++}
++
++void
++eigrp_zebra_route_delete (struct prefix_ipv4 *p, struct eigrp_neighbor_entry *te)
++{
++  u_char message;
++  u_char flags;
++  int psize;
++  struct stream *s;
++
++  if (zclient->redist[ZEBRA_ROUTE_EIGRP])
++    {
++      message = 0;
++      flags = 0;
++      /* Make packet. */
++      s = zclient->obuf;
++      stream_reset (s);
++
++      /* Put command, type, flags, message. */
++      zclient_create_header (s, ZEBRA_IPV4_ROUTE_DELETE);
++      stream_putc (s, ZEBRA_ROUTE_EIGRP);
++      stream_putc (s, flags);
++      stream_putc (s, message);
++      stream_putw (s, SAFI_UNICAST);
++
++      /* Put prefix information. */
++      psize = PSIZE (p->prefixlen);
++      stream_putc (s, p->prefixlen);
++      stream_write (s, (u_char *) & p->prefix, psize);
++
++      /* Nexthop count. */
++      stream_putc (s, 1);
++
++      /* Nexthop, ifindex, distance and metric information. */
++      stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX);
++      stream_put_in_addr (s, &te->adv_router->src);
++      stream_putl (s, te->ei->ifp->ifindex);
++
++      if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
++        {
++          char buf[2][INET_ADDRSTRLEN];
++          zlog_debug ("Zebra: Route del %s/%d nexthop %s",
++		      inet_ntop (AF_INET, &p->prefix,  buf[0], sizeof (buf[0])),
++		      p->prefixlen,
++		      inet_ntop (AF_INET, 0 /*&p->nexthop*/, buf[1], sizeof (buf[1])));
++        }
++
++
++      if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
++        {
++          stream_putl (s, te->distance);
++        }
++
++      stream_putw_at (s, 0, stream_get_endp (s));
++
++      zclient_send_message (zclient);
++    }
++}
++
++int
++eigrp_is_type_redistributed (int type)
++{
++  return (DEFAULT_ROUTE_TYPE (type)) ?
++    zclient->default_information : zclient->redist[type];
++}
++
++int
++eigrp_redistribute_set (struct eigrp *eigrp, int type, struct eigrp_metrics metric)
++{
++
++  if (eigrp_is_type_redistributed (type))
++    {
++      if (eigrp_metrics_is_same(&metric, &eigrp->dmetric[type]))
++        {
++          eigrp->dmetric[type] = metric;
++        }
++
++      eigrp_external_routes_refresh (eigrp, type);
++
++//      if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE))
++//        zlog_debug ("Redistribute[%s]: Refresh  Type[%d], Metric[%d]",
++//                   eigrp_redist_string(type),
++//                   metric_type (eigrp, type), metric_value (eigrp, type));
++      return CMD_SUCCESS;
++    }
++
++  eigrp->dmetric[type] = metric;
++
++  zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type);
++
++//  if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
++//    zlog_debug ("Redistribute[%s]: Start  Type[%d], Metric[%d]",
++//               ospf_redist_string(type),
++//               metric_type (ospf, type), metric_value (ospf, type));
++
++  ++eigrp->redistribute;
++
++  return CMD_SUCCESS;
++}
++
++int
++eigrp_redistribute_unset (struct eigrp *eigrp, int type)
++{
++
++  if (eigrp_is_type_redistributed (type))
++    {
++      memset(&eigrp->dmetric[type], 0, sizeof(struct eigrp_metrics));
++      zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type);
++      --eigrp->redistribute;
++    }
++
++//  if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
++//    zlog_debug ("Redistribute[%s]: Start  Type[%d], Metric[%d]",
++//               ospf_redist_string(type),
++//               metric_type (ospf, type), metric_value (ospf, type));
++
++  return CMD_SUCCESS;
++}
++
+diff -Nur quagga-0.99.22.4/eigrpd/eigrp_zebra.h eigrp/eigrpd/eigrp_zebra.h
+--- a/eigrpd/eigrp_zebra.h	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/eigrp_zebra.h	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,42 @@
++/*
++ * Zebra connect library for EIGRP.
++ * Copyright (C) 2013-2014
++ * Authors:
++ *   Donnie Savage
++ *   Jan Janovic
++ *   Matej Perina
++ *   Peter Orsag
++ *   Peter Paluch
++ *
++ * 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.
++ */
++
++#ifndef _ZEBRA_EIGRP_ZEBRA_H_
++#define _ZEBRA_EIGRP_ZEBRA_H_
++
++#include "vty.h"
++
++extern void eigrp_zebra_init (void);
++
++extern void eigrp_zebra_route_add (struct prefix_ipv4 *, struct eigrp_neighbor_entry *);
++extern void eigrp_zebra_route_delete (struct prefix_ipv4 *, struct eigrp_neighbor_entry *);
++extern int eigrp_redistribute_set (struct eigrp *, int, struct eigrp_metrics);
++extern int eigrp_redistribute_unset (struct eigrp *, int);
++extern int eigrp_is_type_redistributed (int);
++
++#endif /* _ZEBRA_EIGRP_ZEBRA_H_ */
+diff -Nur quagga-0.99.22.4/eigrpd/Makefile.am eigrp/eigrpd/Makefile.am
+--- a/eigrpd/Makefile.am	1970-01-01 02:00:00.000000000 +0200
++++ b/eigrpd/Makefile.am	2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,34 @@
++## Process this file with automake to produce Makefile.in.
++
++AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
++DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\"
++INSTALL_SDATA=@INSTALL@ -m 600
++
++lib_LTLIBRARIES = libeigrp.la
++libeigrp_la_LDFLAGS = -version-info 0:0:0
++
++sbin_PROGRAMS = eigrpd
++
++libeigrp_la_SOURCES = \
++	eigrpd.c eigrp_zebra.c eigrp_interface.c eigrp_neighbor.c eigrp_dump.c eigrp_vty.c \
++	eigrp_network.c eigrp_packet.c eigrp_topology.c eigrp_fsm.c eigrp_hello.c eigrp_update.c \
++	eigrp_query.c eigrp_reply.c eigrp_snmp.c eigrp_siaquery.c eigrp_siareply.c eigrp_filter.c
++
++
++eigrpdheaderdir = $(pkgincludedir)/eigrpd
++
++eigrpdheader_HEADERS = \
++	eigrp_topology.h eigrp_dump.h eigrpd.h
++	
++noinst_HEADERS = \
++	eigrp_const.h eigrp_structs.h eigrp_macros.h eigrp_interface.h eigrp_neighbor.h eigrp_network.h eigrp_packet.h \
++	eigrp_zebra.h eigrp_vty.h eigrp_snmp.h eigrp_filter.h
++	
++eigrpd_SOURCES = eigrp_main.c
++
++eigrpd_LDADD = libeigrp.la ../lib/libzebra.la @LIBCAP@
++
++EXTRA_DIST = EIGRP-MIB.txt
++
++examplesdir = $(exampledir)
++dist_examples_DATA = eigrpd.conf.sample
+diff -Nur quagga-0.99.22.4/pkgsrc/eigrpd.sh.in eigrp/pkgsrc/eigrpd.sh.in
+--- a/pkgsrc/eigrpd.sh.in        1970-01-01 02:00:00.000000000 +0200
++++ b/pkgsrc/eigrpd.sh.in   2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,44 @@
++#!/bin/sh
++#
++# eigrpd is part of the quagga routing beast
++#
++# PROVIDE: eigrpd
++# REQUIRE: zebra
++##
++
++PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin
++export PATH
++
++if [ -f /etc/rc.subr ]
++then
++	. /etc/rc.subr
++fi
++
++name="eigrpd"
++rcvar=$name
++required_files="@sysconfdir@/${name}.conf"
++command="@prefix@/sbin/${name}"
++command_args="-d"
++
++start_precmd="zebra_precmd"
++socket_dir=@localstatedir@
++pidfile="${socket_dir}/${name}.pid"
++
++zebra_precmd()
++{
++    rc_flags="$(
++	set -- $rc_flags
++	while [ $# -ne 0 ]; do
++	    if [ X"$1" = X-P -o X"$1" = X-A ]; then
++		break
++	    fi
++	    shift
++	done
++	if [ $# -eq 0 ]; then
++	    echo "-P 0"
++	fi
++	) $rc_flags"
++}
++
++load_rc_config $name
++run_rc_command "$1"
+diff -Nur quagga-0.99.22.4/lib/sha256.h eigrp/lib/sha256.h
+--- a/lib/sha256.h       1970-01-01 02:00:00.000000000 +0200
++++ b/lib/sha256.h  2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,58 @@
++/*-
++ * Copyright 2005,2007,2009 Colin Percival
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ * $FreeBSD: src/lib/libmd/sha256.h,v 1.2 2006/01/17 15:35:56 phk Exp $
++ */
++
++#ifndef _SHA256_H_
++#define _SHA256_H_
++
++typedef struct SHA256Context {
++        uint32_t state[8];
++        uint32_t count[2];
++        unsigned char buf[64];
++} SHA256_CTX;
++
++typedef struct HMAC_SHA256Context {
++        SHA256_CTX ictx;
++        SHA256_CTX octx;
++} HMAC_SHA256_CTX;
++
++void    SHA256_Init(SHA256_CTX *);
++void    SHA256_Update(SHA256_CTX *, const void *, size_t);
++void    SHA256_Final(unsigned char [32], SHA256_CTX *);
++void    HMAC__SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t);
++void    HMAC__SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t);
++void    HMAC__SHA256_Final(unsigned char [32], HMAC_SHA256_CTX *);
++
++/**
++ * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
++ * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
++ * write the output to buf.  The value dkLen must be at most 32 * (2^32 - 1).
++ */
++void    PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t,
++    uint64_t, uint8_t *, size_t);
++
++#endif /* !_SHA256_H_ */
+diff -Nur quagga-0.99.22.4/lib/sha256.c eigrp/lib/sha256.c
+--- a/lib/sha256.c       1970-01-01 02:00:00.000000000 +0200
++++ b/lib/sha256.c  2015-11-03 23:52:48.000000000 +0200
+@@ -0,0 +1,425 @@
++/*-
++ * Copyright 2005,2007,2009 Colin Percival
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++#include <zebra.h>
++#include "sha256.h"
++
++static inline uint32_t
++be32dec(const void *pp)
++{
++        const uint8_t *p = (uint8_t const *)pp;
++
++        return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +
++            ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
++}
++
++static inline void
++be32enc(void *pp, uint32_t x)
++{
++        uint8_t * p = (uint8_t *)pp;
++
++        p[3] = x & 0xff;
++        p[2] = (x >> 8) & 0xff;
++        p[1] = (x >> 16) & 0xff;
++        p[0] = (x >> 24) & 0xff;
++}
++
++/*
++ * Encode a length len/4 vector of (uint32_t) into a length len vector of
++ * (unsigned char) in big-endian form.  Assumes len is a multiple of 4.
++ */
++static void
++be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
++{
++        size_t i;
++
++        for (i = 0; i < len / 4; i++)
++                be32enc(dst + i * 4, src[i]);
++}
++
++/*
++ * Decode a big-endian length len vector of (unsigned char) into a length
++ * len/4 vector of (uint32_t).  Assumes len is a multiple of 4.
++ */
++static void
++be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
++{
++        size_t i;
++
++        for (i = 0; i < len / 4; i++)
++                dst[i] = be32dec(src + i * 4);
++}
++
++/* Elementary functions used by SHA256 */
++#define Ch(x, y, z)     ((x & (y ^ z)) ^ z)
++#define Maj(x, y, z)    ((x & (y | z)) | (y & z))
++#define SHR(x, n)       (x >> n)
++#define ROTR(x, n)      ((x >> n) | (x << (32 - n)))
++#define S0(x)           (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
++#define S1(x)           (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
++#define s0(x)           (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
++#define s1(x)           (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
++
++/* SHA256 round function */
++#define RND(a, b, c, d, e, f, g, h, k)                  \
++        t0 = h + S1(e) + Ch(e, f, g) + k;               \
++        t1 = S0(a) + Maj(a, b, c);                      \
++        d += t0;                                        \
++        h  = t0 + t1;
++
++/* Adjusted round function for rotating state */
++#define RNDr(S, W, i, k)                        \
++        RND(S[(64 - i) % 8], S[(65 - i) % 8],   \
++            S[(66 - i) % 8], S[(67 - i) % 8],   \
++            S[(68 - i) % 8], S[(69 - i) % 8],   \
++            S[(70 - i) % 8], S[(71 - i) % 8],   \
++            W[i] + k)
++
++/*
++ * SHA256 block compression function.  The 256-bit state is transformed via
++ * the 512-bit input block to produce a new state.
++ */
++static void
++SHA256_Transform(uint32_t * state, const unsigned char block[64])
++{
++        uint32_t W[64];
++        uint32_t S[8];
++        uint32_t t0, t1;
++        int i;
++
++        /* 1. Prepare message schedule W. */
++        be32dec_vect(W, block, 64);
++        for (i = 16; i < 64; i++)
++                W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
++
++        /* 2. Initialize working variables. */
++        memcpy(S, state, 32);
++
++        /* 3. Mix. */
++        RNDr(S, W, 0, 0x428a2f98);
++        RNDr(S, W, 1, 0x71374491);
++        RNDr(S, W, 2, 0xb5c0fbcf);
++        RNDr(S, W, 3, 0xe9b5dba5);
++        RNDr(S, W, 4, 0x3956c25b);
++        RNDr(S, W, 5, 0x59f111f1);
++        RNDr(S, W, 6, 0x923f82a4);
++        RNDr(S, W, 7, 0xab1c5ed5);
++        RNDr(S, W, 8, 0xd807aa98);
++        RNDr(S, W, 9, 0x12835b01);
++        RNDr(S, W, 10, 0x243185be);
++        RNDr(S, W, 11, 0x550c7dc3);
++        RNDr(S, W, 12, 0x72be5d74);
++        RNDr(S, W, 13, 0x80deb1fe);
++        RNDr(S, W, 14, 0x9bdc06a7);
++        RNDr(S, W, 15, 0xc19bf174);
++        RNDr(S, W, 16, 0xe49b69c1);
++        RNDr(S, W, 17, 0xefbe4786);
++        RNDr(S, W, 18, 0x0fc19dc6);
++        RNDr(S, W, 19, 0x240ca1cc);
++        RNDr(S, W, 20, 0x2de92c6f);
++        RNDr(S, W, 21, 0x4a7484aa);
++        RNDr(S, W, 22, 0x5cb0a9dc);
++        RNDr(S, W, 23, 0x76f988da);
++        RNDr(S, W, 24, 0x983e5152);
++        RNDr(S, W, 25, 0xa831c66d);
++        RNDr(S, W, 26, 0xb00327c8);
++        RNDr(S, W, 27, 0xbf597fc7);
++        RNDr(S, W, 28, 0xc6e00bf3);
++        RNDr(S, W, 29, 0xd5a79147);
++        RNDr(S, W, 30, 0x06ca6351);
++        RNDr(S, W, 31, 0x14292967);
++        RNDr(S, W, 32, 0x27b70a85);
++        RNDr(S, W, 33, 0x2e1b2138);
++        RNDr(S, W, 34, 0x4d2c6dfc);
++        RNDr(S, W, 35, 0x53380d13);
++        RNDr(S, W, 36, 0x650a7354);
++        RNDr(S, W, 37, 0x766a0abb);
++        RNDr(S, W, 38, 0x81c2c92e);
++        RNDr(S, W, 39, 0x92722c85);
++        RNDr(S, W, 40, 0xa2bfe8a1);
++        RNDr(S, W, 41, 0xa81a664b);
++        RNDr(S, W, 42, 0xc24b8b70);
++        RNDr(S, W, 43, 0xc76c51a3);
++        RNDr(S, W, 44, 0xd192e819);
++        RNDr(S, W, 45, 0xd6990624);
++        RNDr(S, W, 46, 0xf40e3585);
++        RNDr(S, W, 47, 0x106aa070);
++        RNDr(S, W, 48, 0x19a4c116);
++        RNDr(S, W, 49, 0x1e376c08);
++        RNDr(S, W, 50, 0x2748774c);
++        RNDr(S, W, 51, 0x34b0bcb5);
++        RNDr(S, W, 52, 0x391c0cb3);
++        RNDr(S, W, 53, 0x4ed8aa4a);
++        RNDr(S, W, 54, 0x5b9cca4f);
++        RNDr(S, W, 55, 0x682e6ff3);
++        RNDr(S, W, 56, 0x748f82ee);
++        RNDr(S, W, 57, 0x78a5636f);
++        RNDr(S, W, 58, 0x84c87814);
++        RNDr(S, W, 59, 0x8cc70208);
++        RNDr(S, W, 60, 0x90befffa);
++        RNDr(S, W, 61, 0xa4506ceb);
++        RNDr(S, W, 62, 0xbef9a3f7);
++        RNDr(S, W, 63, 0xc67178f2);
++
++        /* 4. Mix local working variables into global state */
++        for (i = 0; i < 8; i++)
++                state[i] += S[i];
++
++        /* Clean the stack. */
++        memset(W, 0, 256);
++        memset(S, 0, 32);
++        t0 = t1 = 0;
++}
++
++static unsigned char PAD[64] = {
++        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
++};
++
++/* Add padding and terminating bit-count. */
++static void
++SHA256_Pad(SHA256_CTX * ctx)
++{
++        unsigned char len[8];
++        uint32_t r, plen;
++
++        /*
++         * Convert length to a vector of bytes -- we do this now rather
++         * than later because the length will change after we pad.
++         */
++        be32enc_vect(len, ctx->count, 8);
++
++        /* Add 1--64 bytes so that the resulting length is 56 mod 64 */
++        r = (ctx->count[1] >> 3) & 0x3f;
++        plen = (r < 56) ? (56 - r) : (120 - r);
++        SHA256_Update(ctx, PAD, (size_t)plen);
++
++        /* Add the terminating bit-count */
++        SHA256_Update(ctx, len, 8);
++}
++
++/* SHA-256 initialization.  Begins a SHA-256 operation. */
++void
++SHA256_Init(SHA256_CTX * ctx)
++{
++
++        /* Zero bits processed so far */
++        ctx->count[0] = ctx->count[1] = 0;
++
++        /* Magic initialization constants */
++        ctx->state[0] = 0x6A09E667;
++        ctx->state[1] = 0xBB67AE85;
++        ctx->state[2] = 0x3C6EF372;
++        ctx->state[3] = 0xA54FF53A;
++        ctx->state[4] = 0x510E527F;
++        ctx->state[5] = 0x9B05688C;
++        ctx->state[6] = 0x1F83D9AB;
++        ctx->state[7] = 0x5BE0CD19;
++}
++
++/* Add bytes into the hash */
++void
++SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
++{
++        uint32_t bitlen[2];
++        uint32_t r;
++        const unsigned char *src = in;
++
++        /* Number of bytes left in the buffer from previous updates */
++        r = (ctx->count[1] >> 3) & 0x3f;
++
++        /* Convert the length into a number of bits */
++        bitlen[1] = ((uint32_t)len) << 3;
++        bitlen[0] = (uint32_t)(len >> 29);
++
++        /* Update number of bits */
++        if ((ctx->count[1] += bitlen[1]) < bitlen[1])
++                ctx->count[0]++;
++        ctx->count[0] += bitlen[0];
++
++        /* Handle the case where we don't need to perform any transforms */
++        if (len < 64 - r) {
++                memcpy(&ctx->buf[r], src, len);
++                return;
++        }
++
++        /* Finish the current block */
++        memcpy(&ctx->buf[r], src, 64 - r);
++        SHA256_Transform(ctx->state, ctx->buf);
++        src += 64 - r;
++        len -= 64 - r;
++
++        /* Perform complete blocks */
++        while (len >= 64) {
++                SHA256_Transform(ctx->state, src);
++                src += 64;
++                len -= 64;
++        }
++
++        /* Copy left over data into buffer */
++        memcpy(ctx->buf, src, len);
++}
++
++/*
++ * SHA-256 finalization.  Pads the input data, exports the hash value,
++ * and clears the context state.
++ */
++void
++SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
++{
++
++        /* Add padding */
++        SHA256_Pad(ctx);
++
++        /* Write the hash */
++        be32enc_vect(digest, ctx->state, 32);
++
++        /* Clear the context state */
++        memset((void *)ctx, 0, sizeof(*ctx));
++}
++
++/* Initialize an HMAC-SHA256 operation with the given key. */
++void
++HMAC__SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
++{
++        unsigned char pad[64];
++        unsigned char khash[32];
++        const unsigned char * K = _K;
++        size_t i;
++
++        /* If Klen > 64, the key is really SHA256(K). */
++        if (Klen > 64) {
++                SHA256_Init(&ctx->ictx);
++                SHA256_Update(&ctx->ictx, K, Klen);
++                SHA256_Final(khash, &ctx->ictx);
++                K = khash;
++                Klen = 32;
++        }
++
++        /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
++        SHA256_Init(&ctx->ictx);
++        memset(pad, 0x36, 64);
++        for (i = 0; i < Klen; i++)
++                pad[i] ^= K[i];
++        SHA256_Update(&ctx->ictx, pad, 64);
++
++        /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
++        SHA256_Init(&ctx->octx);
++        memset(pad, 0x5c, 64);
++        for (i = 0; i < Klen; i++)
++                pad[i] ^= K[i];
++        SHA256_Update(&ctx->octx, pad, 64);
++
++        /* Clean the stack. */
++        memset(khash, 0, 32);
++}
++
++/* Add bytes to the HMAC-SHA256 operation. */
++void
++HMAC__SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len)
++{
++
++        /* Feed data to the inner SHA256 operation. */
++        SHA256_Update(&ctx->ictx, in, len);
++}
++
++/* Finish an HMAC-SHA256 operation. */
++void
++HMAC__SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx)
++{
++        unsigned char ihash[32];
++
++        /* Finish the inner SHA256 operation. */
++        SHA256_Final(ihash, &ctx->ictx);
++
++        /* Feed the inner hash to the outer SHA256 operation. */
++        SHA256_Update(&ctx->octx, ihash, 32);
++
++        /* Finish the outer SHA256 operation. */
++        SHA256_Final(digest, &ctx->octx);
++
++        /* Clean the stack. */
++        memset(ihash, 0, 32);
++}
++
++/**
++ * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
++ * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
++ * write the output to buf.  The value dkLen must be at most 32 * (2^32 - 1).
++ */
++void
++PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
++    size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
++{
++        HMAC_SHA256_CTX PShctx, hctx;
++        size_t i;
++        uint8_t ivec[4];
++        uint8_t U[32];
++        uint8_t T[32];
++        uint64_t j;
++        int k;
++        size_t clen;
++
++        /* Compute HMAC state after processing P and S. */
++        HMAC__SHA256_Init(&PShctx, passwd, passwdlen);
++        HMAC__SHA256_Update(&PShctx, salt, saltlen);
++
++        /* Iterate through the blocks. */
++        for (i = 0; i * 32 < dkLen; i++) {
++                /* Generate INT(i + 1). */
++                be32enc(ivec, (uint32_t)(i + 1));
++
++                /* Compute U_1 = PRF(P, S || INT(i)). */
++                memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
++                HMAC__SHA256_Update(&hctx, ivec, 4);
++                HMAC__SHA256_Final(U, &hctx);
++
++                /* T_i = U_1 ... */
++                memcpy(T, U, 32);
++
++                for (j = 2; j <= c; j++) {
++                        /* Compute U_j. */
++                        HMAC__SHA256_Init(&hctx, passwd, passwdlen);
++                        HMAC__SHA256_Update(&hctx, U, 32);
++                        HMAC__SHA256_Final(U, &hctx);
++
++                        /* ... xor U_j ... */
++                        for (k = 0; k < 32; k++)
++                                T[k] ^= U[k];
++                }
++
++                /* Copy as many bytes as necessary into buf. */
++                clen = dkLen - i * 32;
++                if (clen > 32)
++                        clen = 32;
++                memcpy(&buf[i * 32], T, clen);
++        }
++
++        /* Clean PShctx, since we never called _Final on it. */
++        memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX));
++}
diff --git a/quagga/patches/201-werr.patch b/quagga/patches/201-werr.patch
new file mode 100644
index 0000000..a7d0fa9
--- /dev/null
+++ b/quagga/patches/201-werr.patch
@@ -0,0 +1,11 @@
+--- a/eigrpd/eigrp_update.c   2015-11-03 23:52:48.000000000 +0200
++++ b/eigrpd/eigrp_update.c      2015-11-04 21:29:09.000000000 +0200
+@@ -182,7 +182,7 @@
+ 
+ 			  if (alist) {
+ 				  zlog_info ("ALIST:");
+-				  zlog_info (alist->name);
++				  zlog_info ("%s", alist->name);
+ 			  } else {
+ 				  zlog_info("ALIST je prazdny");
+ 			  }
-------------- next part --------------
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel


More information about the openwrt-devel mailing list