[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