changeset 417:7c10b5cba79b

7066915 Move Quagga to Userland PSARC 2008/038 Move quagga files from /usr/sfw to /usr 6636788 quagga files should move from /usr/sfw 6610234 Pre-quagga start/stop scripts in /usr/sfw/sbin (bgpdstart,ospfdstart,etc..) should be removed 7064040 quagga smf start method no longer needs to worry about upgrade from SUNWzerbra 7027236 ospfd should allow the -a option to be set in smf 7066821 quaggaadm usage message gives program name as quaggaadm_usage instead of quaggaadm. 6933282 quagga manual pages need to be adjusted for the new IPS package names. 6615038 quaagadm: there is no usage info for the -e option 7002951 quagga pkg should deliver headers to allow users to build OSPF-API client programs
author Brian Utterback <Brian.Utterback@Oracle.COM>
date Mon, 18 Jul 2011 12:08:25 -0700
parents d3ce52a8aecd
children 5b95e3689883
files components/meta-packages/history/SUNWquagga.p5m components/quagga/Makefile components/quagga/Solaris/README.Solaris components/quagga/Solaris/exec_attr components/quagga/Solaris/ospfd.HA.conf.sample components/quagga/Solaris/quagga.1m components/quagga/Solaris/quaggaadm components/quagga/Solaris/quaggaadm.1m components/quagga/patches/10-sunw-smf.patch components/quagga/patches/15-privs-ipinst.patch components/quagga/patches/20-privs-bgpd.patch components/quagga/patches/25-isisd-dlpi.patch components/quagga/patches/30-ospfd-nssa-asbr.patch components/quagga/patches/35-ospfd-spf-sort.patch components/quagga/patches/40-bgp-capab-cleanup.patch components/quagga/patches/45-bgpd-capab-typo.patch components/quagga/patches/50-bgpd-nosub.patch components/quagga/patches/55-bgpd-rm-assert.patch components/quagga/patches/60-bgp-comm-crash.patch components/quagga/patches/65-isisd-iso-checksum.patch components/quagga/patches/70-isisd-trill.patch components/quagga/patches/75-privs-basicprivset.patch components/quagga/patches/80-ripngd-getopt.patch components/quagga/patches/85-remove-fwding-dependency.patch components/quagga/patches/87-ospfd-apiserver.patch components/quagga/patches/90-fix-manpages components/quagga/quagga.license components/quagga/quagga.p5m
diffstat 28 files changed, 15903 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/meta-packages/history/SUNWquagga.p5m	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# Legacy package information for renamed SUNWntpr and SUNWntpu packages
+#
+
+set name=pkg.fmri value=pkg:/SUNWquagga@0.99.8,5.11-0.133
+set name=pkg.renamed value=true
+
+set name=org.opensolaris.consolidation value=$(CONSOLIDATION)
+
+depend fmri=system/network/routing/quagga@0.99.8-0.133 type=require
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/Makefile	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,78 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../../make-rules/shared-macros.mk
+
+COMPONENT_NAME=		quagga
+COMPONENT_VERSION=	0.99.8
+IPS_COMPONENT_VERSION=	$(COMPONENT_VERSION)
+COMPONENT_SRC=		$(COMPONENT_NAME)-$(COMPONENT_VERSION)
+COMPONENT_ARCHIVE=	$(COMPONENT_SRC).tar.gz
+COMPONENT_ARCHIVE_HASH=	sha1:9576d0ac266d173d2a90b8c6f72da8c6b43583d7
+COMPONENT_ARCHIVE_URL=	http://www.quagga.net/download/attic/$(COMPONENT_ARCHIVE)
+PATCH_LEVEL = 0
+
+# These options are carried over from the SFW consolidation. Using -xO4 was
+# explicitly commented out, but no reason was docuemnted.
+
+studio_OPT = -xO3
+
+LDFLAGS +=-lumem
+CFGLOCALSTATEDIR=/system/volatile/quagga
+CFGSYSCONFDIR=  $(ETCDIR)/quagga
+
+CFLAGS += -xspace -Xa
+CFLAGS += -g -xdebugformat=dwarf -O
+CFLAGS += -errtags=yes -xc99=%all
+CFLAGS += -erroff=E_TRAILING_COMMA_IN_ENUM
+CFLAGS += -erroff=E_STATEMENT_NOT_REACHED
+CFLAGS += -erroff=E_EMPTY_TRANSLATION_UNIT
+
+include ../../make-rules/prep.mk
+include ../../make-rules/configure.mk
+include ../../make-rules/ips.mk
+
+CONFIGURE_OPTIONS +=	--with-tags=""
+CONFIGURE_OPTIONS +=	--with-cflags="$(CFLAGS)"
+CONFIGURE_OPTIONS +=	--enable-opaque-lsa
+CONFIGURE_OPTIONS +=	--localstatedir=$(CFGLOCALSTATEDIR)
+CONFIGURE_OPTIONS +=	--sysconfdir=$(CFGSYSCONFDIR)
+CONFIGURE_OPTIONS +=	--includedir=$(CONFIGURE_INCLUDEDIR)
+CONFIGURE_OPTIONS +=	--infodir=$(CONFIGURE_INFODIR)
+CONFIGURE_OPTIONS +=	--enable-isisd
+CONFIGURE_OPTIONS +=	--enable-trill
+CONFIGURE_OPTIONS +=	--disable-watchquagga
+CONFIGURE_OPTIONS +=	--enable-ospf6d
+CONFIGURE_OPTIONS +=	--enable-ripngd
+CONFIGURE_OPTIONS +=	--enable-user=root
+CONFIGURE_OPTIONS +=	--enable-group=root
+
+BUILD_PKG_DEPENDENCIES =	$(BUILD_TOOLS)
+
+build:		$(BUILD_32)
+install:	$(INSTALL_32)
+test:	$(NO_TESTS)
+
+include ../../make-rules/depend.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/Solaris/README.Solaris	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,503 @@
+#
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+#ident	"@(#)README.Solaris	1.2	11/01/03 SMI"
+
+		SOLARIS' OFFERING OF OPENSOURCE QUAGGA SOFTWARE
+	       ************************************************
+Quagga(version 0.99.4) in Solaris is comprised of the following packages:
+
+SUNWquagga-daemons:
+ - Provides the Quagga daemons and the quaggaadm utility. 
+   The daemons installed by this package are:
+   
+   ripd, ripngd, ospfd, ospf6d, bgpd, and zebra(the routing manager daemon)
+                    
+   This package has dependencies on SUNWquaggar and SUNWquagga-libs
+
+SUNWquaggar: 
+ - Provides sample configuration files in /etc/quagga/, this README.Solaris
+   file and SMF manifests for Quagga daemons.
+
+SUNWquagga-libs:
+ - Provides Quagga-specific dynamic libraries used by the Quagga daemons.
+
+SUNWquagga-dev:
+ - Provides header files, archive libraries and libtool files required for
+   building code using the Quagga libraries. Note that these interfaces are
+   External to Solaris and come without API stability guarantees. See also the
+   attributes (5) manual page.
+ 
+SUNWquaggaS
+
+ - Provides the sources from which this release of the SUNWquagga packages
+   were built. You may need to install either the Workshop compilers or gcc
+   to compile the source.  In order to compile Quagga's vtysh utility, you
+   will need Readline libraries, which are freely available on the web.
+
+
+Location of Installed Files and Directories
+===========================================
+
+Modules of Quagga				Location
+-------------------------------------------------------------
+Sample configuration files			/etc/quagga
+Daemon binaries(zebra,ospfd, ospf6d, ripd, 
+                ripngd, bgpd)			/usr/sbin
+quaggaadm (formerly zebraadm)			/usr/sbin
+daemon start/stop scripts			/lib/svc/method 
+SMF manifests					/lib/svc/manifest/network/routing
+Quagga Info documentation			/usr/share/info
+Manual Pages					/usr/share/man/man1m
+Libraries					/usr/lib
+Development headers				/usr/include/quagga
+
+
+Upgrading from SUNWzebra
+========================
+
+Previously, the Zebra routing protocol suite was delivered as part of the
+SFW consolidation.  This has now been replaced with Quagga, and Zebra
+routing configuration can be migrated easily, either explicitly by running
+"routeadm -u" (see routeadm (1M)), or by rebooting the system. The
+appropriate configuration files for the daemons used will be migrated to
+Quagga, and the equivalent Quagga SMF services will be enabled. 
+
+
+Incompatibilities of Quagga  
+============================
+
+You may use in.routed(1M) on other systems on your network, but you must not
+run in.routed or in.rdisc on the same system that is configured to run
+Quagga. Quagga is incompatible with the Solaris IP Multipathing
+(in.mpathd(1M)) feature.  Do not enable IPMP on a system running Quagga. If
+you have a machine set up with IPMP and wish to run Quagga on it, please
+unconfigure IPMP. See
+
+IPMP details at:
+Solaris 10 System Administrator Collection >>
+	System Administration Guide: IP Services >>
+		Part VI IP Network Multipathing (IPMP)  >>
+			30. Administering IPMP (Task)) 
+
+
+IFF_NORTEXCH Interface Flag Support
+====================================
+
+Currently Quagga is not aware of the IFF_NORTEXCH interface flag, so if
+you're trying to fence off interfaces from the intrusion of unwanted routing
+protocols, make sure you don't configure those interfaces in Quagga.
+
+
+Support Level of Quagga Software
+================================
+
+The contents of SUNWquaggar, SUNWquagga-daemons are provided with full Level
+1 support in accordance with your current software support agreement. This
+support includes Sun's global 24/7 sustaining model.
+
+
+Configuring a Multi-homed Host as a Router Using Quagga
+==========================================================
+
+Steps:
+1. Create the appropriate  daemon configuration file in /etc/quagga.
+   Sample configuration files have been provided in that directory.  
+
+2.  Enable forwarding 
+		routeadm -e ipv4-forwarding
+		routeadm -u
+
+    Disable IPMP if machine is set up with it. To do this, you will 
+    have to undo all the things you had done to configure IPMP
+    on your system. Please see :
+	http://docs.sun.com
+	Product Categories>> Solaris >> Solaris 10
+	Solaris 10 System Administration Guide:IP services, Chapter 30
+
+    for configurations details of IPMP.
+
+3. Ensure that IPMP is disabled, and that the svc:/network/routing/route
+   and svc:/network/routing/rdisc SMF services are disabled.
+
+   Also it is important to note that each daemon is invoked with
+   arguments to disable remote Telnet access to the daemons as it is a
+   security risk. Please do not edit these configuration parameters that
+   comprise part of the daemon-args property for each service.
+
+   Pick the appropriate SMF service for the routing daemon that
+   you wish to start. To enable a Quagga daemon service, type the following
+   routeadm command:
+
+  # routeadm -s routing-svcs="<routing daemon svc>" -e ipv4-routing -u
+  
+  or
+
+  # svcadm enable <routing daemon svc>
+
+  Example: To enable the ospfd daemon, type the command:
+
+  # routeadm -s routing-svcs=ospf:quagga -e ipv4-routing -u
+
+  To enable the ospf6d daemon, type the command:
+
+  # routeadm -s routing-svcs=ospf6:quagga -e ipv6-routing -u
+
+
+Editing the Daemon Arguments
+----------------------------
+You can change the arguments used to invoke the Quagga routing
+daemons by modifying the service properties (listed by
+running "routeadm -l <routing daemon svc>"). For example,
+setting
+
+   # routeadm -m ripng:quagga config_file=/path2/ripng.conf
+
+sets an alternate configuration file.
+
+Monitoring, Debugging and Reconfiguring Quagga Daemons Interactively
+====================================================================
+
+Quagga provides a Telnet UI so that the user can access the daemons in
+real-time.  This interface is disabled by default for all daemons, but can
+be enabled by changing the daemon-args property of Quagga services to a suitable
+value, such as "-A 127.0.0.1":
+
+  # routeadm -m ospf:quagga vty_address="127.0.0.1"
+
+This user interface allows one to connect to each daemon, monitor the
+daemon, tag debugging parameters, and reconfigure the parameters of the
+running daemon. We have provided this facility with a wrapper utility called
+quaggaadm (formerly zebraadm).
+
+To access a particular daemon type
+	/usr/sbin/quaggaadm zebra - to access a running zebra daemon
+	/usr/sbin/quaggaadm ospfd - to access a running ospfd daemon
+	/usr/sbin/quaggaadm ripd - to access a running ripd daemon
+	/usr/sbin/quaggaadm bgpd - to access a running bgpd daemon
+
+*****WARNING*****WARNING****WARNING********
+
+By default, if the daemon-args are not set so as to restrict access, Quagga
+allows a user to remotely access the daemons via the Telnet UI. We STRONGLY
+RECOMMEND AGAINST remote Telnet access of the daemons, as it leaves the
+system vulnerable to security holes. To avoid leaving your system
+vulnerable, all daemons must be invoked with "-A 127.0.0.1" option, as shown
+in the example above where routeadm is used to modify the 'daemon-args'
+property.
+
+*****WARNING*****WARNING****WARNING********
+
+
+Disabling Quagga Daemons on a System
+====================================
+
+If you have enabled Quagga routing daemons as discussed above, and now wish
+to disable them, this can be done generally with:
+
+	# routeadm -d ipv4-routing -u
+
+or
+
+	# routeadm -d ipv6-routing -u
+
+as appropriate. One may also disable just specific daemons with:
+
+	# svcadm disable <daemon service>
+
+High-Availability Networking for Hosts with Quagga
+==================================================
+
+The OSPF-MP (OSPF Multi-Pathing) feature is a layer 3 solution to achieve
+network connectivity redundancy on servers. It uses the popular technique of
+advertising loopback-hosted virtual addresses using a routing protocol, in
+this case the OSPF routing protocol.
+
+The OSPF-MP feature is meant to be enabled on multihomed servers to
+implement an HA solution based on the OSPF protocol. Note that the server's
+interfaces *do not require forwarding to be enabled* for the functioning of
+this feature. The feature does require, though, that
+ip_strict_dst_multihoming not be enabled. The OSPF-MP feature can be
+achieved by configuring Quagga appropriately on a server.
+
+ Configuration
+ =============
+
+	  | loopback virtual addresses:
+          | lo0:1, lo0:2.... lo0:n
+	  |
+	---------------------------------------
+	| server with OSPF-MP feature enabled |
+	---------------------------------------
+	      |	   		   |
+	   ====== subnet A	 ===== subnet B
+	      |                    |
+	----------------------------------
+        |     OSPF      router           |
+	----------------------------------
+		   | 
+		 ======  subnet C
+		   |  
+                ----------
+		| client |
+		----------
+
+ 
+Setting up a Multi-Homed Host with OSPF-MP
+==========================================
+
+Steps
+1.Configure loopback aliases on the machine. Following is an
+  example: 
+	#ifconfig lo0:1 inet plumb 172.16.3.91/32 up
+
+  To have these loopback aliases plumb up across boots, create the
+  corresponding /etc/hostname.lo0:<alias#> files. For the above
+  example loopback alias case, the corresponding /etc/hostname.lo0:1
+  file would have the following entry:
+	172.16.3.91 netmask 255.255.255.255 up
+  
+2. Copy over the OSPF-MP sample configuration files:
+          cd /etc/quagga
+          cp server-zebra.HA.conf.sample zebra.conf
+          cp server-ospfd.HA.conf.sample ospdf.conf
+
+3  Edit the zebra and ospfd configuration files appropriately  
+
+4. Disable forwarding on your server.
+		routeadm -d ipv4-forwarding
+		routeadm -u
+
+5. Disable IPMP if machine is set up with it. To do this you will
+   have to undo all the things you had done to configure IPMP on your
+   system. Please see:
+        http://docs.sun.com
+        Product Categories>> Solaris >> Solaris 10
+        Solaris 10 System Administration Guide:IP services, Chapter 30
+
+    for configuration details of IPMP.
+
+6. Enable the OSPF-MP service at boot time, type the following
+   routeadm command:
+    # routeadm -s routing-svcs=ospf:quagga -e ipv4-routing -u
+
+7. Verify that the loopback hosted addresses are being correctly 
+   advertised by OSPF on the server, use the following snoop command:  
+	snoop -d <device> -rv ospf
+
+Following is the snoop output on a server that is enabled with OSPF-MP, and
+is configured with the loopback alias of the example case above:
+
+ETHER:  ----- Ether Header -----
+ETHER:  
+ETHER:  Packet 8 arrived at 16:23:57.00008
+ETHER:  Packet size = 82 bytes
+ETHER:  Destination = 1:0:5e:0:0:5, (multicast)
+ETHER:  Source      = 0:d0:b7:b9:ac:b2, 
+ETHER:  Ethertype = 0800 (IP)
+ETHER:  
+IP:   ----- IP Header -----
+IP:   
+IP:   Version = 4
+IP:   Header length = 20 bytes
+IP:   Type of service = 0xc0
+IP:         xxx. .... = 6 (precedence)
+IP:         ...0 .... = normal delay
+IP:         .... 0... = normal throughput
+IP:         .... .0.. = normal reliability
+IP:         .... ..0. = not ECN capable transport
+IP:         .... ...0 = no ECN congestion experienced
+IP:   Total length = 68 bytes
+IP:   Identification = 41685
+IP:   Flags = 0x0
+IP:         .0.. .... = may fragment
+IP:         ..0. .... = last fragment
+IP:   Fragment offset = 0 bytes
+IP:   Time to live = 1 seconds/hops
+IP:   Protocol = 89 (OSPF)
+IP:   Header checksum = 2ac5
+IP:   Source address = 10.1.1.1, 10.1.1.1
+IP:   Destination address = 224.0.0.5, 224.0.0.5
+IP:   No options
+IP:   
+OSPF:  ----- OSPF Header -----
+OSPF:  
+OSPF:  Version = 2
+OSPF:  Type = Hello
+OSPF:  Router ID = 10.1.2.1
+OSPF:  Area ID = 0.0.0.1
+OSPF:  Checksum = 0x2b27
+OSPF:  Auth = None
+OSPF HELLO:  ----- Hello Packet -----
+OSPF HELLO:  
+OSPF HELLO:  Options = E
+OSPF HELLO:  Mask = 255.255.255.0
+OSPF HELLO:  Hello interval = 10
+OSPF HELLO:  Priority = 1
+OSPF HELLO:  Dead interval = 40
+OSPF HELLO:  Designated Router = 10.1.1.2
+OSPF HELLO:  Backup Designated Router = 10.1.1.1
+OSPF HELLO:  Neighbor: 172.16.3.91
+ 
+
+Example configuration case on a server with OSPF-MP feature
+-----------------------------------------------------------
+Given a server with the following ifconfig output:
+
+# ifconfig -a
+lo0: flags=1000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4> mtu 8232 index 1
+        inet 127.0.0.1 netmask ff000000 
+lo0:1: flags=1000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4> mtu 8232 index 1
+        inet 172.16.3.91 netmask ffffffff 
+hme1: flags=1100843<UP,BROADCAST,RUNNING,MULTICAST,ROUTER,IPv4> mtu
+1500 index 3  inet 10.10.48.91
+netmask ffffff00 broadcast 10.10.48.255 ether 8:0:20:d9:53:71 
+qfe0: flags=1100843<UP,BROADCAST,RUNNING,MULTICAST,ROUTER,IPv4> mtu 1500 index 4  inet 10.11.48.91
+netmask ffffff00 broadcast 10.11.48.255 ether 0:3:ba:17:4d:47 
+
+Its ospfd and zebra config files for OSPF-MP would be the following:
+::::::::::::::
+zebra.conf
+::::::::::::::
+!
+! Zebra configuration saved from vty
+!   2004/03/08 18:35:11
+!
+hostname test-machine
+password zebra
+log file /var/tmp/zebra.log
+service advanced-vty
+!
+interface lo0
+interface hme1
+ link-detect
+interface qfe0
+ link-detect
+!
+line vty
+!
+::::::::::::::
+ospfd.conf
+::::::::::::::
+!
+! Zebra configuration saved from vty
+!   2004/03/15 16:23:35
+!
+hostname test-machine 
+password zebra
+log file /var/tmp/ospf.log
+service advanced-vty
+!
+router ospf
+ ospf router-id 10.10.48.91 
+ redistribute connected
+ network 10.10.48.0/24 area 1
+ network 10.11.48.0/24 area 1
+!
+line vty
+exec-timeout 0 0
+!
+# 
+
+Troubleshooting the OSPF-MP Feature 
+===================================
+
+Use the following monitoring and debugging commands on a running
+ospfd daemon via the telnet command (ie "/usr/sbin/quaggaadm ospfd").
+
+Monitoring Commands for the ospfd Daemon
+----------------------------------------
+  show ip ospf
+  show ip ospf neighbor
+  show history
+  show debugging ospf
+  show ip ospf interface [INTERFACE]
+  show running-config
+  show startup-config 
+
+Debug Commands for the ospfd Daemon
+-----------------------------------
+  debug ospf event
+  debug ospf ism
+  debug ospf ism (status|events|timers)
+  debug ospf lsa
+  debug ospf lsa (generate|flooding|refresh)
+  debug ospf nsm
+  debug ospf nsm (status|events|timers)
+  debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)
+  debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv)
+     (detail|)
+  debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)
+    (send|recv|detail)
+  debug ospf zebra
+  debug ospf zebra (interface|redistribute)
+
+Similarly, use the following monitoring and debugging commands on a running
+zebra daemon via the telnet command ( ie "/usr/sbin/zebraadm zebra").
+
+Monitor Commands for the zebra Daemon
+--------------------------------------
+  show history
+  show debugging zebra
+  show interface [IFNAME]
+  show ip forwarding
+  show running-config
+  show startup-config
+
+Debug Commands for the zebra Daemon
+-----------------------------------
+  debug zebra events
+  debug zebra kernel
+  debug zebra packet
+  debug zebra packet (recv|send)
+  debug zebra packet (recv|send) detail
+
+
+Fine-tuning the OSPF-MP Feature by Customizing the OSPF Timers
+==============================================================
+Use specific interface level configuration subcommands of Telnet UI 
+to fine-tune the timers of OSPF daemon. To get to the interface level
+configuration mode, type:
+
+	/usr/sbin/quaggaadm ospfd
+	Password:<type password that is set in the ospfd.conf file>
+	<hostname>#configure terminal
+	<hostname>(config)# interface <interface name>
+	<hostname>(config-if)#
+
+The appropriate subcommands to customize the timers are:
+
+ ip ospf dead-interval <1-65535>
+ ip ospf hello-interval <1-65535>
+ ip ospf retransmit-interval <3-65535>
+ ip ospf transmit-delay <1-65535>
+
+You can have these new parameters committed to the configuration file by
+typing:
+
+	<hostname>(config-if)# write file
+
+For further details of the above commands, please see the Quagga
+documentation:
+
+	http://www.quagga.net/docs.php
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/Solaris/exec_attr	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,2 @@
+Network Management:solaris:cmd:RO::/usr/sbin/quaggaadm:privs=basic
+Network Management:solaris:cmd:RO::/usr/sbin/zebraadm:privs=basic
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/Solaris/ospfd.HA.conf.sample	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,34 @@
+!
+! Zebra configuration saved from vty
+!
+# Specify the hostname of the server
+hostname Servername 
+!
+# Specify the password for the vty interface. This will be your telnet login
+# password 
+password zebra
+!
+# Specify the log file name
+log file /var/tmp/ospf.log
+!
+service advanced-vty
+!
+router ospf
+!
+# Specify the router-id to your machine's primary interface IP address
+ospf router-id a.b.c.d 
+!
+redistribute connected
+!
+# Specify the OSPF enabled interface(s).Enter a network entry per OSPF
+# enabled interface If the interface has an address
+# of 10.0.0.1/8 then the command below provides network information
+# to the ospf routers  :
+#                network 10.0.0.0/8 area 0
+# the network command's mask length should be the same as the interface
+# address's mask. All the network entries must have the same area number
+network a.b.c.d/m area  <0-4294967295>
+!
+line vty
+ exec-timeout 0 0
+!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/Solaris/quagga.1m	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,139 @@
+'\" te
+.\" Copyright (c) 2006, 2011, Oracle and/or its affiliates\&. All rights reserved\&.
+.TH quagga 1m "01 Aug 2006" "SunOS 5.11" "System Administration Commands"
+.SH "NAME"
+quagga - advanced routing protocol suite from www.quagga.net
+.SH "SYNOPSIS"
+.PP
+\fBQuagga\fR is an advanced routing software package that provides a suite of
+TCP/IP based routing protocols.
+.PP
+\fBQuagga\fR supports protocols such as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3,
+BGP-4, and BGP-4+. This document is provided for informational purposes to
+help users configure quagga under Solaris specifically. Further
+documentation on quagga configuration in general is provided at
+http://www.quagga.net.
+.SH "DESCRIPTION"
+.PP
+\fBQuagga\fR consists of the following package:
+.sp
+.in +2
+.ie t \(bu
+.el o
+.mk
+.in +3
+.rt
+system/network/routing/quagga - Quagga root files
+.sp
+.in -3
+.in -2
+.PP
+More detailed \fBQuagga\fR documentation is available from
+http://www.quagga.net/docs, or in the GNU Info format \fBQuagga\fR documentation
+installed in /usr/share/info.
+.PP
+In Solaris, quagga daemons are managed by the following smf(5) services:
+.PP
+svc:/network/routing/zebra:quagga	zebra routing manager daemon
+.PP
+svc:/network/routing/rip:quagga	RIPv2 routing daemon
+.PP
+svc:/network/routing/ripng:quagga	RIPng routing daemon
+.PP
+svc:/network/routing/bgp:quagga	BGP routing daemon
+.PP
+svc:/network/routing/ospf:quagga	OSPF routing daemon
+.PP
+svc:/network/routing/ospf6:quagga	OSPF6 routing daemon
+.PP
+\fBQuagga\fR daemons can be configured either via the \fBsmf\fR(5) framework, or via routeadm(1M),
+the global dynamic routing management utility.
+.PP
+Note that quagga was built without the vtysh (unified vty shell) utility, as it depends on a package
+not currently distributed with Solaris.
+.PP
+.SH "COMMANDS"
+.PP
+By default, \fBin.routed\fR and \fBin.ripngd\fR, managed by the svc:/network/routing/route
+and svc:/network/routing/ripng services respectively, are configured as default 
+IPv4/IPv6 routing services. To disable these, either utilize \fBrouteadm\fR (1M) or 
+\fBsvcadm\fR (1M) as follows:
+.sp
+.nf
+\f(CW# routeadm -d route
+# routeadm -d ripng:default
+\fR
+.fi
+.sp
+disables in.routed and in.ripngd respectively using \fBrouteadm\fR (1M). 
+.sp
+.nf
+\f(CW# svcadm disable route:default
+# svcadm disable ripng:default
+\fR
+.fi
+.sp
+disables in.routed and in.ripngd respectively using smf(1). 
+.PP
+Note that these services must be disabled or their quagga counterparts
+(rip:quagga, ripng:quagga) will not run, since they services specify to the
+smf framework that they and their quagga counterparts cannot run
+simultaneously.
+.PP
+To enable quagga services, again either \fBrouteadm\fR(1M) or \fBsvcadm\fR(1M) can be used.
+Note that quagga services, like in.routed and in.ripngd, specify dependencies
+on ipv4(6)-routing(forwarding) services, so as with all smf(1) services, ensure the 
+appropriate dependencies are enabled or the services will not start.
+.PP
+For example,
+.sp
+.nf
+\f(CW# routeadm -e rip:quagga
+# routeadm -e ipv4-routing -u
+\fR
+.fi
+.sp
+enables quagga's RIPv2 daemon (the -u option above is required, as 
+global ip routing/forwarding settings are not applied to the system until next reboot
+unless the -u is issued).
+.PP
+To do the same via \fBsmf\fR(1),
+.sp
+.nf
+\f(CW# svcadm enable -r rip:quagga
+\fR
+.fi
+.sp
+The "-r" option recursively enables rip:quagga's dependencies, which include
+the ipv4-routing service.
+.PP
+The status of all routing daemon services can be displayed via \fBrouteadm\fR(1M),
+run without options, or, through smf(1), via the svcs(1) command.
+.PP
+Commandline arguments to the quagga daemons can be altered by
+modifying the routing/daemon-args property, again either via \fBrouteadm\fR(1M)
+or svccfg(1M):
+.sp
+.nf
+\f(CW# routeadm -m rip:quagga daemon-args="-s"
+\fR
+.fi
+.sp
+or
+.sp
+.nf
+\f(CW# svccfg -s rip:quagga setprop routing/daemon-args="-s"
+# svcadm refresh rip:quagga
+\fR
+.fi
+.sp
+The "refresh" is required to ensure the daemon re-reads its configuration.
+.SH "DIAGNOSTICS"
+.PP
+To see status of all routing services, run \fBrouteadm\fR(1M) without options.
+.SH "SEE ALSO"
+.PP
+\fBripngd\fR(1m), \fBisisd\fR(1m), \fBospfd\fR(1m), \fBospf6d\fR(1m), \fBbgpd\fR(1m), \fBzebra\fR(1m), \fBrouteadm\fR(1M),
+\fBsvcadm\fR(1M), svcs(1), svccfg(1M), smf(5)
+.SH "AUTHORS"
+See <http://www.quagga.net>, or the Info file for an  accurate  list of authors.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/Solaris/quaggaadm	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,114 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+# ident	"@(#)quaggaadm	1.3	08/10/02 SMI"
+daemons="zebra ripd ripngd ospfd ospf6d bgpd isisd"
+
+function quaggaadm_usage
+{
+	print - "Usage:\n" >&2
+	for H in ${daemons} ; do
+		print - "\t${1} [-e] ${H}\t\tConnect to ${H} daemon" >&2
+	done
+	print - "\nThe -e flag enables the named daemon to accept ${1} connections and" >&2
+	print - "must be used on the first use of ${1} to connect to a particular daemon." >&2
+}
+
+if [ ${#} -gt 2 ]
+then
+	quaggaadm_usage ${0}
+	exit 1
+fi
+
+function vty_enable
+{
+	restart=0;
+	
+	/usr/bin/svcprop -p routing/vty_address ${1} \
+		| grep -- '[0-9a-zA-Z]' > /dev/null || \
+		/usr/sbin/routeadm -m ${1} vty_address="127.0.0.1" && \
+			restart=1
+	/usr/bin/svcprop -p routing/vty_port ${1}| grep 0 > /dev/null && \
+		/usr/sbin/routeadm -m ${1} vty_port=${2}
+	if [ $restart = "1" ]; then
+		/usr/sbin/svcadm restart ${1}
+	fi			
+}			
+
+ENABLE="no"
+
+if [ ${#} -eq 2 ] ; then
+	DAEMON=${2}
+	if [ ${1} != "-e" ]; then
+		quaggaadm_usage ${0}
+		exit 1;
+	fi
+	ENABLE="yes"
+elif [ ${#} -eq 1 ] ; then
+	DAEMON=${1}
+fi
+
+case ${DAEMON} in
+	zebra)    # telnet to zebra daemon
+		PORT=2601
+		SVC="zebra:quagga"
+	;;
+	rip|ripd) # telnet to ripd daemon
+		PORT=2602
+		SVC="rip:quagga"
+	;;
+	ripng|ripngd)    # telnet to ripngd daemon
+		PORT=2603
+		SVC="ripng:quagga"
+	;;
+	ospfd|ospf)    # telnet to ospfd daemon
+		PORT=2604
+		SVC="ospf:quagga"
+	;;
+	bgp|bgpd)    # telnet to bgpd daemon
+		PORT=2605
+		SVC="bgp:quagga"
+	;;
+	ospf6|ospf6d)    # telnet to ospf6d daemon
+		PORT=2606
+		SVC="ospf6:quagga"
+	;;
+	isis|isisd)	# telnet to isisd daemon
+		PORT=2608
+		SVC="isis:quagga"
+	;;
+	*)
+		# unknown daemon
+		print - "Unrecognized command: ${1}..." >&2
+		quaggaadm_usage ${0}
+		exit 1
+	;;
+esac
+
+if [ ${ENABLE} = "yes" ] ; then
+	vty_enable ${SVC} ${PORT} || exit 1
+fi
+
+exec telnet 127.0.0.1 ${PORT}
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/Solaris/quaggaadm.1m	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,63 @@
+'\" te
+.\" Copyright (c) 2008, 2011, Oracle and/or its affiliates\&. All rights reserved\&.
+.\" ident	"@(#)quaggaadm.1m	1.3	10/03/16 SMI"
+.TH quaggaadm 1M "02 Oct 2008" "" ""
+.SH "NAME"
+quaggaadm \- quagga routing daemon administration tool
+.SH "SYNOPSIS"
+.PP
+\fBquaggaadm\fR [-\fBe\fR] \fIzebra\fR|\fIripd\fR|\fIripngd\fR|\fIospfd\fR|\fIospf6d\fR|\fIbgpd\fR|\fIisisd\fR
+.SH "DESCRIPTION"
+.PP
+The \fBquaggaadm\fR command is provided as a simple wrapper to facilitate connection
+to the quagga daemons respective vty terminal telnet interfaces. \fBquaggaadm\fR simply telnets
+the appropriate vty port for the specified daemon on localhost, and from there the
+user can update configuration for that daemon. Note that if the vty is disabled
+for the given daemon, \fBquaggaadm\fR will prompt the user to request enable. Note
+that to complete this operation, the user will require solaris.smf.manage.routing
+and solaris.smf.modify.routing authorizations.
+.SH "OPTIONS"
+.PP
+The following command-line options are supported:
+.sp
+.ne 2
+.mk
+.na
+\fB\fB\-e\fR\fR
+.ad
+.sp .6
+.in +4
+Automatically enable the vty for the specified daemon.
+.sp
+.sp 1
+.in -4
+.SH "EXIT STATUS"
+.PP
+The following exit values are returned:
+.sp
+.ne 2
+.mk
+.na
+\fB\fB0\fR\fR
+.ad
+.sp .6
+.in +4
+Successful completion.
+.sp
+.sp 1
+.in -4
+.sp
+.ne 2
+.mk
+.na
+\fB\fB!=0\fR\fR
+.ad
+.sp .6
+.in +4
+An error occurred while obtaining or modifying the system configuration.
+.sp
+.sp 1
+.in -4
+.SH "SEE ALSO"
+.PP
+\fBquagga\fR(1M), \fBattributes\fR(5), \fBrouteadm\fR(1M)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/10-sunw-smf.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,983 @@
+--- solaris/quagga.init.in
++++ solaris/quagga.init.in
+@@ -1,6 +1,6 @@
+ #!/sbin/sh
+ #
+-# Copyright 2001,2003 Sun Microsystems, Inc. All rights reserved.
++# Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ # Use is subject to license terms.
+ #
+ # This file is part of Quagga.
+@@ -25,40 +25,88 @@
+ # Starts/stops the given daemon
+ 
+ SMFINCLUDE=/lib/svc/share/smf_include.sh
++ROUTEADMINCLUDE=/lib/svc/share/routing_include.sh
++GLOBAL_OPTIONS="PAfiug"
+ DAEMON_PATH=@sbindir@
++USER=@enable_user@
++GROUP=@enable_group@
+ 
++# Relevant to S10+
+ quagga_is_globalzone () {
+-	if [ "${QUAGGA_INIT_ZONENAME:=`/sbin/zonename`}" != "global" ]; then
+-		return 1
+-	else
++	if [ "${QUAGGA_INIT_ZONENAME:=`/sbin/zonename`}" = "global" \
++		-o `/sbin/zonename -t` = "exclusive" ]; then
+ 		return 0
++	else
++		return 1
+ 	fi
+ }
+ 
+-# Include smf functions, if available. If not, define smf_present to indicate
+-# there is no SMF. Should allow this script to work pre-S10.
+-if [ -f "$SMFINCLUDE" ] ; then
+-	. "$SMFINCLUDE";
+-else
+-	# pre-SMF system, fake up any functions and exit codes
+-	# which SMFINCLUDE usually provides.
+-	smf_present () {
+-		return 1
+-	}
+-	SMF_EXIT_OK=0;
+-	SMF_EXIT_ERR_CONFIG=96;
+-	SMF_EXIT_ERR_FATAL=95;
+-fi
++routeadm_daemon_args () {
++	# globals
++	args="`get_daemon_option_from_property $SMF_FMRI config_file f`"
++	args="${args} `get_daemon_option_from_property $SMF_FMRI vty_port P`"
++	args="${args} `get_daemon_option_from_property $SMF_FMRI vty_address A`"
++	args="${args} `get_daemon_option_from_property $SMF_FMRI pid_file i`"
+ 	
+-# if there's no SMF, set some default DAEMON_ARGS
+-smf_present || DAEMON_ARGS=""
++	# user and group we need for config file upgrade..
++	SMF_USER=`get_routeadm_property $SMF_FMRI user`
++	SMF_GROUP=`get_routeadm_property()$SMF_FMRI group`
++	if [ "${SMF_USER}" ] ; then
++		USER="${SMF_USER}"
++		args="${args} -u ${SMF_USER}"
++	fi
++	if [ "${SMF_GROUP}" ] ; then 
++		GROUP="${SMF_GROUP}"
++		args="${args} -g ${SMF_GROUP}"
++	fi
+ 
+-usage () {
+-	if smf_present ; then
+-		echo "Usage: $0 <daemon> <daemon arguments>";
+-	else
+-		echo "Usage: $0 <stop|start> <daemon> <daemon arguments>";
++	case $1 in
++	zebra)
++		args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI batch -b true`"
++		args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI retain -r true`"
++		;;
++	ripd|ripngd)
++		args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI retain -r true`"
++		;;
++	bgpd)
++		args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI retain -r true`"
++		args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI no_kernel -n true`"
++		args="${args} `get_daemon_option_from_property $SMF_FMRI bgp_port p 179`"
++		;;
++	esac
++	echo ${args}
++}
++
++# certain daemons need zebra
++routeadm_zebra_enable () {
++
++	if [ "$DAEMON" = "zebra" ]; then
++		return
+ 	fi
++	
++	enable_zebra=`/usr/bin/svcprop -p \
++		routing/enable_zebra $SMF_FMRI 2> /dev/null`
++	if [ "$enable_zebra" != "false" ]; then
++		zenabled=`/usr/bin/svcprop -p general/enabled zebra:quagga`
++		zenabledt=`/usr/bin/svcprop -p general_ovr/enabled zebra:quagga`
++		if [ "$zenabled" = "true" -o "$zenabledt" = "true" ]; then
++			/usr/sbin/svcadm disable zebra:quagga
++			/usr/sbin/svcadm enable -st zebra:quagga
++		else
++			/usr/sbin/svcadm enable -st zebra:quagga 
++		fi
++		if [ "$?" != "0" ]; then
++			echo "Could not enable zebra:quagga"
++			exit $SMF_EXIT_ERR_FATAL
++		fi
++	fi
++}
++
++. "$SMFINCLUDE";
++. "$ROUTEADMINCLUDE"
++	
++usage () {
++	echo "Usage: $0 <daemon>";
+ 	echo "The --pid_file argument is implied";
+ 	echo "This help message: $0 <help|usage>";
+ }
+@@ -67,20 +115,13 @@
+ case $1 in
+ 	'help' | 'usage')
+ 		usage
+-		exit SMF_EXIT_OK
++		exit $SMF_EXIT_OK
+ 		;;
+ esac
+ 
+-if smf_present ; then
+-	QUAGGA_METHOD="start"
+-else
+-	QUAGGA_METHOD="$1"
+-	shift;
+-fi
++QUAGGA_METHOD="start"
+ 
+ DAEMON="$1"
+-shift
+-DAEMON_ARGS="$@"
+ 
+ # daemon path must be given
+ if [ -z "$DAEMON_PATH/$DAEMON" ]; then
+@@ -91,12 +132,9 @@
+ # only bgpd is suitable for running in a non-global zone, at this
+ # time.
+ case "${DAEMON}" in
+-	zebra)
+-		quagga_is_globalzone || exit $SMF_EXIT_OK
+-	;;
+ 	bgpd)
+ 	;;
+-	ospfd | ospf6d | ripd | ripngd )
++	zebra | ospfd | ospf6d | ripd | ripngd )
+ 		quagga_is_globalzone || exit $SMF_EXIT_OK
+ 	;;
+ 	*)
+@@ -105,6 +143,14 @@
+ 	;;
+ esac
+ 
++DAEMON_ARGS=`routeadm_daemon_args $DAEMON`;
++routeadm_zebra_enable $DAEMON;
++
++if [ ! -f "@sysconfdir@/${DAEMON}.conf" ] ; then
++	echo "Could not find config file, @sysconfdir@/${DAEMON}.conf"
++	exit $SMF_EXIT_ERR_CONFIG
++fi
++
+ # we need @quagga_statedir@ to exist, it probably is on tmpfs.
+ if [ ! -d @quagga_statedir@ ] ; then
+ 	mkdir -p @quagga_statedir@
+@@ -115,7 +161,11 @@
+ PIDFILE="@quagga_statedir@/${DAEMON}.pid"
+ 
+ start () {
+-	$DAEMON_PATH/$DAEMON $DAEMON_ARGS --pid_file ${PIDFILE} &
++	if [ ! -x "$DAEMON_PATH/$DAEMON" ] ; then
++		echo "Error, could not find daemon, $DAEMON_PATH/$DAEMON"
++		exit $SMF_EXIT_ERR_FATAL
++	fi
++	eval exec $DAEMON_PATH/$DAEMON $DAEMON_ARGS --pid_file ${PIDFILE} &
+ }
+ 
+ stop () {
+@@ -134,7 +184,7 @@
+ 
+ *)
+ 	usage
+-	exit SMF_EXIT_ERR_FATAL
++	exit $SMF_EXIT_ERR_FATAL
+ 	;;
+ esac	
+ 
+--- solaris/quagga.xml.in
++++ solaris/quagga.xml.in
+@@ -18,18 +18,20 @@
+ 	Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 	02111-1307, USA.
+ 
+-	Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
++	Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ 	Use is subject to license terms.
+ 
+ 	ident	"@(#)quagga.xml	1.0	05/03/15 SMI"
+ -->
+ 
+-<service_bundle type='manifest' name='QUAGGAdaemons:quagga'>
++<service_bundle type='manifest' name='SUNWquagga-daemons:quagga'>
++
+ <service
+ 	name='network/routing/zebra'
+ 	type='service'
+ 	version='1'>
+-
++	
++	<single_instance />
+ 	<instance name='quagga' enabled='false'>
+ 	
+ 	<dependency name='fs'
+@@ -46,24 +48,24 @@
+ 		type='service'>
+ 		<service_fmri value='svc:/network/initial' />
+ 	</dependency>
+-
+-	<dependency name='config_data'
++	
++	<!-- do not not run unless routing-setup has run -->
++	<dependency
++		name='network_routing_setup'
+ 		grouping='require_all'
+-		restart_on='restart'
+-		type='path'>
+-		<service_fmri
+-			value='file://localhost/@sysconfdir@/zebra.conf' />
++		restart_on='refresh'
++		type='service'>
++		<service_fmri value='svc:/network/routing-setup' />
+ 	</dependency>
+-	
++
+ 	<exec_method
+ 		type='method'
+ 		name='start'
+-		exec='/lib/svc/method/quagga zebra %{routing/daemon-args}'
++		exec='/lib/svc/method/quagga zebra'
+ 		timeout_seconds='60'>
+ 		<method_context>
+ 		  <method_credential
+-		   user='root' group='root'
+-		   privileges='basic,net_icmpaccess,net_rawaccess,sys_admin,sys_net_config'/>
++		   user='root' group='root'/>
+  		</method_context>
+ 	</exec_method>
+ 
+@@ -84,11 +86,48 @@
+ 		<propval name='ignore_error'
+ 		    type='astring' value='core,signal' />
+ 	</property_group>
+-
++	
++	<!-- Properties in this group are used by routeadm (1M) -->
++	<property_group name='routeadm' type='application'>
++		<stability value='Unstable' />
++		<!-- Identifies service as a routing service -->
++		<propval name='daemon' type='astring'
++			value='@sbindir@/zebra' />
++		<propval name='value_authorization' type='astring'
++			value='solaris.smf.value.routing' />
++		<!-- zebra should not contribute to ipv4/ipv6 routing state -->
++		<propval name='protocol' type='astring' value='zebra' />
++	</property_group>
++	
++	<!-- Properties in this group are modifiable via routeadm (1M) -->
+ 	<property_group name='routing' type='application'>
++		<stability value='Evolving' />
+ 		<propval name='value_authorization' type='astring' 
+-		         value='solaris.smf.modify.routing' />
+-		<propval name='daemon-args' type='astring' value='-P 0'/>
++		         value='solaris.smf.value.routing' />
++		
++		<!-- Options common to Quagga daemons
++		     Property names are equivalent to the long
++		     option name, consult Quagga documentation -->
++		<!-- The config file to use, if not the default -->
++		<propval name='config_file' type='astring' value=''/>
++		<!-- The vty_port to listen on if not the default.
++		     0 to disable --> 
++		<propval name='vty_port' type='integer' value='0' />
++		<!-- The address to bind the VTY interface to, if not any. -->
++		<propval name='vty_address' type='astring' value='' />
++		<!-- The user to switch to after startup, if not the default -->
++		<propval name='user' type='astring' value='' />
++		<!-- The group to switch to, if not the default.
++		     If user is specified, this defaults to a group with
++		     same name as user -->
++		<propval name='group' type='astring' value='' />
++		<!-- The pidfile to use, if not the default of
++		     @quagga_statedir@ -->
++		<propval name='pid_file' type='astring' value='' />
++		
++		<!-- Options specific to zebra -->
++		<propval name='batch' type='boolean' value='false' />
++		<propval name='retain' type='boolean' value='false' />
+ 	</property_group>
+ 	
+ 	<property_group name='general' type='framework'>
+@@ -95,6 +134,8 @@
+ 		<!-- to start stop routing services -->
+ 		<propval name='action_authorization' type='astring'
+ 			 value='solaris.smf.manage.routing' />
++		<propval name='value_authorization' type='astring'
++			 value='solaris.smf.manage.routing' />
+ 	</property_group>
+ 
+ 	<template>
+@@ -111,7 +152,7 @@
+ 		</documentation>
+ 	</template>
+ 	</instance>
+-	<stability value='Evolving' />
++	<stability value='Unstable' />
+ </service>
+ 
+ <service
+@@ -129,39 +170,40 @@
+ 			value='svc:/system/filesystem/usr:default' />
+ 	</dependency>
+ 
+-	<!-- Depends on Work-In-Progress, not yet in SNV
+-	<dependency name='net'
+-		grouping='require_all'
+-		restart_on='none'
++	<dependency
++		name='ipv4-forwarding'
++		grouping='optional_all'
++		restart_on='refresh'
+ 		type='service'>
+-		<service_fmri value='svc:/network/routing/ipv4-routing' />
++		<service_fmri value='svc:/network/ipv4-forwarding' />
+ 	</dependency>
+-	-->
+ 	
+-	<dependency name='zebra'
+-			grouping='require_all'
+-			restart_on='restart'
+-			type='service'>
+-			<service_fmri value='svc:/network/routing/zebra:quagga' />
+-	</dependency>
+-
+-	<dependency name='config_data'
++	<!-- do not not run unless routing-setup has run -->
++	<dependency
++		name='network_routing_setup'
+ 		grouping='require_all'
+-		restart_on='restart'
+-		type='path'>
+-		<service_fmri
+-			value='file://localhost/@sysconfdir@/ripd.conf' />
++		restart_on='refresh'
++		type='service'>
++		<service_fmri value='svc:/network/routing-setup' />
+ 	</dependency>
+ 	
++	<!-- ensure that restart of zebra is propogated to daemon -->
++	<dependency
++		name='zebra'
++		grouping='optional_all'
++		restart_on='restart'
++		type='service'>
++		<service_fmri value='svc:/network/routing/zebra:quagga' />
++	</dependency>
++
+ 	<exec_method
+ 		type='method'
+ 		name='start'
+-		exec='/lib/svc/method/quagga ripd %{routing/daemon-args}'
++		exec='/lib/svc/method/quagga ripd'
+ 		timeout_seconds='60'>
+ 		<method_context>
+ 		  <method_credential
+-		   user='root' group='root'
+-		   privileges='basic,net_icmpaccess,net_privaddr,net_rawaccess'/>
++		   user='root' group='root'/>
+  		</method_context>
+ 	</exec_method>
+ 
+@@ -179,10 +221,42 @@
+ 		    type='astring' value='core,signal' />
+ 	</property_group>
+ 
++	<!-- Properties in this group are used by routeadm (1M) -->
++	<property_group name='routeadm' type='application'>
++		<stability value='Unstable' />
++		<!-- Identifies service as a routing service -->
++		<propval name='daemon' type='astring'
++			value='@sbindir@/ripd' />
++		<propval name='value_authorization' type='astring'
++			value='solaris.smf.value.routing' />
++		<propval name='protocol' type='astring' value='ipv4' />
++	</property_group>
++	
++	<!-- Properties in this group are modifiable via routeadm (1M) -->
+ 	<property_group name='routing' type='application'>
+ 		<propval name='value_authorization' type='astring' 
+-		         value='solaris.smf.modify.routing' />
+-		<propval name='daemon-args' type='astring' value='-P 0'/>
++		         value='solaris.smf.value.routing' />
++
++		<!-- Options common to Quagga daemons -->
++		<!-- The config file to use, if not the default -->
++		<propval name='config_file' type='astring' value=''/>
++		<!-- The vty_port to listen on if not the default.
++		     0 to disable --> 
++		<propval name='vty_port' type='integer' value='0' />
++		<!-- The address to bind the VTY interface to, if not any. -->
++		<propval name='vty_address' type='astring' value='' />
++		<!-- The user to switch to after startup, if not the default -->
++		<propval name='user' type='astring' value='' />
++		<!-- The group to switch to, if not the default.
++		     If user is specified, this defaults to a group with
++		     same name as user -->
++		<propval name='group' type='astring' value='' />
++		<!-- The pidfile to use, if not the default of
++		     @quagga_statedir@ -->
++		<propval name='pid_file' type='astring' value='' />
++		
++		<!-- Options specific to ripd -->
++		<propval name='retain' type='boolean' value='false' />
+ 	</property_group>
+ 
+ 	<property_group name='general' type='framework'>
+@@ -189,6 +263,8 @@
+ 		<!-- to start stop routing services -->
+ 		<propval name='action_authorization' type='astring'
+ 			 value='solaris.smf.manage.routing' />
++		<propval name='value_authorization' type='astring'
++			 value='solaris.smf.manage.routing' />
+ 	</property_group>
+ 
+ 	<template>
+@@ -205,7 +281,7 @@
+ 		</documentation>
+ 	</template>
+ 	</instance>
+-	<stability value='Evolving' />
++	<stability value='Unstable' />
+ </service>
+ 
+ <service
+@@ -223,39 +299,40 @@
+ 			value='svc:/system/filesystem/usr:default' />
+ 	</dependency>
+ 	
+-	<!-- Depends on WIP, not yet in SNV
+-	<dependency name='net'
+-		grouping='require_all'
+-		restart_on='none'
++	<dependency
++		name='ipv6-forwarding'
++		grouping='optional_all'
++		restart_on='refresh'
+ 		type='service'>
+-		<service_fmri value='svc:/network/routing/ipv6-routing' />
++		<service_fmri value='svc:/network/ipv6-forwarding' />
+ 	</dependency>
+-	-->
+ 
+-	<dependency name='zebra'
+-			grouping='require_all'
+-			restart_on='restart'
+-			type='service'>
+-			<service_fmri value='svc:/network/routing/zebra:quagga' />
++	<!-- do not not run unless routing-setup has run -->
++	<dependency
++		name='network_routing_setup'
++		grouping='require_all'
++		restart_on='refresh'
++		type='service'>
++		<service_fmri value='svc:/network/routing-setup' />
+ 	</dependency>
+ 
+-	<dependency name='config_data'
+-		grouping='require_all'
++	<!-- ensure that restart of zebra is propogated to daemon -->
++	<dependency
++		name='zebra'
++		grouping='optional_all'
+ 		restart_on='restart'
+-		type='path'>
+-		<service_fmri
+-			value='file://localhost/@sysconfdir@/ripngd.conf' />
++		type='service'>
++		<service_fmri value='svc:/network/routing/zebra:quagga' />
+ 	</dependency>
+-	
++
+ 	<exec_method
+ 		type='method'
+ 		name='start'
+-		exec='/lib/svc/method/quagga ripngd %{routing/daemon-args}'
++		exec='/lib/svc/method/quagga ripngd'
+ 		timeout_seconds='60'>
+ 		<method_context>
+ 		  <method_credential
+-		   user='root' group='root'
+-		   privileges='basic,net_icmpaccess,net_privaddr,net_rawaccess'/>
++		   user='root' group='root'/>
+  		</method_context>
+ 	</exec_method>
+ 
+@@ -273,10 +350,42 @@
+ 		    type='astring' value='core,signal' />
+ 	</property_group>
+ 
++	<!-- Properties in this group are used by routeadm (1M) -->
++	<property_group name='routeadm' type='application'>
++		<stability value='Unstable' />
++		<!-- Identifies service as a routing service -->
++		<propval name='daemon' type='astring'
++			value='@sbindir@/ripngd' />
++		<propval name='value_authorization' type='astring'
++			value='solaris.smf.value.routing' />
++		<propval name='protocol' type='astring' value='ipv6'/>
++	</property_group>
++	
++	<!-- Properties in this group are modifiable via routeadm (1M) -->
+ 	<property_group name='routing' type='application'>
+ 		<propval name='value_authorization' type='astring' 
+-		         value='solaris.smf.modify.routing' />
+-		<propval name='daemon-args' type='astring' value='-P 0'/>
++		         value='solaris.smf.value.routing' />
++
++		<!-- Options common to Quagga daemons -->
++		<!-- The config file to use, if not the default -->
++		<propval name='config_file' type='astring' value=''/>
++		<!-- The vty_port to listen on if not the default.
++		     0 to disable --> 
++		<propval name='vty_port' type='integer' value='0' />
++		<!-- The address to bind the VTY interface to, if not any. -->
++		<propval name='vty_address' type='astring' value='' />
++		<!-- The user to switch to after startup, if not the default -->
++		<propval name='user' type='astring' value='' />
++		<!-- The group to switch to, if not the default.
++		     If user is specified, this defaults to a group with
++		     same name as user -->
++		<propval name='group' type='astring' value='' />
++		<!-- The pidfile to use, if not the default of
++		     @quagga_statedir@ -->
++		<propval name='pid_file' type='astring' value='' />
++
++		<!-- Options specific to ripngd -->
++		<propval name='retain' type='boolean' value='false' />
+ 	</property_group>
+ 
+ 	<property_group name='general' type='framework'>
+@@ -283,6 +392,8 @@
+ 		<!-- to start stop routing services -->
+ 		<propval name='action_authorization' type='astring'
+ 			 value='solaris.smf.manage.routing' />
++		<propval name='value_authorization' type='astring'
++			 value='solaris.smf.manage.routing' />
+ 	</property_group>
+ 
+ 	<template>
+@@ -299,7 +410,7 @@
+ 		</documentation>
+ 	</template>
+ 	</instance>
+-	<stability value='Evolving' />
++	<stability value='Unstable' />
+ </service>
+ 
+ <service
+@@ -317,47 +428,51 @@
+ 			value='svc:/system/filesystem/usr:default' />
+ 	</dependency>
+ 	
+-	<!-- Depends on WIP, not yet in SNV
+-	<dependency name='net'
+-		grouping='require_all'
+-		restart_on='none'
++	<dependency
++		name='ipv4-forwarding'
++		grouping='optional_all'
++		restart_on='refresh'
+ 		type='service'>
+-		<service_fmri value='svc:/network/routing/ipv4-routing' />
++		<service_fmri value='svc:/network/ipv4-forwarding' />
+ 	</dependency>
+-	-->
+ 
+-	<dependency name='zebra'
+-			grouping='require_all'
+-			restart_on='restart'
+-			type='service'>
+-			<service_fmri value='svc:/network/routing/zebra:quagga' />
++	<!-- do not not run unless routing-setup has run -->
++	<dependency
++		name='network_routing_setup'
++		grouping='require_all'
++		restart_on='refresh'
++		type='service'>
++		<service_fmri value='svc:/network/routing-setup' />
+ 	</dependency>
+ 
+-	<dependency name='config_data'
+-		grouping='require_all'
++	<!-- ensure that restart of zebra is propogated to daemon -->
++	<dependency
++		name='zebra'
++		grouping='optional_all'
+ 		restart_on='restart'
+-		type='path'>
+-		<service_fmri
+-			value='file://localhost/@sysconfdir@/ospfd.conf' />
++		type='service'>
++		<service_fmri value='svc:/network/routing/zebra:quagga' />
+ 	</dependency>
+-	
++
+ 	<exec_method
+ 		type='method'
+ 		name='start'
+-		exec='/lib/svc/method/quagga ospfd %{routing/daemon-args}'
++		exec='/lib/svc/method/quagga ospfd'
+ 		timeout_seconds='60'>
+ 		<method_context>
+ 		  <method_credential
+-		   user='root' group='root'
+-		   privileges='basic,net_icmpaccess,net_privaddr,net_rawaccess,sys_net_config'/>
++		   user='root' group='root'/>
+  		</method_context>
+ 	</exec_method>
+ 
++	<!-- ospfd can take a long time to shutdown, due to graceful 
++	     shutdown 
++	 -->
+ 	<exec_method
+ 		type='method'
+ 		name='stop'
+ 		exec=':kill'
+-		timeout_seconds='60'>
++		timeout_seconds='600'>
+ 	</exec_method>
+ 
+ 	<property_group name='startd'
+@@ -367,10 +482,39 @@
+ 		    type='astring' value='core,signal' />
+ 	</property_group>
+ 
++	<!-- Properties in this group are used by routeadm (1M) -->
++	<property_group name='routeadm' type='application'>
++		<stability value='Unstable' />
++		<!-- Identifies service as a routing service -->
++		<propval name='daemon' type='astring'
++			value='@sbindir@/ospfd' />
++		<propval name='value_authorization' type='astring'
++			value='solaris.smf.value.routing' />
++		<propval name='protocol' type='astring' value='ipv4'/>
++	</property_group>
++	
++	<!-- Properties in this group are modifiable via routeadm (1M) -->
+ 	<property_group name='routing' type='application'>
+ 		<propval name='value_authorization' type='astring' 
+-		         value='solaris.smf.modify.routing' />
+-		<propval name='daemon-args' type='astring' value='-P 0'/>
++		         value='solaris.smf.value.routing' />
++
++		<!-- Options common to Quagga daemons -->
++		<!-- The config file to use, if not the default -->
++		<propval name='config_file' type='astring' value=''/>
++		<!-- The vty_port to listen on if not the default.
++		     0 to disable --> 
++		<propval name='vty_port' type='integer' value='0' />
++		<!-- The address to bind the VTY interface to, if not any. -->
++		<propval name='vty_address' type='astring' value='' />
++		<!-- The user to switch to after startup, if not the default -->
++		<propval name='user' type='astring' value='' />
++		<!-- The group to switch to, if not the default.
++		     If user is specified, this defaults to a group with
++		     same name as user -->
++		<propval name='group' type='astring' value='' />
++		<!-- The pidfile to use, if not the default of
++		     @quagga_statedir@ -->
++		<propval name='pid_file' type='astring' value='' />
+ 	</property_group>
+ 
+ 	<property_group name='general' type='framework'>
+@@ -377,6 +521,8 @@
+ 		<!-- to start stop routing services -->
+ 		<propval name='action_authorization' type='astring'
+ 			 value='solaris.smf.manage.routing' />
++		<propval name='value_authorization' type='astring'
++			 value='solaris.smf.manage.routing' />
+ 	</property_group>
+ 
+ 	<template>
+@@ -393,7 +539,7 @@
+ 		</documentation>
+ 	</template>
+ 	</instance>
+-	<stability value='Evolving' />
++	<stability value='Unstable' />
+ </service>
+ 
+ <service
+@@ -411,39 +557,40 @@
+ 			value='svc:/system/filesystem/usr:default' />
+ 	</dependency>
+ 	
+-	<!-- Depends on WIP, not yet in SNV
+-	<dependency name='net'
+-		grouping='require_all'
+-		restart_on='none'
++	<dependency
++		name='ipv6-forwarding'
++		grouping='optional_all'
++		restart_on='refresh'
+ 		type='service'>
+-		<service_fmri value='svc:/network/routing/ipv6-routing' />
++		<service_fmri value='svc:/network/ipv6-forwarding' />
+ 	</dependency>
+-	-->
+ 
+-	<dependency name='zebra'
+-			grouping='require_all'
+-			restart_on='restart'
+-			type='service'>
+-			<service_fmri value='svc:/network/routing/zebra:quagga' />
++	<!-- do not not run unless routing-setup has run -->
++	<dependency
++		name='network_routing_setup'
++		grouping='require_all'
++		restart_on='refresh'
++		type='service'>
++		<service_fmri value='svc:/network/routing-setup' />
+ 	</dependency>
+ 
+-	<dependency name='config_data'
+-		grouping='require_all'
++	<!-- ensure that restart of zebra is propogated to daemon -->
++	<dependency
++		name='zebra'
++		grouping='optional_all'
+ 		restart_on='restart'
+-		type='path'>
+-		<service_fmri
+-			value='file://localhost/@sysconfdir@/ospf6d.conf' />
++		type='service'>
++		<service_fmri value='svc:/network/routing/zebra:quagga' />
+ 	</dependency>
+-	
++
+ 	<exec_method
+ 		type='method'
+ 		name='start'
+-		exec='/lib/svc/method/quagga ospf6d %{routing/daemon-args}'
++		exec='/lib/svc/method/quagga ospf6d'
+ 		timeout_seconds='60'>
+ 		<method_context>
+ 		  <method_credential
+-		   user='root' group='root'
+-		   privileges='basic,net_icmpaccess,net_privaddr,net_rawaccess'/>
++		   user='root' group='root'/>
+  		</method_context>
+ 	</exec_method>
+ 
+@@ -461,10 +608,39 @@
+ 		    type='astring' value='core,signal' />
+ 	</property_group>
+ 
++	<!-- Properties in this group are used by routeadm (1M) -->
++	<property_group name='routeadm' type='application'>
++		<stability value='Unstable' />
++		<!-- Identifies service as a routing service -->
++		<propval name='daemon' type='astring'
++			value='@sbindir@/ospf6d' />
++		<propval name='value_authorization' type='astring'
++			value='solaris.smf.value.routing' />
++		<propval name='protocol' type='astring' value='ipv6'/>
++	</property_group>
++	
++	<!-- Properties in this group are modifiable via routeadm (1M) -->
+ 	<property_group name='routing' type='application'>
+ 		<propval name='value_authorization' type='astring' 
+-		         value='solaris.smf.modify.routing' />
+-		<propval name='daemon-args' type='astring' value='-P 0'/>
++		         value='solaris.smf.value.routing' />
++
++		<!-- Options common to Quagga daemons -->
++		<!-- The config file to use, if not the default -->
++		<propval name='config_file' type='astring' value=''/>
++		<!-- The vty_port to listen on if not the default.
++		     0 to disable --> 
++		<propval name='vty_port' type='integer' value='0' />
++		<!-- The address to bind the VTY interface to, if not any. -->
++		<propval name='vty_address' type='astring' value='' />
++		<!-- The user to switch to after startup, if not the default -->
++		<propval name='user' type='astring' value='' />
++		<!-- The group to switch to, if not the default.
++		     If user is specified, this defaults to a group with
++		     same name as user -->
++		<propval name='group' type='astring' value='' />
++		<!-- The pidfile to use, if not the default of
++		     @quagga_statedir@ -->
++		<propval name='pid_file' type='astring' value='' />
+ 	</property_group>
+ 
+ 	<property_group name='general' type='framework'>
+@@ -471,12 +647,14 @@
+ 		<!-- to start stop routing services -->
+ 		<propval name='action_authorization' type='astring'
+ 			 value='solaris.smf.manage.routing' />
++		<propval name='value_authorization' type='astring'
++			 value='solaris.smf.manage.routing' />
+ 	</property_group>
+ 
+ 	<template>
+ 		<common_name>
+ 			<loctext xml:lang='C'>
+-			Quagga: ospf6d, OSPFv3 IPv6 routing protocol daemon.
++ 			Quagga: ospf6d, OSPFv3 IPv6 routing protocol daemon.
+ 			</loctext>
+ 		</common_name>
+ 		<documentation>
+@@ -487,7 +665,7 @@
+ 		</documentation>
+ 	</template>
+ 	</instance>
+-	<stability value='Evolving' />
++	<stability value='Unstable' />
+ </service>
+ 
+ 
+@@ -506,40 +684,48 @@
+ 			value='svc:/system/filesystem/usr:default' />
+ 	</dependency>
+ 	
+-	<!-- Depends on WIP, not yet in SNV
+-	<dependency name='net'
+-		grouping='require_any'
+-		restart_on='none'
++	<dependency
++		name='ipv6-forwarding'
++		grouping='optional_all'
++		restart_on='refresh'
+ 		type='service'>
+-		<service_fmri value='svc:/network/routing/ipv6-routing' />
+-		<service_fmri value='svc:/network/routing/ipv4-routing' />
++		<service_fmri value='svc:/network/ipv6-forwarding' />
+ 	</dependency>
+-	-->
++
++	<dependency
++		name='ipv4-forwarding'
++		grouping='optional_all'
++		restart_on='refresh'
++		type='service'>
++		<service_fmri value='svc:/network/ipv4-forwarding' />
++	</dependency>
+ 	
+-	<dependency name='zebra'
+-			grouping='optional_all'
+-			restart_on='restart'
+-			type='service'>
+-			<service_fmri value='svc:/network/routing/zebra:quagga' />
++	<!-- do not not run unless routing-setup has run -->
++	<dependency
++		name='network_routing_setup'
++		grouping='require_all'
++		restart_on='refresh'
++		type='service'>
++		<service_fmri value='svc:/network/routing-setup' />
+ 	</dependency>
+ 
+-	<dependency name='config_data'
+-		grouping='require_all'
++	<!-- ensure that restart of zebra is propogated to daemon -->
++	<dependency
++		name='zebra'
++		grouping='optional_all'
+ 		restart_on='restart'
+-		type='path'>
+-		<service_fmri
+-			value='file://localhost/@sysconfdir@/bgpd.conf' />
++		type='service'>
++		<service_fmri value='svc:/network/routing/zebra:quagga' />
+ 	</dependency>
+-	
++
+ 	<exec_method
+ 		type='method'
+ 		name='start'
+-		exec='/lib/svc/method/quagga bgpd %{routing/daemon-args}'
++		exec='/lib/svc/method/quagga bgpd'
+ 		timeout_seconds='60'>
+ 		<method_context>
+ 		  <method_credential
+-		   user='root' group='root'
+-		   privileges='basic,net_icmpaccess,net_privaddr,net_rawaccess'/>
++		   user='root' group='root'/>
+  		</method_context>
+ 	</exec_method>
+ 
+@@ -557,10 +743,55 @@
+ 		    type='astring' value='core,signal' />
+ 	</property_group>
+ 
++	<!-- Properties in this group are used by routeadm (1M) -->
++	<property_group name='routeadm' type='application'>
++		<stability value='Unstable' />
++		<!-- Identifies service as a routing service -->
++		<propval name='daemon' type='astring'
++			value='@sbindir@/bgpd' />
++		<propval name='value_authorization' type='astring'
++			value='solaris.smf.value.routing' />
++		<property name='protocol' type='astring'>
++			<astring_list>
++				<value_node value='ipv4'/>
++				<value_node value='ipv6'/>
++			</astring_list>
++		</property>
++	</property_group>
++	
++	<!-- Properties in this group are modifiable via routeadm (1M) -->
+ 	<property_group name='routing' type='application'>
+ 		<propval name='value_authorization' type='astring' 
+-		         value='solaris.smf.modify.routing' />
+-		<propval name='daemon-args' type='astring' value='-P 0'/>
++		         value='solaris.smf.value.routing' />
++
++		<!-- Options common to Quagga daemons. -->
++		<!-- The config file to use, if not the default -->
++		<propval name='config_file' type='astring' value=''/>
++		<!-- The vty_port to listen on if not the default.
++		     0 to disable --> 
++		<propval name='vty_port' type='integer' value='0' />
++		<!-- The address to bind the VTY interface to, if not any. -->
++		<propval name='vty_address' type='astring' value='' />
++		<!-- The user to switch to after startup, if not the default -->
++		<propval name='user' type='astring' value='' />
++		<!-- The group to switch to, if not the default.
++		     If user is specified, this defaults to a group with
++		     same name as user -->
++		<propval name='group' type='astring' value='' />
++		<!-- The pidfile to use, if not the default of
++		     @quagga_statedir@ -->
++		<propval name='pid_file' type='astring' value='' />
++
++		<!-- Options specific to bgpd -->
++		<propval name='retain' type='boolean' value='false' />
++		<propval name='no_kernel' type='boolean' value='false' />
++		<propval name='bgp_port' type='astring' value='' />
++		
++		<!--
++			If enable_zebra is false, it will not be switched
++			on by the start method.
++		-->
++		<propval name='enable_zebra' type='boolean' value='true' />
+ 	</property_group>
+ 
+ 	<property_group name='general' type='framework'>
+@@ -567,6 +798,8 @@
+ 		<!-- to start stop routing services -->
+ 		<propval name='action_authorization' type='astring'
+ 			 value='solaris.smf.manage.routing' />
++		<propval name='value_authorization' type='astring'
++			 value='solaris.smf.manage.routing' />
+ 	</property_group>
+ 
+ 	<template>
+@@ -583,6 +816,6 @@
+ 		</documentation>
+ 	</template>
+ 	</instance>
+-	<stability value='Evolving' />
++	<stability value='Unstable' />
+ </service>
+ </service_bundle>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/15-privs-ipinst.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,15 @@
+--- lib/privs.c
++++ lib/privs.c
+@@ -117,7 +117,12 @@
+   /* Quagga -> Solaris privilege mappings */
+   [ZCAP_SETID] =	{ 1, (pvalue_t []) { PRIV_PROC_SETID		}, },
+   [ZCAP_BIND] = 	{ 1, (pvalue_t []) { PRIV_NET_PRIVADDR		}, },
++  /* IP_CONFIG is a subset of NET_CONFIG and is allowed in zones */
++#ifdef PRIV_SYS_IP_CONFIG
++  [ZCAP_NET_ADMIN] =	{ 1, (pvalue_t []) { PRIV_SYS_IP_CONFIG	}, },
++#else
+   [ZCAP_NET_ADMIN] =	{ 1, (pvalue_t []) { PRIV_SYS_NET_CONFIG	}, },
++#endif
+   [ZCAP_NET_RAW] = 	{ 2, (pvalue_t []) { PRIV_NET_RAWACCESS,
+                                              PRIV_NET_ICMPACCESS 	}, },
+   [ZCAP_CHROOT] = 	{ 1, (pvalue_t []) { PRIV_PROC_CHROOT		}, },
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/20-privs-bgpd.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,10 @@
+--- bgpd/bgp_main.c
++++ bgpd/bgp_main.c
+@@ -103,7 +103,6 @@
+ zebra_capabilities_t _caps_p [] =  
+ {
+     ZCAP_BIND, 
+-    ZCAP_NET_RAW,
+ };
+ 
+ struct zebra_privs_t bgpd_privs =
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/25-isisd-dlpi.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,2333 @@
+diff --git a/ChangeLog b/ChangeLog
+index 38ea66d..ad1c40c 100644
+--- ChangeLog
++++ ChangeLog
+@@ -1,3 +1,8 @@
++2007-08-07 James Carlson <james.d.carlson@sun.com>
++
++	* configure.ac: Added support for separate link-layer access
++	  mechanisms in isisd.
++
+ 2007-07-27 Paul Jakma <paul.jakma@sun.com>
+ 
+ 	* configure.ac: Bump version to 0.99.8
+diff --git a/configure.ac b/configure.ac
+index 857f415..437767e 100755
+--- configure.ac
++++ configure.ac
+@@ -750,6 +750,35 @@
+ AC_SUBST(KERNEL_METHOD)
+ AC_SUBST(OTHER_METHOD)
+ 
++dnl --------------------------
++dnl Determine IS-IS I/O method
++dnl --------------------------
++AC_CHECK_HEADER(net/bpf.h)
++AC_CHECK_HEADER(sys/dlpi.h)
++AC_MSG_CHECKING(zebra IS-IS I/O method)
++if test x"$opsys" = x"gnu-linux"; then
++  AC_MSG_RESULT(pfpacket)
++  ISIS_METHOD=isis_pfpacket.o
++elif test x"$opsys" = x"sol2-6" -o x"$opsys" = x"sol8"; then
++  AC_MSG_RESULT(DLPI)
++  ISIS_METHOD="isis_dlpi.o"
++else
++  if test $ac_cv_header_net_bpf_h = no; then
++    if test $ac_cv_header_sys_dlpi_h = no; then
++      AC_MSG_RESULT(none)
++      AC_MSG_WARN([*** IS-IS support will not be built ***])
++      ISISD=""
++    else
++      AC_MSG_RESULT(DLPI)
++    fi
++    ISIS_METHOD="isis_dlpi.o"
++  else
++    AC_MSG_RESULT(BPF)
++    ISIS_METHOD="isis_bpf.o"
++  fi
++fi
++AC_SUBST(ISIS_METHOD)
++
+ dnl ------------------------------------
+ dnl check for broken CMSG_FIRSTHDR macro
+ dnl ------------------------------------
+diff --git a/isisd/ChangeLog b/isisd/ChangeLog
+index 8797af1..c2482f0 100644
+--- isisd/ChangeLog
++++ isisd/ChangeLog
+@@ -1,3 +1,20 @@
++2008-01-29 James Carlson <james.d.carlson@sun.com>
++
++	* Fix bug #437, assert due to bogus index management 
++	* isis_flags.c: (flags_initialize) new
++	* (flags_get_index) fix off by one, leading to list assert
++	  on null node data.
++	  (flags_free_index) ditto.
++	* isisd.c: (isis_area_create) use flags_initialize
++	  (isis_area_destroy) deconfigure circuits when
++	  taking down area.
++
++2007-07-18 James Carlson <james.d.carlson@sun.com>
++
++	* isis_network.c: split up into isis_bpf.c, isis_dlpi.c, and
++	  isis_pfpacket.c, selected by autoconf, and added DLPI support.
++	* (general) Fixed to allow compilation and use on Solaris.
++
+ 2006-12-08 Hannes Gredler <hannes@gredler.at>
+ 
+ 	* isis_adjacency.c: (isis_new_adj) Allow NULL snpa argument.
+diff --git a/isisd/Makefile.am b/isisd/Makefile.am
+index 1dd5493..859facd 100644
+--- isisd/Makefile.am
++++ isisd/Makefile.am
+@@ -9,9 +9,11 @@ noinst_LIBRARIES = libisis.a
+ sbin_PROGRAMS = isisd 
+ SUBDIRS = topology
+ 
++isis_method = @ISIS_METHOD@
++
+ libisis_a_SOURCES = \
+ 	isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \
+-	isis_tlv.c isisd.c isis_misc.c isis_network.c isis_zebra.c isis_dr.c \
++	isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \
+ 	isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
+ 	isis_spf.c isis_route.c isis_routemap.c
+ 
+@@ -26,7 +28,11 @@ noinst_HEADERS = \
+ isisd_SOURCES = \
+ 	isis_main.c $(libisis_a_SOURCES)
+ 
+-isisd_LDADD = @ISIS_TOPOLOGY_LIB@ ../lib/libzebra.la @LIBCAP@
++isisd_LDADD = $(isis_method) @ISIS_TOPOLOGY_LIB@ ../lib/libzebra.la @LIBCAP@
++
++isisd_DEPENDENCIES = $(isis_method)
++
++EXTRA_DIST = isis_bpf.c isis_dlpi.c isis_pfpacket.c
+ 
+ examplesdir = $(exampledir)
+ dist_examples_DATA = isisd.conf.sample
+diff --git a/isisd/dict.c b/isisd/dict.c
+index a333d3e..6c3e1e7 100644
+--- isisd/dict.c
++++ isisd/dict.c
+@@ -14,12 +14,13 @@
+  * into proprietary software; there is no requirement for such software to
+  * contain a copyright notice related to this source.
+  *
+- * $Id: dict.c,v 1.4 2005/09/25 12:04:25 hasso Exp $
+- * $Name:  $
++ * $Id$
++ * $Name$
+  */
+ 
+ #include <stdlib.h>
+ #include <stddef.h>
++#include "zebra.h"
+ #include "zassert.h"
+ #define DICT_IMPLEMENTATION
+ #include "dict.h"
+diff --git a/isisd/include-netbsd/iso.h b/isisd/include-netbsd/iso.h
+index 714b42d..1a80aec 100644
+--- isisd/include-netbsd/iso.h
++++ isisd/include-netbsd/iso.h
+@@ -192,7 +192,13 @@ extern struct protosw isosw[];
+ #else
+ /* user utilities definitions from the iso library */
+ 
++#ifdef SUNOS_5
++#define	__P(x)	x
++#define	__BEGIN_DECLS
++#define	__END_DECLS
++#else
+ #include <sys/cdefs.h>
++#endif
+ 
+ __BEGIN_DECLS
+ struct iso_addr *iso_addr __P((const char *));
+diff --git a/isisd/isisd.c b/isisd/isisd.c
+index 714b42d..1a80aec 100644
+--- isisd/isisd.c
++++ isisd/isisd.c
+@@ -130,7 +130,7 @@
+   area->circuit_list = list_new ();
+   area->area_addrs = list_new ();
+   THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1);
+-  area->flags.maxindex = -1;
++  flags_initialize (&area->flags);
+   /*
+    * Default values
+    */
+@@ -215,7 +215,11 @@
+   if (area->circuit_list)
+     {
+       for (ALL_LIST_ELEMENTS (area->circuit_list, node, nnode, circuit))
+-        isis_circuit_del (circuit);
++	{
++	  /* The fact that it's in circuit_list means that it was configured */
++	  isis_circuit_deconfigure (circuit, area);
++	  isis_circuit_del (circuit);
++	}
+       
+       list_delete (area->circuit_list);
+     }
+diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c
+new file mode 100644
+index 0000000..e66ac98
+--- /dev/null
++++ isisd/isis_bpf.c
+@@ -0,0 +1,340 @@
++/*
++ * IS-IS Rout(e)ing protocol - isis_bpf.c
++ *
++ * Copyright (C) 2001,2002    Sampo Saaristo
++ *                            Tampere University of Technology      
++ *                            Institute of Communications Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify it 
++ * under the terms of the GNU General Public Licenseas published by the Free 
++ * Software Foundation; either version 2 of the License, or (at your option) 
++ * any later version.
++ *
++ * This program 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 this program; if not, write to the Free Software Foundation, Inc., 
++ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ */
++
++#include <zebra.h>
++#include <net/if.h>
++#include <netinet/if_ether.h>
++#include <sys/time.h>
++#include <sys/ioctl.h>
++#include <net/bpf.h>
++
++#include "log.h"
++#include "stream.h"
++#include "if.h"
++
++#include "isisd/dict.h"
++#include "isisd/include-netbsd/iso.h"
++#include "isisd/isis_constants.h"
++#include "isisd/isis_common.h"
++#include "isisd/isis_circuit.h"
++#include "isisd/isis_flags.h"
++#include "isisd/isisd.h"
++#include "isisd/isis_constants.h"
++#include "isisd/isis_circuit.h"
++#include "isisd/isis_network.h"
++
++#include "privs.h"
++
++extern struct zebra_privs_t isisd_privs;
++
++struct bpf_insn llcfilter[] = {
++  BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN),	/* check first byte */
++  BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 5),
++  BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 1),
++  BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 3),	/* check second byte */
++  BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 2),
++  BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1),	/* check third byte */
++  BPF_STMT (BPF_RET + BPF_K, (u_int) - 1),
++  BPF_STMT (BPF_RET + BPF_K, 0)
++};
++int readblen = 0;
++u_char *readbuff = NULL;
++
++/*
++ * Table 9 - Architectural constants for use with ISO 8802 subnetworks
++ * ISO 10589 - 8.4.8
++ */
++
++u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 };
++u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 };
++u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 };
++u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 };
++
++static char sock_buff[8192];
++
++static int
++open_bpf_dev (struct isis_circuit *circuit)
++{
++  int i = 0, fd;
++  char bpfdev[128];
++  struct ifreq ifr;
++  u_int16_t blen;
++  int true = 1, false = 0;
++  struct timeval timeout;
++  struct bpf_program bpf_prog;
++
++  do
++    {
++      (void) snprintf (bpfdev, sizeof (bpfdev), "/dev/bpf%d", i++);
++      fd = open (bpfdev, O_RDWR);
++    }
++  while (fd < 0 && errno == EBUSY);
++
++  if (fd < 0)
++    {
++      zlog_warn ("open_bpf_dev(): failed to create bpf socket: %s",
++		 safe_strerror (errno));
++      return ISIS_WARNING;
++    }
++
++  zlog_debug ("Opened BPF device %s", bpfdev);
++
++  memcpy (ifr.ifr_name, circuit->interface->name, sizeof (ifr.ifr_name));
++  if (ioctl (fd, BIOCSETIF, (caddr_t) & ifr) < 0)
++    {
++      zlog_warn ("open_bpf_dev(): failed to bind to interface: %s",
++		 safe_strerror (errno));
++      return ISIS_WARNING;
++    }
++
++  if (ioctl (fd, BIOCGBLEN, (caddr_t) & blen) < 0)
++    {
++      zlog_warn ("failed to get BPF buffer len");
++      blen = circuit->interface->mtu;
++    }
++
++  readblen = blen;
++
++  if (readbuff == NULL)
++    readbuff = malloc (blen);
++
++  zlog_debug ("BPF buffer len = %u", blen);
++
++  /*  BPF(4): reads return immediately upon packet reception.
++   *  Otherwise, a read will block until either the kernel
++   *  buffer becomes full or a timeout occurs. 
++   */
++  if (ioctl (fd, BIOCIMMEDIATE, (caddr_t) & true) < 0)
++    {
++      zlog_warn ("failed to set BPF dev to immediate mode");
++    }
++
++#ifdef BIOCSSEESENT
++  /*
++   * We want to see only incoming packets
++   */
++  if (ioctl (fd, BIOCSSEESENT, (caddr_t) & false) < 0)
++    {
++      zlog_warn ("failed to set BPF dev to incoming only mode");
++    }
++#endif
++
++  /*
++   * ...but all of them
++   */
++  if (ioctl (fd, BIOCPROMISC, (caddr_t) & true) < 0)
++    {
++      zlog_warn ("failed to set BPF dev to promiscuous mode");
++    }
++
++  /*
++   * If the buffer length is smaller than our mtu, lets try to increase it
++   */
++  if (blen < circuit->interface->mtu)
++    {
++      if (ioctl (fd, BIOCSBLEN, &circuit->interface->mtu) < 0)
++	{
++	  zlog_warn ("failed to set BPF buffer len (%u to %u)", blen,
++		     circuit->interface->mtu);
++	}
++    }
++
++  /*
++   * Set a timeout parameter - hope this helps select()
++   */
++  timeout.tv_sec = 600;
++  timeout.tv_usec = 0;
++  if (ioctl (fd, BIOCSRTIMEOUT, (caddr_t) & timeout) < 0)
++    {
++      zlog_warn ("failed to set BPF device timeout");
++    }
++
++  /*
++   * And set the filter
++   */
++  memset (&bpf_prog, 0, sizeof (struct bpf_program));
++  bpf_prog.bf_len = 8;
++  bpf_prog.bf_insns = &(llcfilter[0]);
++  if (ioctl (fd, BIOCSETF, (caddr_t) & bpf_prog) < 0)
++    {
++      zlog_warn ("open_bpf_dev(): failed to install filter: %s",
++		 safe_strerror (errno));
++      return ISIS_WARNING;
++    }
++
++  assert (fd > 0);
++
++  circuit->fd = fd;
++
++  return ISIS_OK;
++}
++
++/*
++ * Create the socket and set the tx/rx funcs
++ */
++int
++isis_sock_init (struct isis_circuit *circuit)
++{
++  int retval = ISIS_OK;
++
++  if (isisd_privs.change (ZPRIVS_RAISE))
++    zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno));
++
++  retval = open_bpf_dev (circuit);
++
++  if (retval != ISIS_OK)
++    {
++      zlog_warn ("%s: could not initialize the socket", __func__);
++      goto end;
++    }
++
++  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
++    {
++      circuit->tx = isis_send_pdu_bcast;
++      circuit->rx = isis_recv_pdu_bcast;
++    }
++  else if (circuit->circ_type == CIRCUIT_T_P2P)
++    {
++      circuit->tx = isis_send_pdu_p2p;
++      circuit->rx = isis_recv_pdu_p2p;
++    }
++  else
++    {
++      zlog_warn ("isis_sock_init(): unknown circuit type");
++      retval = ISIS_WARNING;
++      goto end;
++    }
++
++end:
++  if (isisd_privs.change (ZPRIVS_LOWER))
++    zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno));
++
++  return retval;
++}
++
++int
++isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
++{
++  int bytesread = 0, bytestoread, offset, one = 1;
++  struct bpf_hdr *bpf_hdr;
++
++  assert (circuit->fd > 0);
++
++  if (ioctl (circuit->fd, FIONREAD, (caddr_t) & bytestoread) < 0)
++    {
++      zlog_warn ("ioctl() FIONREAD failed: %s", safe_strerror (errno));
++    }
++
++  if (bytestoread)
++    {
++      bytesread = read (circuit->fd, readbuff, readblen);
++    }
++  if (bytesread < 0)
++    {
++      zlog_warn ("isis_recv_pdu_bcast(): read() failed: %s",
++		 safe_strerror (errno));
++      return ISIS_WARNING;
++    }
++
++  if (bytesread == 0)
++    return ISIS_WARNING;
++
++  bpf_hdr = (struct bpf_hdr *) readbuff;
++
++  assert (bpf_hdr->bh_caplen == bpf_hdr->bh_datalen);
++
++  offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN;
++
++  /* then we lose the BPF, LLC and ethernet headers */
++  stream_write (circuit->rcv_stream, readbuff + offset, 
++                bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
++  stream_set_getp (circuit->rcv_stream, 0);
++
++  memcpy (ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETHER_ADDR_LEN,
++	  ETHER_ADDR_LEN);
++
++  if (ioctl (circuit->fd, BIOCFLUSH, &one) < 0)
++    zlog_warn ("Flushing failed: %s", safe_strerror (errno));
++
++  return ISIS_OK;
++}
++
++int
++isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
++{
++  int bytesread;
++
++  bytesread = stream_read (circuit->rcv_stream, circuit->fd, 
++                           circuit->interface->mtu);
++
++  if (bytesread < 0)
++    {
++      zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", safe_strerror (errno));
++      return ISIS_WARNING;
++    }
++
++  return ISIS_OK;
++}
++
++int
++isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
++{
++  struct ether_header *eth;
++  int written;
++
++  stream_set_getp (circuit->snd_stream, 0);
++
++  /*
++   * First the eth header
++   */
++  eth = (struct ether_header *) sock_buff;
++  if (level == 1)
++    memcpy (eth->ether_dhost, ALL_L1_ISS, ETHER_ADDR_LEN);
++  else
++    memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN);
++  memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN);
++  eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
++
++  /*
++   * Then the LLC
++   */
++  sock_buff[ETHER_HDR_LEN] = ISO_SAP;
++  sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP;
++  sock_buff[ETHER_HDR_LEN + 2] = 0x03;
++
++  /* then we copy the data */
++  memcpy (sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data,
++	  stream_get_endp (circuit->snd_stream));
++
++  /* now we can send this */
++  written = write (circuit->fd, sock_buff,
++		   stream_get_endp (circuit->snd_stream) 
++		    + LLC_LEN + ETHER_HDR_LEN);
++
++  return ISIS_OK;
++}
++
++int
++isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
++{
++  return ISIS_OK;
++}
+diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
+index fe3eb82..af24988 100644
+--- isisd/isis_circuit.c
++++ isisd/isis_circuit.c
+@@ -26,6 +26,10 @@
+ #include <netinet/if_ether.h>
+ #endif
+ 
++#ifndef ETHER_ADDR_LEN
++#define	ETHER_ADDR_LEN	ETHERADDRL
++#endif
++
+ #include "log.h"
+ #include "memory.h"
+ #include "if.h"
+@@ -381,11 +385,13 @@ isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp)
+        * Get the Hardware Address
+        */
+ #ifdef HAVE_STRUCT_SOCKADDR_DL
++#ifndef SUNOS_5
+       if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN)
+ 	zlog_warn ("unsupported link layer");
+       else
+ 	memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl),
+ 		ETH_ALEN);
++#endif
+ #else
+       if (circuit->interface->hw_addr_len != ETH_ALEN)
+ 	{
+@@ -447,10 +453,12 @@ isis_circuit_update_params (struct isis_circuit *circuit,
+    * Get the Hardware Address
+    */
+ #ifdef HAVE_STRUCT_SOCKADDR_DL
++#ifndef SUNOS_5
+   if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN)
+     zlog_warn ("unsupported link layer");
+   else
+     memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl), ETH_ALEN);
++#endif
+ #else
+   if (circuit->interface->hw_addr_len != ETH_ALEN)
+     {
+diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
+index b5ef269..a7e719f 100644
+--- isisd/isis_circuit.h
++++ isisd/isis_circuit.h
+@@ -69,6 +69,7 @@ struct isis_circuit
+   struct isis_area *area;	/* back pointer to the area */
+   struct interface *interface;	/* interface info from z */
+   int fd;			/* IS-IS l1/2 socket */
++  int sap_length;		/* SAP length for DLPI */
+   struct nlpids nlpids;
+   /*
+    * Threads
+diff --git a/isisd/isis_dlpi.c b/isisd/isis_dlpi.c
+new file mode 100644
+index 0000000..db4383b
+--- /dev/null
++++ isisd/isis_dlpi.c
+@@ -0,0 +1,607 @@
++/*
++ * IS-IS Rout(e)ing protocol - isis_dlpi.c
++ *
++ * Copyright (C) 2001,2002    Sampo Saaristo
++ *                            Tampere University of Technology      
++ *                            Institute of Communications Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify it 
++ * under the terms of the GNU General Public Licenseas published by the Free 
++ * Software Foundation; either version 2 of the License, or (at your option) 
++ * any later version.
++ *
++ * This program 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 this program; if not, write to the Free Software Foundation, Inc., 
++ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ */
++
++#include <zebra.h>
++#include <net/if.h>
++#include <netinet/if_ether.h>
++#include <sys/types.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <stropts.h>
++#include <poll.h>
++#include <sys/dlpi.h>
++#include <sys/pfmod.h>
++
++#include "log.h"
++#include "stream.h"
++#include "if.h"
++
++#include "isisd/dict.h"
++#include "isisd/include-netbsd/iso.h"
++#include "isisd/isis_constants.h"
++#include "isisd/isis_common.h"
++#include "isisd/isis_circuit.h"
++#include "isisd/isis_flags.h"
++#include "isisd/isisd.h"
++#include "isisd/isis_constants.h"
++#include "isisd/isis_circuit.h"
++#include "isisd/isis_network.h"
++
++#include "privs.h"
++
++extern struct zebra_privs_t isisd_privs;
++
++static t_uscalar_t dlpi_ctl[1024];	/* DLPI control messages */
++
++/*
++ * Table 9 - Architectural constants for use with ISO 8802 subnetworks
++ * ISO 10589 - 8.4.8
++ */
++
++u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 };
++u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 };
++u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 };
++u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 };
++
++static u_char sock_buff[8192];
++
++static u_short pf_filter[] =
++{
++  ENF_PUSHWORD + 0,		/* Get the SSAP/DSAP values */
++  ENF_PUSHLIT | ENF_CAND,	/* Check them */
++  ISO_SAP | (ISO_SAP << 8),
++  ENF_PUSHWORD + 1,		/* Get the control value */
++  ENF_PUSHLIT | ENF_AND,	/* Isolate it */
++#ifdef _BIG_ENDIAN
++  0xFF00,
++#else
++  0x00FF,
++#endif
++  ENF_PUSHLIT | ENF_CAND,	/* Test for expected value */
++#ifdef _BIG_ENDIAN
++  0x0300
++#else
++  0x0003
++#endif
++};
++
++/*
++ * We would like to use something like libdlpi here, but that's not present on
++ * all versions of Solaris or on any non-Solaris system, so it's nowhere near
++ * as portable as we'd like.  Thus, we use the standards-conformant DLPI
++ * interfaces plus the (optional; not needed) Solaris packet filter module.
++ */
++
++static void
++dlpisend (int fd, const void *cbuf, size_t cbuflen,
++  const void *dbuf, size_t dbuflen, int flags)
++{
++  const struct strbuf *ctlptr = NULL;
++  const struct strbuf *dataptr = NULL;
++  struct strbuf ctlbuf, databuf;
++
++  if (cbuf != NULL)
++    {
++      memset (&ctlbuf, 0, sizeof (ctlbuf));
++      ctlbuf.len = cbuflen;
++      ctlbuf.buf = (void *)cbuf;
++      ctlptr = &ctlbuf;
++    }
++
++  if (dbuf != NULL)
++    {
++      memset (&databuf, 0, sizeof (databuf));
++      databuf.len = dbuflen;
++      databuf.buf = (void *)dbuf;
++      dataptr = &databuf;
++    }
++
++  /* We assume this doesn't happen often and isn't operationally significant */
++  if (putmsg (fd, ctlptr, dataptr, flags) == -1)
++    zlog_debug ("%s: putmsg: %s", __func__, safe_strerror (errno));
++}
++
++static ssize_t
++dlpirctl (int fd)
++{
++  struct pollfd fds[1];
++  struct strbuf ctlbuf, databuf;
++  int flags, retv;
++
++  do
++    {
++      /* Poll is used here in case the device doesn't speak DLPI correctly */
++      memset (fds, 0, sizeof (fds));
++      fds[0].fd = fd;
++      fds[0].events = POLLIN | POLLPRI;
++      if (poll (fds, 1, 1000) <= 0)
++	return -1;
++
++      memset (&ctlbuf, 0, sizeof (ctlbuf));
++      memset (&databuf, 0, sizeof (databuf));
++      ctlbuf.maxlen = sizeof (dlpi_ctl);
++      ctlbuf.buf = (void *)dlpi_ctl;
++      databuf.maxlen = sizeof (sock_buff);
++      databuf.buf = (void *)sock_buff;
++      flags = 0;
++      retv = getmsg (fd, &ctlbuf, &databuf, &flags);
++
++      if (retv < 0)
++	return -1;
++    }
++  while (ctlbuf.len == 0);
++
++  if (!(retv & MORECTL))
++    {
++      while (retv & MOREDATA)
++	{
++	  flags = 0;
++	  retv = getmsg (fd, NULL, &databuf, &flags);
++	}
++      return ctlbuf.len;
++    }
++
++  while (retv & MORECTL)
++    {
++      flags = 0;
++      retv = getmsg (fd, &ctlbuf, &databuf, &flags);
++    }
++  return -1;
++}
++
++static int
++dlpiok (int fd, t_uscalar_t oprim)
++{
++  int retv;
++  dl_ok_ack_t *doa = (dl_ok_ack_t *)dlpi_ctl;
++
++  retv = dlpirctl (fd);
++  if (retv < DL_OK_ACK_SIZE || doa->dl_primitive != DL_OK_ACK ||
++    doa->dl_correct_primitive != oprim)
++    {
++      return -1;
++    }
++  else
++    {
++      return 0;
++    }
++}
++
++static int
++dlpiinfo (int fd)
++{
++  dl_info_req_t dir;
++  ssize_t retv;
++
++  memset (&dir, 0, sizeof (dir));
++  dir.dl_primitive = DL_INFO_REQ;
++  /* Info_req uses M_PCPROTO. */
++  dlpisend (fd, &dir, sizeof (dir), NULL, 0, RS_HIPRI);
++  retv = dlpirctl (fd);
++  if (retv < DL_INFO_ACK_SIZE || dlpi_ctl[0] != DL_INFO_ACK)
++    return -1;
++  else
++    return retv;
++}
++
++static int
++dlpiopen (const char *devpath, ssize_t *acklen)
++{
++  int fd, flags;
++
++  fd = open (devpath, O_RDWR | O_NONBLOCK | O_NOCTTY);
++  if (fd == -1)
++    return -1;
++
++  /* All that we want is for the open itself to be non-blocking, not I/O. */
++  flags = fcntl (fd, F_GETFL, 0);
++  if (flags != -1)
++    fcntl (fd, F_SETFL, flags & ~O_NONBLOCK);
++
++  /* After opening, ask for information */
++  if ((*acklen = dlpiinfo (fd)) == -1)
++    {
++      close (fd);
++      return -1;
++    }
++
++  return fd;
++}
++
++static int
++dlpiattach (int fd, int unit)
++{
++  dl_attach_req_t dar;
++
++  memset (&dar, 0, sizeof (dar));
++  dar.dl_primitive = DL_ATTACH_REQ;
++  dar.dl_ppa = unit;
++  dlpisend (fd, &dar, sizeof (dar), NULL, 0, 0);
++  return dlpiok (fd, dar.dl_primitive);
++}
++
++static int
++dlpibind (int fd)
++{
++  dl_bind_req_t dbr;
++  int retv;
++  dl_bind_ack_t *dba = (dl_bind_ack_t *)dlpi_ctl;
++
++  memset (&dbr, 0, sizeof (dbr));
++  dbr.dl_primitive = DL_BIND_REQ;
++  dbr.dl_service_mode = DL_CLDLS;
++  dlpisend (fd, &dbr, sizeof (dbr), NULL, 0, 0);
++
++  retv = dlpirctl (fd);
++  if (retv < DL_BIND_ACK_SIZE || dba->dl_primitive != DL_BIND_ACK)
++    return -1;
++  else
++    return 0;
++}
++
++static int
++dlpimcast (int fd, const u_char *mcaddr)
++{
++  struct {
++    dl_enabmulti_req_t der;
++    u_char addr[ETHERADDRL];
++  } dler;
++
++  memset (&dler, 0, sizeof (dler));
++  dler.der.dl_primitive = DL_ENABMULTI_REQ;
++  dler.der.dl_addr_length = sizeof (dler.addr);
++  dler.der.dl_addr_offset = dler.addr - (u_char *)&dler;
++  memcpy (dler.addr, mcaddr, sizeof (dler.addr));
++  dlpisend (fd, &dler, sizeof (dler), NULL, 0, 0);
++  return dlpiok (fd, dler.der.dl_primitive);
++}
++
++static int
++dlpiaddr (int fd, u_char *addr)
++{
++  dl_phys_addr_req_t dpar;
++  dl_phys_addr_ack_t *dpaa = (dl_phys_addr_ack_t *)dlpi_ctl;
++  int retv;
++
++  memset (&dpar, 0, sizeof (dpar));
++  dpar.dl_primitive = DL_PHYS_ADDR_REQ;
++  dpar.dl_addr_type = DL_CURR_PHYS_ADDR;
++  dlpisend (fd, &dpar, sizeof (dpar), NULL, 0, 0);
++
++  retv = dlpirctl (fd);
++  if (retv < DL_PHYS_ADDR_ACK_SIZE || dpaa->dl_primitive != DL_PHYS_ADDR_ACK)
++    return -1;
++
++  if (dpaa->dl_addr_offset < DL_PHYS_ADDR_ACK_SIZE ||
++    dpaa->dl_addr_length != ETHERADDRL ||
++    dpaa->dl_addr_offset + dpaa->dl_addr_length > retv)
++    return -1;
++
++  bcopy((char *)dpaa + dpaa->dl_addr_offset, addr, ETHERADDRL);
++  return 0;
++}
++
++static int
++open_dlpi_dev (struct isis_circuit *circuit)
++{
++  int fd, unit, retval;
++  char devpath[MAXPATHLEN];
++  dl_info_ack_t *dia = (dl_info_ack_t *)dlpi_ctl;
++  ssize_t acklen;
++
++  /* Only broadcast-type are supported at the moment */
++  if (circuit->circ_type != CIRCUIT_T_BROADCAST)
++    {
++      zlog_warn ("%s: non-broadcast interface %s", __func__,
++	circuit->interface->name);
++      return ISIS_WARNING;
++    }
++
++  /* Try first as Style 1 */
++  (void) snprintf(devpath, sizeof (devpath), "/dev/%s",
++    circuit->interface->name);
++  unit = -1;
++  fd = dlpiopen (devpath, &acklen);
++
++  /* If that fails, try again as Style 2 */
++  if (fd == -1)
++    {
++      char *cp;
++
++      cp = devpath + strlen (devpath);
++      while (--cp >= devpath && isdigit(*cp))
++	;
++      unit = strtol(cp, NULL, 0);
++      *cp = '\0';
++      fd = dlpiopen (devpath, &acklen);
++
++      /* If that too fails, then the device really doesn't exist */
++      if (fd == -1)
++	{
++	  zlog_warn ("%s: unknown interface %s", __func__,
++	    circuit->interface->name);
++	  return ISIS_WARNING;
++	}
++
++      /* Double check the DLPI style */
++      if (dia->dl_provider_style != DL_STYLE2)
++	{
++	  zlog_warn ("open_dlpi_dev(): interface %s: %s is not style 2",
++	    circuit->interface->name, devpath);
++	  close (fd);
++	  return ISIS_WARNING;
++	}
++
++      /* If it succeeds, then we need to attach to the unit specified */
++      dlpiattach (fd, unit);
++
++      /* Reget the information, as it may be different per node */
++      if ((acklen = dlpiinfo (fd)) == -1)
++	{
++	  close (fd);
++	  return ISIS_WARNING;
++	}
++    }
++  else
++    {
++      /* Double check the DLPI style */
++      if (dia->dl_provider_style != DL_STYLE1)
++	{
++	  zlog_warn ("open_dlpi_dev(): interface %s: %s is not style 1",
++	    circuit->interface->name, devpath);
++	  close (fd);
++	  return ISIS_WARNING;
++	}
++    }
++
++  /* Check that the interface we've got is the kind we expect */
++  if ((dia->dl_sap_length != 2 && dia->dl_sap_length != -2) ||
++    dia->dl_service_mode != DL_CLDLS || dia->dl_addr_length != ETHERADDRL + 2 ||
++    dia->dl_brdcst_addr_length != ETHERADDRL)
++    {
++      zlog_warn ("%s: unsupported interface type for %s", __func__,
++	circuit->interface->name);
++      close (fd);
++      return ISIS_WARNING;
++    }
++  switch (dia->dl_mac_type)
++    {
++    case DL_CSMACD:
++    case DL_ETHER:
++    case DL_100VG:
++    case DL_100VGTPR:
++    case DL_ETH_CSMA:
++    case DL_100BT:
++      break;
++    default:
++      zlog_warn ("%s: unexpected mac type on %s: %d", __func__,
++	circuit->interface->name, dia->dl_mac_type);
++      close (fd);
++      return ISIS_WARNING;
++    }
++
++  circuit->sap_length = dia->dl_sap_length;
++
++  /*
++   * The local hardware address is something that should be provided by way of
++   * sockaddr_dl for the interface, but isn't on Solaris.  We set it here based
++   * on DLPI's reported address to avoid roto-tilling the world.
++   * (Note that isis_circuit_if_add on Solaris doesn't set the snpa.)
++   *
++   * Unfortunately, GLD is broken and doesn't provide the address after attach,
++   * so we need to be careful and use DL_PHYS_ADDR_REQ instead.
++   */
++  if (dlpiaddr (fd, circuit->u.bc.snpa) == -1)
++    {
++      zlog_warn ("open_dlpi_dev(): interface %s: unable to get MAC address",
++	circuit->interface->name);
++      close (fd);
++      return ISIS_WARNING;
++    }
++
++  /* Now bind to SAP 0.  This gives us 802-type traffic. */
++  if (dlpibind (fd) == -1)
++    {
++      zlog_warn ("%s: cannot bind SAP 0 on %s", __func__,
++	circuit->interface->name);
++      close (fd);
++      return ISIS_WARNING;
++    }
++
++  /*
++   * Join to multicast groups according to
++   * 8.4.2 - Broadcast subnetwork IIH PDUs
++   */
++  retval = 0;
++  if (circuit->circuit_is_type & IS_LEVEL_1)
++    {
++      retval |= dlpimcast (fd, ALL_L1_ISS);
++      retval |= dlpimcast (fd, ALL_ISS);
++    }
++  if (circuit->circuit_is_type & IS_LEVEL_2)
++    retval |= dlpimcast (fd, ALL_L2_ISS);
++
++  if (retval != 0)
++    {
++      zlog_warn ("%s: unable to join multicast on %s", __func__,
++	circuit->interface->name);
++      close (fd);
++      return ISIS_WARNING;
++    }
++
++  /* Push on the packet filter to avoid stray 802 packets */
++  if (ioctl (fd, I_PUSH, "pfmod") == 0)
++    {
++      struct packetfilt pfil;
++
++      pfil.Pf_Priority = 0;
++      pfil.Pf_FilterLen = sizeof (pf_filter) / sizeof (u_short);
++      memcpy (pfil.Pf_Filter, pf_filter, sizeof (pf_filter));
++      ioctl (fd, PFIOCSETF, &pfil);
++    }
++
++  circuit->fd = fd;
++
++  return ISIS_OK;
++}
++
++/*
++ * Create the socket and set the tx/rx funcs
++ */
++int
++isis_sock_init (struct isis_circuit *circuit)
++{
++  int retval = ISIS_OK;
++
++  if (isisd_privs.change (ZPRIVS_RAISE))
++    zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno));
++
++  retval = open_dlpi_dev (circuit);
++
++  if (retval != ISIS_OK)
++    {
++      zlog_warn ("%s: could not initialize the socket", __func__);
++      goto end;
++    }
++
++  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
++    {
++      circuit->tx = isis_send_pdu_bcast;
++      circuit->rx = isis_recv_pdu_bcast;
++    }
++  else
++    {
++      zlog_warn ("isis_sock_init(): unknown circuit type");
++      retval = ISIS_WARNING;
++      goto end;
++    }
++
++end:
++  if (isisd_privs.change (ZPRIVS_LOWER))
++    zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno));
++
++  return retval;
++}
++
++int
++isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
++{
++  struct pollfd fds[1];
++  struct strbuf ctlbuf, databuf;
++  int flags, retv;
++  dl_unitdata_ind_t *dui = (dl_unitdata_ind_t *)dlpi_ctl;
++
++  memset (fds, 0, sizeof (fds));
++  fds[0].fd = circuit->fd;
++  fds[0].events = POLLIN | POLLPRI;
++  if (poll (fds, 1, 0) <= 0)
++    return ISIS_WARNING;
++
++  memset (&ctlbuf, 0, sizeof (ctlbuf));
++  memset (&databuf, 0, sizeof (databuf));
++  ctlbuf.maxlen = sizeof (dlpi_ctl);
++  ctlbuf.buf = (void *)dlpi_ctl;
++  databuf.maxlen = sizeof (sock_buff);
++  databuf.buf = (void *)sock_buff;
++  flags = 0;
++  retv = getmsg (circuit->fd, &ctlbuf, &databuf, &flags);
++
++  if (retv < 0)
++    {
++      zlog_warn ("isis_recv_pdu_bcast: getmsg failed: %s",
++		 safe_strerror (errno));
++      return ISIS_WARNING;
++    }
++
++  if (retv & (MORECTL | MOREDATA))
++    {
++      while (retv & (MORECTL | MOREDATA))
++	{
++	  flags = 0;
++	  retv = getmsg (circuit->fd, &ctlbuf, &databuf, &flags);
++	}
++      return ISIS_WARNING;
++    }
++
++  if (ctlbuf.len < DL_UNITDATA_IND_SIZE ||
++    dui->dl_primitive != DL_UNITDATA_IND)
++    return ISIS_WARNING;
++
++  if (dui->dl_src_addr_length != ETHERADDRL + 2 ||
++    dui->dl_src_addr_offset < DL_UNITDATA_IND_SIZE ||
++    dui->dl_src_addr_offset + dui->dl_src_addr_length > ctlbuf.len)
++    return ISIS_WARNING;
++
++  memcpy (ssnpa, (char *)dui + dui->dl_src_addr_offset +
++    (circuit->sap_length > 0 ? circuit->sap_length : 0), ETHERADDRL);
++
++  if (databuf.len < LLC_LEN || sock_buff[0] != ISO_SAP ||
++    sock_buff[1] != ISO_SAP || sock_buff[2] != 3)
++    return ISIS_WARNING;
++
++  stream_write (circuit->rcv_stream, sock_buff + LLC_LEN,
++                databuf.len - LLC_LEN);
++  stream_set_getp (circuit->rcv_stream, 0);
++
++  return ISIS_OK;
++}
++
++int
++isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
++{
++  dl_unitdata_req_t *dur = (dl_unitdata_req_t *)dlpi_ctl;
++  char *dstaddr;
++  u_short *dstsap;
++
++  stream_set_getp (circuit->snd_stream, 0);
++
++  memset (dur, 0, sizeof (*dur));
++  dur->dl_primitive = DL_UNITDATA_REQ;
++  dur->dl_dest_addr_length = ETHERADDRL + 2;
++  dur->dl_dest_addr_offset = sizeof (*dur);
++
++  dstaddr = (char *)(dur + 1);
++  if (circuit->sap_length < 0)
++    {
++      dstsap = (u_short *)(dstaddr + ETHERADDRL);
++    }
++  else
++    {
++      dstsap = (u_short *)dstaddr;
++      dstaddr += circuit->sap_length;
++    }
++  if (level == 1)
++    memcpy (dstaddr, ALL_L1_ISS, ETHERADDRL);
++  else
++    memcpy (dstaddr, ALL_L2_ISS, ETHERADDRL);
++  /* Note: DLPI SAP values are in host byte order */
++  *dstsap = stream_get_endp (circuit->snd_stream) + LLC_LEN;
++
++  sock_buff[0] = ISO_SAP;
++  sock_buff[1] = ISO_SAP;
++  sock_buff[2] = 0x03;
++  memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data,
++	  stream_get_endp (circuit->snd_stream));
++  dlpisend (circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length,
++    sock_buff, stream_get_endp (circuit->snd_stream) + LLC_LEN, 0);
++  return ISIS_OK;
++}
+diff --git a/isisd/isis_flags.c b/isisd/isis_flags.c
+index 1dd5493..859facd 100644
+--- isisd/isis_flags.c
++++ isisd/isis_flags.c
+@@ -29,6 +29,13 @@
+ #include "isisd/isis_common.h"
+ #include "isisd/isis_flags.h"
+ 
++void
++flags_initialize (struct flags *flags)
++{
++  flags->maxindex = 0;
++  flags->free_idcs = NULL;
++}
++
+ int
+ flags_get_index (struct flags *flags)
+ {
+@@ -37,8 +44,7 @@
+ 
+   if (flags->free_idcs == NULL || flags->free_idcs->count == 0)
+     {
+-      flags->maxindex++;
+-      index = flags->maxindex;
++      index = flags->maxindex++;
+     }
+   else
+     {
+@@ -45,6 +51,7 @@
+       node = listhead (flags->free_idcs);
+       index = (int) listgetdata (node);
+       listnode_delete (flags->free_idcs, (void *) index);
++      index--;
+     }
+ 
+   return index;
+@@ -53,12 +60,18 @@
+ void
+ flags_free_index (struct flags *flags, int index)
+ {
++  if (index + 1 == flags->maxindex)
++    {
++      flags->maxindex--;
++      return;
++    }
++
+   if (flags->free_idcs == NULL)
+     {
+       flags->free_idcs = list_new ();
+     }
+ 
+-  listnode_add (flags->free_idcs, (void *) index);
++  listnode_add (flags->free_idcs, (void *) (index + 1));
+ 
+   return;
+ }
+diff --git a/isisd/isis_flags.h b/isisd/isis_flags.h
+--- isisd/isis_flags.h
++++ isisd/isis_flags.h
+index 1dd5493..859facd 100644
+@@ -28,6 +28,7 @@
+  * the support will be achived using the newest drafts */
+ #define ISIS_MAX_CIRCUITS 32 /* = 1024 */	/*FIXME:defined in lsp.h as well */
+ 
++void flags_initialize (struct flags *flags);
+ struct flags *new_flags (int size);
+ int flags_get_index (struct flags *flags);
+ void flags_free_index (struct flags *flags, int index);
+diff --git a/isisd/isis_network.c b/isisd/isis_network.c
+deleted file mode 100644
+index 56459ec..0000000
+--- isisd/isis_network.c
++++ /dev/null
+@@ -1,643 +0,0 @@
+-/*
+- * IS-IS Rout(e)ing protocol - isis_network.c   
+- *
+- * Copyright (C) 2001,2002    Sampo Saaristo
+- *                            Tampere University of Technology      
+- *                            Institute of Communications Engineering
+- *
+- * This program is free software; you can redistribute it and/or modify it 
+- * under the terms of the GNU General Public Licenseas published by the Free 
+- * Software Foundation; either version 2 of the License, or (at your option) 
+- * any later version.
+- *
+- * This program 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 this program; if not, write to the Free Software Foundation, Inc., 
+- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+- */
+-
+-#include <zebra.h>
+-#ifdef GNU_LINUX
+-#include <net/ethernet.h>	/* the L2 protocols */
+-#else
+-#include <net/if.h>
+-#include <netinet/if_ether.h>
+-#endif
+-
+-#include "log.h"
+-#include "stream.h"
+-#include "if.h"
+-
+-#include "isisd/dict.h"
+-#include "isisd/include-netbsd/iso.h"
+-#include "isisd/isis_constants.h"
+-#include "isisd/isis_common.h"
+-#include "isisd/isis_circuit.h"
+-#include "isisd/isis_flags.h"
+-#include "isisd/isisd.h"
+-#include "isisd/isis_constants.h"
+-#include "isisd/isis_circuit.h"
+-#include "isisd/isis_network.h"
+-
+-#include "privs.h"
+-
+-extern struct zebra_privs_t isisd_privs;
+-
+-/*
+- * On linux we can use the packet(7) sockets, in other OSs we have to do with
+- * Berkley Packet Filter (BPF). Please tell me if you can think of a better 
+- * way...
+- */
+-#ifdef GNU_LINUX
+-#include <netpacket/packet.h>
+-#else
+-#include <sys/time.h>
+-#include <sys/ioctl.h>
+-#include <net/bpf.h>
+-struct bpf_insn llcfilter[] = {
+-  BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN),	/* check first byte */
+-  BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 5),
+-  BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 1),
+-  BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 3),	/* check second byte */
+-  BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 2),
+-  BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1),	/* check third byte */
+-  BPF_STMT (BPF_RET + BPF_K, (u_int) - 1),
+-  BPF_STMT (BPF_RET + BPF_K, 0)
+-};
+-int readblen = 0;
+-u_char *readbuff = NULL;
+-#endif /* GNU_LINUX */
+-
+-/*
+- * Table 9 - Architectural constans for use with ISO 8802 subnetworks
+- * ISO 10589 - 8.4.8
+- */
+-
+-u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 };
+-u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 };
+-u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 };
+-u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 };
+-
+-#ifdef GNU_LINUX
+-static char discard_buff[8192];
+-#endif
+-static char sock_buff[8192];
+-
+-/*
+- * if level is 0 we are joining p2p multicast
+- * FIXME: and the p2p multicast being ???
+- */
+-#ifdef GNU_LINUX
+-static int
+-isis_multicast_join (int fd, int registerto, int if_num)
+-{
+-  struct packet_mreq mreq;
+-
+-  memset (&mreq, 0, sizeof (mreq));
+-  mreq.mr_ifindex = if_num;
+-  if (registerto)
+-    {
+-      mreq.mr_type = PACKET_MR_MULTICAST;
+-      mreq.mr_alen = ETH_ALEN;
+-      if (registerto == 1)
+-	memcpy (&mreq.mr_address, ALL_L1_ISS, ETH_ALEN);
+-      else if (registerto == 2)
+-	memcpy (&mreq.mr_address, ALL_L2_ISS, ETH_ALEN);
+-      else if (registerto == 3)
+-	memcpy (&mreq.mr_address, ALL_ISS, ETH_ALEN);
+-      else
+-	memcpy (&mreq.mr_address, ALL_ESS, ETH_ALEN);
+-
+-    }
+-  else
+-    {
+-      mreq.mr_type = PACKET_MR_ALLMULTI;
+-    }
+-#ifdef EXTREME_DEBUG
+-  zlog_debug ("isis_multicast_join(): fd=%d, reg_to=%d, if_num=%d, "
+-	      "address = %02x:%02x:%02x:%02x:%02x:%02x",
+-	      fd, registerto, if_num, mreq.mr_address[0], mreq.mr_address[1],
+-	      mreq.mr_address[2], mreq.mr_address[3], mreq.mr_address[4],
+-	      mreq.mr_address[5]);
+-#endif /* EXTREME_DEBUG */
+-  if (setsockopt (fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq,
+-		  sizeof (struct packet_mreq)))
+-    {
+-      zlog_warn ("isis_multicast_join(): setsockopt(): %s", safe_strerror (errno));
+-      return ISIS_WARNING;
+-    }
+-
+-  return ISIS_OK;
+-}
+-
+-static int
+-open_packet_socket (struct isis_circuit *circuit)
+-{
+-  struct sockaddr_ll s_addr;
+-  int fd, retval = ISIS_OK;
+-
+-  fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL));
+-  if (fd < 0)
+-    {
+-      zlog_warn ("open_packet_socket(): socket() failed %s",
+-		 safe_strerror (errno));
+-      return ISIS_WARNING;
+-    }
+-
+-  /*
+-   * Bind to the physical interface
+-   */
+-  memset (&s_addr, 0, sizeof (struct sockaddr_ll));
+-  s_addr.sll_family = AF_PACKET;
+-  s_addr.sll_protocol = htons (ETH_P_ALL);
+-  s_addr.sll_ifindex = circuit->interface->ifindex;
+-
+-  if (bind (fd, (struct sockaddr *) (&s_addr),
+-	    sizeof (struct sockaddr_ll)) < 0)
+-    {
+-      zlog_warn ("open_packet_socket(): bind() failed: %s", safe_strerror (errno));
+-      return ISIS_WARNING;
+-    }
+-
+-  circuit->fd = fd;
+-
+-  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+-    {
+-      /*
+-       * Join to multicast groups
+-       * according to
+-       * 8.4.2 - Broadcast subnetwork IIH PDUs
+-       * FIXME: is there a case only one will fail??
+-       */
+-      if (circuit->circuit_is_type & IS_LEVEL_1)
+-	{
+-	  /* joining ALL_L1_ISS */
+-	  retval = isis_multicast_join (circuit->fd, 1,
+-					circuit->interface->ifindex);
+-	  /* joining ALL_ISS */
+-	  retval = isis_multicast_join (circuit->fd, 3,
+-					circuit->interface->ifindex);
+-	}
+-      if (circuit->circuit_is_type & IS_LEVEL_2)
+-	/* joining ALL_L2_ISS */
+-	retval = isis_multicast_join (circuit->fd, 2,
+-				      circuit->interface->ifindex);
+-    }
+-  else
+-    {
+-      retval =
+-	isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
+-    }
+-
+-  return retval;
+-}
+-
+-#else
+-
+-static int
+-open_bpf_dev (struct isis_circuit *circuit)
+-{
+-  int i = 0, fd;
+-  char bpfdev[128];
+-  struct ifreq ifr;
+-  u_int16_t blen;
+-  int true = 1, false = 0;
+-  struct timeval timeout;
+-  struct bpf_program bpf_prog;
+-
+-  do
+-    {
+-      (void) snprintf (bpfdev, sizeof (bpfdev), "/dev/bpf%d", i++);
+-      fd = open (bpfdev, O_RDWR);
+-    }
+-  while (fd < 0 && errno == EBUSY);
+-
+-  if (fd < 0)
+-    {
+-      zlog_warn ("open_bpf_dev(): failed to create bpf socket: %s",
+-		 safe_strerror (errno));
+-      return ISIS_WARNING;
+-    }
+-
+-  zlog_debug ("Opened BPF device %s", bpfdev);
+-
+-  memcpy (ifr.ifr_name, circuit->interface->name, sizeof (ifr.ifr_name));
+-  if (ioctl (fd, BIOCSETIF, (caddr_t) & ifr) < 0)
+-    {
+-      zlog_warn ("open_bpf_dev(): failed to bind to interface: %s",
+-		 safe_strerror (errno));
+-      return ISIS_WARNING;
+-    }
+-
+-  if (ioctl (fd, BIOCGBLEN, (caddr_t) & blen) < 0)
+-    {
+-      zlog_warn ("failed to get BPF buffer len");
+-      blen = circuit->interface->mtu;
+-    }
+-
+-  readblen = blen;
+-
+-  if (readbuff == NULL)
+-    readbuff = malloc (blen);
+-
+-  zlog_debug ("BPF buffer len = %u", blen);
+-
+-  /*  BPF(4): reads return immediately upon packet reception.
+-   *  Otherwise, a read will block until either the kernel
+-   *  buffer becomes full or a timeout occurs. 
+-   */
+-  if (ioctl (fd, BIOCIMMEDIATE, (caddr_t) & true) < 0)
+-    {
+-      zlog_warn ("failed to set BPF dev to immediate mode");
+-    }
+-
+-#ifdef BIOCSSEESENT
+-  /*
+-   * We want to see only incoming packets
+-   */
+-  if (ioctl (fd, BIOCSSEESENT, (caddr_t) & false) < 0)
+-    {
+-      zlog_warn ("failed to set BPF dev to incoming only mode");
+-    }
+-#endif
+-
+-  /*
+-   * ...but all of them
+-   */
+-  if (ioctl (fd, BIOCPROMISC, (caddr_t) & true) < 0)
+-    {
+-      zlog_warn ("failed to set BPF dev to promiscuous mode");
+-    }
+-
+-  /*
+-   * If the buffer length is smaller than our mtu, lets try to increase it
+-   */
+-  if (blen < circuit->interface->mtu)
+-    {
+-      if (ioctl (fd, BIOCSBLEN, &circuit->interface->mtu) < 0)
+-	{
+-	  zlog_warn ("failed to set BPF buffer len (%u to %u)", blen,
+-		     circuit->interface->mtu);
+-	}
+-    }
+-
+-  /*
+-   * Set a timeout parameter - hope this helps select()
+-   */
+-  timeout.tv_sec = 600;
+-  timeout.tv_usec = 0;
+-  if (ioctl (fd, BIOCSRTIMEOUT, (caddr_t) & timeout) < 0)
+-    {
+-      zlog_warn ("failed to set BPF device timeout");
+-    }
+-
+-  /*
+-   * And set the filter
+-   */
+-  memset (&bpf_prog, 0, sizeof (struct bpf_program));
+-  bpf_prog.bf_len = 8;
+-  bpf_prog.bf_insns = &(llcfilter[0]);
+-  if (ioctl (fd, BIOCSETF, (caddr_t) & bpf_prog) < 0)
+-    {
+-      zlog_warn ("open_bpf_dev(): failed to install filter: %s",
+-		 safe_strerror (errno));
+-      return ISIS_WARNING;
+-    }
+-
+-  assert (fd > 0);
+-
+-  circuit->fd = fd;
+-
+-  return ISIS_OK;
+-}
+-
+-#endif /* GNU_LINUX */
+-
+-/*
+- * Create the socket and set the tx/rx funcs
+- */
+-int
+-isis_sock_init (struct isis_circuit *circuit)
+-{
+-  int retval = ISIS_OK;
+-
+-  if (isisd_privs.change (ZPRIVS_RAISE))
+-    zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno));
+-
+-#ifdef GNU_LINUX
+-  retval = open_packet_socket (circuit);
+-#else
+-  retval = open_bpf_dev (circuit);
+-#endif
+-
+-  if (retval != ISIS_OK)
+-    {
+-      zlog_warn ("%s: could not initialize the socket", __func__);
+-      goto end;
+-    }
+-
+-  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+-    {
+-      circuit->tx = isis_send_pdu_bcast;
+-      circuit->rx = isis_recv_pdu_bcast;
+-    }
+-  else if (circuit->circ_type == CIRCUIT_T_P2P)
+-    {
+-      circuit->tx = isis_send_pdu_p2p;
+-      circuit->rx = isis_recv_pdu_p2p;
+-    }
+-  else
+-    {
+-      zlog_warn ("isis_sock_init(): unknown circuit type");
+-      retval = ISIS_WARNING;
+-      goto end;
+-    }
+-
+-end:
+-  if (isisd_privs.change (ZPRIVS_LOWER))
+-    zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno));
+-
+-  return retval;
+-}
+-
+-static inline int
+-llc_check (u_char * llc)
+-{
+-  if (*llc != ISO_SAP || *(llc + 1) != ISO_SAP || *(llc + 2) != 3)
+-    return 0;
+-
+-  return 1;
+-}
+-
+-#ifdef GNU_LINUX
+-int
+-isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
+-{
+-  int bytesread, addr_len;
+-  struct sockaddr_ll s_addr;
+-  u_char llc[LLC_LEN];
+-
+-  addr_len = sizeof (s_addr);
+-
+-  memset (&s_addr, 0, sizeof (struct sockaddr_ll));
+-
+-  bytesread = recvfrom (circuit->fd, (void *) &llc,
+-			LLC_LEN, MSG_PEEK,
+-			(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
+-
+-  if (bytesread < 0)
+-    {
+-      zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s",
+-		 circuit->fd, safe_strerror (errno));
+-      zlog_warn ("circuit is %s", circuit->interface->name);
+-      zlog_warn ("circuit fd %d", circuit->fd);
+-      zlog_warn ("bytesread %d", bytesread);
+-      /* get rid of the packet */
+-      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
+-      return ISIS_WARNING;
+-    }
+-  /*
+-   * Filtering by llc field, discard packets sent by this host (other circuit)
+-   */
+-  if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING)
+-    {
+-      /*  Read the packet into discard buff */
+-      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
+-      if (bytesread < 0)
+-	zlog_warn ("isis_recv_pdu_bcast(): read() failed");
+-      return ISIS_WARNING;
+-    }
+-
+-  /* on lan we have to read to the static buff first */
+-  bytesread = recvfrom (circuit->fd, sock_buff, circuit->interface->mtu, 0,
+-			(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
+-
+-  /* then we lose the LLC */
+-  stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN);
+-
+-  memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
+-
+-  return ISIS_OK;
+-}
+-
+-int
+-isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
+-{
+-  int bytesread, addr_len;
+-  struct sockaddr_ll s_addr;
+-
+-  memset (&s_addr, 0, sizeof (struct sockaddr_ll));
+-  addr_len = sizeof (s_addr);
+-
+-  /* we can read directly to the stream */
+-  bytesread = stream_recvfrom (circuit->rcv_stream, circuit->fd,
+-                               circuit->interface->mtu, 0,
+-                               (struct sockaddr *) &s_addr, 
+-                               (socklen_t *) &addr_len);
+-
+-  if (s_addr.sll_pkttype == PACKET_OUTGOING)
+-    {
+-      /*  Read the packet into discard buff */
+-      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
+-      if (bytesread < 0)
+-	zlog_warn ("isis_recv_pdu_p2p(): read() failed");
+-      return ISIS_WARNING;
+-    }
+-
+-  /* If we don't have protocol type 0x00FE which is
+-   * ISO over GRE we exit with pain :)
+-   */
+-  if (ntohs (s_addr.sll_protocol) != 0x00FE)
+-    {
+-      zlog_warn ("isis_recv_pdu_p2p(): protocol mismatch(): %X",
+-		 ntohs (s_addr.sll_protocol));
+-      return ISIS_WARNING;
+-    }
+-
+-  memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
+-
+-  return ISIS_OK;
+-}
+-
+-int
+-isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
+-{
+-  /* we need to do the LLC in here because of P2P circuits, which will
+-   * not need it
+-   */
+-  int written = 1;
+-  struct sockaddr_ll sa;
+-
+-  stream_set_getp (circuit->snd_stream, 0);
+-  memset (&sa, 0, sizeof (struct sockaddr_ll));
+-  sa.sll_family = AF_PACKET;
+-  sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
+-  sa.sll_ifindex = circuit->interface->ifindex;
+-  sa.sll_halen = ETH_ALEN;
+-  if (level == 1)
+-    memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
+-  else
+-    memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
+-
+-  /* on a broadcast circuit */
+-  /* first we put the LLC in */
+-  sock_buff[0] = 0xFE;
+-  sock_buff[1] = 0xFE;
+-  sock_buff[2] = 0x03;
+-
+-  /* then we copy the data */
+-  memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data,
+-	  stream_get_endp (circuit->snd_stream));
+-
+-  /* now we can send this */
+-  written = sendto (circuit->fd, sock_buff,
+-		    stream_get_endp(circuit->snd_stream) + LLC_LEN, 0,
+-		    (struct sockaddr *) &sa, sizeof (struct sockaddr_ll));
+-
+-  return ISIS_OK;
+-}
+-
+-int
+-isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
+-{
+-
+-  int written = 1;
+-  struct sockaddr_ll sa;
+-
+-  stream_set_getp (circuit->snd_stream, 0);
+-  memset (&sa, 0, sizeof (struct sockaddr_ll));
+-  sa.sll_family = AF_PACKET;
+-  sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
+-  sa.sll_ifindex = circuit->interface->ifindex;
+-  sa.sll_halen = ETH_ALEN;
+-  if (level == 1)
+-    memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
+-  else
+-    memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
+-
+-
+-  /* lets try correcting the protocol */
+-  sa.sll_protocol = htons (0x00FE);
+-  written = sendto (circuit->fd, circuit->snd_stream->data,
+-		    stream_get_endp (circuit->snd_stream), 0, 
+-		    (struct sockaddr *) &sa,
+-		    sizeof (struct sockaddr_ll));
+-
+-  return ISIS_OK;
+-}
+-
+-#else
+-
+-int
+-isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
+-{
+-  int bytesread = 0, bytestoread, offset, one = 1;
+-  struct bpf_hdr *bpf_hdr;
+-
+-  assert (circuit->fd > 0);
+-
+-  if (ioctl (circuit->fd, FIONREAD, (caddr_t) & bytestoread) < 0)
+-    {
+-      zlog_warn ("ioctl() FIONREAD failed: %s", safe_strerror (errno));
+-    }
+-
+-  if (bytestoread)
+-    {
+-      bytesread = read (circuit->fd, readbuff, readblen);
+-    }
+-  if (bytesread < 0)
+-    {
+-      zlog_warn ("isis_recv_pdu_bcast(): read() failed: %s",
+-		 safe_strerror (errno));
+-      return ISIS_WARNING;
+-    }
+-
+-  if (bytesread == 0)
+-    return ISIS_WARNING;
+-
+-  bpf_hdr = (struct bpf_hdr *) readbuff;
+-
+-  assert (bpf_hdr->bh_caplen == bpf_hdr->bh_datalen);
+-
+-  offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN;
+-
+-  /* then we lose the BPF, LLC and ethernet headers */
+-  stream_write (circuit->rcv_stream, readbuff + offset, 
+-                bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
+-  stream_set_getp (circuit->rcv_stream, 0);
+-
+-  memcpy (ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETHER_ADDR_LEN,
+-	  ETHER_ADDR_LEN);
+-
+-  if (ioctl (circuit->fd, BIOCFLUSH, &one) < 0)
+-    zlog_warn ("Flushing failed: %s", safe_strerror (errno));
+-
+-  return ISIS_OK;
+-}
+-
+-int
+-isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
+-{
+-  int bytesread;
+-
+-  bytesread = stream_read (circuit->rcv_stream, circuit->fd, 
+-                           circuit->interface->mtu);
+-
+-  if (bytesread < 0)
+-    {
+-      zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", safe_strerror (errno));
+-      return ISIS_WARNING;
+-    }
+-
+-  return ISIS_OK;
+-}
+-
+-int
+-isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
+-{
+-  struct ether_header *eth;
+-  int written;
+-
+-  stream_set_getp (circuit->snd_stream, 0);
+-
+-  /*
+-   * First the eth header
+-   */
+-  eth = (struct ether_header *) sock_buff;
+-  if (level == 1)
+-    memcpy (eth->ether_dhost, ALL_L1_ISS, ETHER_ADDR_LEN);
+-  else
+-    memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN);
+-  memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN);
+-  eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
+-
+-  /*
+-   * Then the LLC
+-   */
+-  sock_buff[ETHER_HDR_LEN] = ISO_SAP;
+-  sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP;
+-  sock_buff[ETHER_HDR_LEN + 2] = 0x03;
+-
+-  /* then we copy the data */
+-  memcpy (sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data,
+-	  stream_get_endp (circuit->snd_stream));
+-
+-  /* now we can send this */
+-  written = write (circuit->fd, sock_buff,
+-		   stream_get_endp (circuit->snd_stream) 
+-		    + LLC_LEN + ETHER_HDR_LEN);
+-
+-  return ISIS_OK;
+-}
+-
+-int
+-isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
+-{
+-  return ISIS_OK;
+-}
+-
+-#endif /* GNU_LINUX */
+diff --git a/isisd/isis_pdu.h b/isisd/isis_pdu.h
+index 29c7621..95c1ee4 100644
+--- isisd/isis_pdu.h
++++ isisd/isis_pdu.h
+@@ -24,6 +24,10 @@
+ #ifndef _ZEBRA_ISIS_PDU_H
+ #define _ZEBRA_ISIS_PDU_H
+ 
++#ifdef __SUNPRO_C
++#pragma pack(1)
++#endif
++
+ /*
+  *                    ISO 9542 - 7.5,7.6
+  *
+@@ -222,6 +226,10 @@ struct isis_partial_seqnum_hdr
+ };
+ #define ISIS_PSNP_HDRLEN 9
+ 
++#ifdef __SUNPRO_C
++#pragma pack()
++#endif
++
+ /*
+  * Function for receiving IS-IS PDUs
+  */
+diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c
+new file mode 100644
+index 0000000..8752dba
+--- /dev/null
++++ isisd/isis_pfpacket.c
+@@ -0,0 +1,373 @@
++/*
++ * IS-IS Rout(e)ing protocol - isis_pfpacket.c
++ *
++ * Copyright (C) 2001,2002    Sampo Saaristo
++ *                            Tampere University of Technology      
++ *                            Institute of Communications Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify it 
++ * under the terms of the GNU General Public Licenseas published by the Free 
++ * Software Foundation; either version 2 of the License, or (at your option) 
++ * any later version.
++ *
++ * This program 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 this program; if not, write to the Free Software Foundation, Inc., 
++ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ */
++
++#include <zebra.h>
++#include <net/ethernet.h>	/* the L2 protocols */
++#include <netpacket/packet.h>
++
++#include "log.h"
++#include "stream.h"
++#include "if.h"
++
++#include "isisd/dict.h"
++#include "isisd/include-netbsd/iso.h"
++#include "isisd/isis_constants.h"
++#include "isisd/isis_common.h"
++#include "isisd/isis_circuit.h"
++#include "isisd/isis_flags.h"
++#include "isisd/isisd.h"
++#include "isisd/isis_constants.h"
++#include "isisd/isis_circuit.h"
++#include "isisd/isis_network.h"
++
++#include "privs.h"
++
++extern struct zebra_privs_t isisd_privs;
++
++/*
++ * Table 9 - Architectural constants for use with ISO 8802 subnetworks
++ * ISO 10589 - 8.4.8
++ */
++
++u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 };
++u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 };
++u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 };
++u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 };
++
++static char discard_buff[8192];
++static char sock_buff[8192];
++
++/*
++ * if level is 0 we are joining p2p multicast
++ * FIXME: and the p2p multicast being ???
++ */
++static int
++isis_multicast_join (int fd, int registerto, int if_num)
++{
++  struct packet_mreq mreq;
++
++  memset (&mreq, 0, sizeof (mreq));
++  mreq.mr_ifindex = if_num;
++  if (registerto)
++    {
++      mreq.mr_type = PACKET_MR_MULTICAST;
++      mreq.mr_alen = ETH_ALEN;
++      if (registerto == 1)
++	memcpy (&mreq.mr_address, ALL_L1_ISS, ETH_ALEN);
++      else if (registerto == 2)
++	memcpy (&mreq.mr_address, ALL_L2_ISS, ETH_ALEN);
++      else if (registerto == 3)
++	memcpy (&mreq.mr_address, ALL_ISS, ETH_ALEN);
++      else
++	memcpy (&mreq.mr_address, ALL_ESS, ETH_ALEN);
++
++    }
++  else
++    {
++      mreq.mr_type = PACKET_MR_ALLMULTI;
++    }
++#ifdef EXTREME_DEBUG
++  zlog_debug ("isis_multicast_join(): fd=%d, reg_to=%d, if_num=%d, "
++	      "address = %02x:%02x:%02x:%02x:%02x:%02x",
++	      fd, registerto, if_num, mreq.mr_address[0], mreq.mr_address[1],
++	      mreq.mr_address[2], mreq.mr_address[3], mreq.mr_address[4],
++	      mreq.mr_address[5]);
++#endif /* EXTREME_DEBUG */
++  if (setsockopt (fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq,
++		  sizeof (struct packet_mreq)))
++    {
++      zlog_warn ("isis_multicast_join(): setsockopt(): %s", safe_strerror (errno));
++      return ISIS_WARNING;
++    }
++
++  return ISIS_OK;
++}
++
++static int
++open_packet_socket (struct isis_circuit *circuit)
++{
++  struct sockaddr_ll s_addr;
++  int fd, retval = ISIS_OK;
++
++  fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL));
++  if (fd < 0)
++    {
++      zlog_warn ("open_packet_socket(): socket() failed %s",
++		 safe_strerror (errno));
++      return ISIS_WARNING;
++    }
++
++  /*
++   * Bind to the physical interface
++   */
++  memset (&s_addr, 0, sizeof (struct sockaddr_ll));
++  s_addr.sll_family = AF_PACKET;
++  s_addr.sll_protocol = htons (ETH_P_ALL);
++  s_addr.sll_ifindex = circuit->interface->ifindex;
++
++  if (bind (fd, (struct sockaddr *) (&s_addr),
++	    sizeof (struct sockaddr_ll)) < 0)
++    {
++      zlog_warn ("open_packet_socket(): bind() failed: %s", safe_strerror (errno));
++      return ISIS_WARNING;
++    }
++
++  circuit->fd = fd;
++
++  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
++    {
++      /*
++       * Join to multicast groups
++       * according to
++       * 8.4.2 - Broadcast subnetwork IIH PDUs
++       * FIXME: is there a case only one will fail??
++       */
++      if (circuit->circuit_is_type & IS_LEVEL_1)
++	{
++	  /* joining ALL_L1_ISS */
++	  retval = isis_multicast_join (circuit->fd, 1,
++					circuit->interface->ifindex);
++	  /* joining ALL_ISS */
++	  retval = isis_multicast_join (circuit->fd, 3,
++					circuit->interface->ifindex);
++	}
++      if (circuit->circuit_is_type & IS_LEVEL_2)
++	/* joining ALL_L2_ISS */
++	retval = isis_multicast_join (circuit->fd, 2,
++				      circuit->interface->ifindex);
++    }
++  else
++    {
++      retval =
++	isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
++    }
++
++  return retval;
++}
++
++/*
++ * Create the socket and set the tx/rx funcs
++ */
++int
++isis_sock_init (struct isis_circuit *circuit)
++{
++  int retval = ISIS_OK;
++
++  if (isisd_privs.change (ZPRIVS_RAISE))
++    zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno));
++
++  retval = open_packet_socket (circuit);
++
++  if (retval != ISIS_OK)
++    {
++      zlog_warn ("%s: could not initialize the socket", __func__);
++      goto end;
++    }
++
++  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
++    {
++      circuit->tx = isis_send_pdu_bcast;
++      circuit->rx = isis_recv_pdu_bcast;
++    }
++  else if (circuit->circ_type == CIRCUIT_T_P2P)
++    {
++      circuit->tx = isis_send_pdu_p2p;
++      circuit->rx = isis_recv_pdu_p2p;
++    }
++  else
++    {
++      zlog_warn ("isis_sock_init(): unknown circuit type");
++      retval = ISIS_WARNING;
++      goto end;
++    }
++
++end:
++  if (isisd_privs.change (ZPRIVS_LOWER))
++    zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno));
++
++  return retval;
++}
++
++static inline int
++llc_check (u_char * llc)
++{
++  if (*llc != ISO_SAP || *(llc + 1) != ISO_SAP || *(llc + 2) != 3)
++    return 0;
++
++  return 1;
++}
++
++int
++isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
++{
++  int bytesread, addr_len;
++  struct sockaddr_ll s_addr;
++  u_char llc[LLC_LEN];
++
++  addr_len = sizeof (s_addr);
++
++  memset (&s_addr, 0, sizeof (struct sockaddr_ll));
++
++  bytesread = recvfrom (circuit->fd, (void *) &llc,
++			LLC_LEN, MSG_PEEK,
++			(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
++
++  if (bytesread < 0)
++    {
++      zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s",
++		 circuit->fd, safe_strerror (errno));
++      zlog_warn ("circuit is %s", circuit->interface->name);
++      zlog_warn ("circuit fd %d", circuit->fd);
++      zlog_warn ("bytesread %d", bytesread);
++      /* get rid of the packet */
++      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
++      return ISIS_WARNING;
++    }
++  /*
++   * Filtering by llc field, discard packets sent by this host (other circuit)
++   */
++  if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING)
++    {
++      /*  Read the packet into discard buff */
++      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
++      if (bytesread < 0)
++	zlog_warn ("isis_recv_pdu_bcast(): read() failed");
++      return ISIS_WARNING;
++    }
++
++  /* on lan we have to read to the static buff first */
++  bytesread = recvfrom (circuit->fd, sock_buff, circuit->interface->mtu, 0,
++			(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
++
++  /* then we lose the LLC */
++  stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN);
++
++  memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
++
++  return ISIS_OK;
++}
++
++int
++isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
++{
++  int bytesread, addr_len;
++  struct sockaddr_ll s_addr;
++
++  memset (&s_addr, 0, sizeof (struct sockaddr_ll));
++  addr_len = sizeof (s_addr);
++
++  /* we can read directly to the stream */
++  bytesread = stream_recvfrom (circuit->rcv_stream, circuit->fd,
++                               circuit->interface->mtu, 0,
++                               (struct sockaddr *) &s_addr, 
++                               (socklen_t *) &addr_len);
++
++  if (s_addr.sll_pkttype == PACKET_OUTGOING)
++    {
++      /*  Read the packet into discard buff */
++      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
++      if (bytesread < 0)
++	zlog_warn ("isis_recv_pdu_p2p(): read() failed");
++      return ISIS_WARNING;
++    }
++
++  /* If we don't have protocol type 0x00FE which is
++   * ISO over GRE we exit with pain :)
++   */
++  if (ntohs (s_addr.sll_protocol) != 0x00FE)
++    {
++      zlog_warn ("isis_recv_pdu_p2p(): protocol mismatch(): %X",
++		 ntohs (s_addr.sll_protocol));
++      return ISIS_WARNING;
++    }
++
++  memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
++
++  return ISIS_OK;
++}
++
++int
++isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
++{
++  /* we need to do the LLC in here because of P2P circuits, which will
++   * not need it
++   */
++  int written = 1;
++  struct sockaddr_ll sa;
++
++  stream_set_getp (circuit->snd_stream, 0);
++  memset (&sa, 0, sizeof (struct sockaddr_ll));
++  sa.sll_family = AF_PACKET;
++  sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
++  sa.sll_ifindex = circuit->interface->ifindex;
++  sa.sll_halen = ETH_ALEN;
++  if (level == 1)
++    memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
++  else
++    memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
++
++  /* on a broadcast circuit */
++  /* first we put the LLC in */
++  sock_buff[0] = 0xFE;
++  sock_buff[1] = 0xFE;
++  sock_buff[2] = 0x03;
++
++  /* then we copy the data */
++  memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data,
++	  stream_get_endp (circuit->snd_stream));
++
++  /* now we can send this */
++  written = sendto (circuit->fd, sock_buff,
++		    stream_get_endp(circuit->snd_stream) + LLC_LEN, 0,
++		    (struct sockaddr *) &sa, sizeof (struct sockaddr_ll));
++
++  return ISIS_OK;
++}
++
++int
++isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
++{
++
++  int written = 1;
++  struct sockaddr_ll sa;
++
++  stream_set_getp (circuit->snd_stream, 0);
++  memset (&sa, 0, sizeof (struct sockaddr_ll));
++  sa.sll_family = AF_PACKET;
++  sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
++  sa.sll_ifindex = circuit->interface->ifindex;
++  sa.sll_halen = ETH_ALEN;
++  if (level == 1)
++    memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
++  else
++    memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
++
++
++  /* lets try correcting the protocol */
++  sa.sll_protocol = htons (0x00FE);
++  written = sendto (circuit->fd, circuit->snd_stream->data,
++		    stream_get_endp (circuit->snd_stream), 0, 
++		    (struct sockaddr *) &sa,
++		    sizeof (struct sockaddr_ll));
++
++  return ISIS_OK;
++}
+diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h
+index 951a254..fc9f35f 100644
+--- isisd/isis_tlv.h
++++ isisd/isis_tlv.h
+@@ -152,6 +152,10 @@ struct lan_neigh
+   u_char LAN_addr[6];
+ };
+ 
++#ifdef __SUNPRO_C
++#pragma pack(1)
++#endif
++
+ /* struct for LSP entry */
+ struct lsp_entry
+ {
+@@ -161,6 +165,10 @@ struct lsp_entry
+   u_int16_t checksum;
+ } __attribute__ ((packed));
+ 
++#ifdef __SUNPRO_C
++#pragma pack()
++#endif
++
+ /* struct for checksum */
+ struct checksum
+ {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/30-ospfd-nssa-asbr.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,27 @@
+diff --git a/ospfd/ChangeLog b/ospfd/ChangeLog
+index 24c3d29..bb0e908 100644
+--- ospfd/ChangeLog
++++ ospfd/ChangeLog
+@@ -1,3 +1,8 @@
++2007-08-06 Paul Jakma <paul.jakma@sun.com>
++
++	* ospf_lsa.c: (router_lsa_flags) Bug #331, NSSA regression caused
++	  caused ASBRs to not advertise E-bit into NSSA areas.
++
+ 2007-05-09 Milan Kocian <milon@wq.cz>
+ 
+ 	* ospf_vty.c: Fix commands: 'ip ospf authentication A.B.C.D',
+diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
+index b9a70a6..243928f 100644
+--- ospfd/ospf_lsa.c
++++ ospfd/ospf_lsa.c
+@@ -437,8 +437,7 @@ router_lsa_flags (struct ospf_area *area)
+ 	SET_FLAG (flags, ROUTER_LSA_SHORTCUT);
+ 
+   /* ASBR can't exit in stub area. */
+-  if (area->external_routing == OSPF_AREA_STUB
+-      || area->external_routing == OSPF_AREA_NSSA)
++  if (area->external_routing == OSPF_AREA_STUB)
+     UNSET_FLAG (flags, ROUTER_LSA_EXTERNAL);
+   /* If ASBR set External flag */
+   else if (IS_OSPF_ASBR (area->ospf))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/35-ospfd-spf-sort.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,71 @@
+commit 7591d8b862439dfae8b4b16d148ce567b6ff8cb7
+Author: Paul Jakma <paul.jakma@sun.com>
+Date:   Mon Aug 6 18:52:45 2007 +0000
+
+    [ospfd] Fix bad SPF calculation on some topologies - incorrect sorting
+    
+    2007-08-07 Atis Elsts <atis@mikrotik.com>
+    
+    	* ospf_spf.c: (ospf_spf_next) Sort heap in correct direction
+    	  after vertex cost is changed, thus fixing incorrect SPF
+    	  calculation on certain topologies.
+    	* lib/pqueue.{c,h}: Export trickle_up
+
+diff --git a/lib/pqueue.c b/lib/pqueue.c
+index a974a49..12a779f 100644
+--- lib/pqueue.c
++++ lib/pqueue.c
+@@ -42,7 +42,7 @@ Boston, MA 02111-1307, USA.  */
+ #define RIGHT_OF(x) (2 * x + 2)
+ #define HAVE_CHILD(x,q) (x < (q)->size / 2)
+ 
+-static void
++void
+ trickle_up (int index, struct pqueue *queue)
+ {
+   void *tmp;
+diff --git a/lib/pqueue.h b/lib/pqueue.h
+index 1f3201b..be37f98 100644
+--- lib/pqueue.h
++++ lib/pqueue.h
+@@ -40,5 +40,6 @@ extern void pqueue_enqueue (void *data, struct pqueue *queue);
+ extern void *pqueue_dequeue (struct pqueue *queue);
+ 
+ extern void trickle_down (int index, struct pqueue *queue);
++extern void trickle_up (int index, struct pqueue *queue);
+ 
+ #endif /* _ZEBRA_PQUEUE_H */
+diff --git a/ospfd/ChangeLog b/ospfd/ChangeLog
+index bb0e908..422208e 100644
+--- ospfd/ChangeLog
++++ ospfd/ChangeLog
+@@ -1,3 +1,9 @@
++2007-08-07 Atis Elsts <atis@mikrotik.com>
++
++	* ospf_spf.c: (ospf_spf_next) Sort heap in correct direction
++	  after vertex cost is changed, thus fixing incorrect SPF
++	  calculation on certain topologies.
++
+ 2007-08-06 Paul Jakma <paul.jakma@sun.com>
+ 
+ 	* ospf_lsa.c: (router_lsa_flags) Bug #331, NSSA regression caused
+diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
+index 51e3383..41288f1 100644
+--- ospfd/ospf_spf.c
++++ ospfd/ospf_spf.c
+@@ -896,9 +896,12 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
+                * will flush the old parents
+                */
+               if (ospf_nexthop_calculation (area, v, w, l, distance))
+-                /* Decrease the key of the node in the heap,
+-                 * re-sort the heap. */
+-                trickle_down (w_lsa->stat, candidate);
++                /* Decrease the key of the node in the heap.
++                 * trickle-sort it up towards root, just in case this
++                 * node should now be the new root due the cost change. 
++                 * (pqueu_{de,en}queue 
++                 */
++                trickle_up (w_lsa->stat, candidate);
+             }
+         } /* end W is already on the candidate list */
+     } /* end loop over the links in V's LSA */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/40-bgp-capab-cleanup.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,1298 @@
+commit 6d58272b4cf96f0daa846210dd2104877900f921
+Author: Paul Jakma <paul.jakma@sun.com>
+Date:   Mon Aug 6 15:21:45 2007 +0000
+
+    [bgpd] cleanup, compact and consolidate capability parsing code
+    
+    2007-07-26 Paul Jakma <paul.jakma@sun.com>
+    
+    	* (general) Clean up and compact capability parsing slightly.
+    	  Consolidate validation of length and logging of generic TLV, and
+    	  memcpy of capability data, thus removing such from cap specifc
+    	  code (not always present or correct).
+    	* bgp_open.h: Add structures for the generic capability TLV header
+    	  and for the data formats of the various specific capabilities we
+    	  support.  Hence remove the badly named, or else misdefined, struct
+    	  capability.
+    	* bgp_open.c: (bgp_capability_vty_out) Use struct capability_mp_data.
+    	  Do the length checks *before* memcpy()'ing based on that length
+    	  (stored capability - should have been validated anyway on input,
+    	  but..).
+    	  (bgp_afi_safi_valid_indices) new function to validate (afi,safi)
+    	  which is about to be used as index into arrays, consolidates
+    	  several instances of same, at least one of which appeared to be
+    	  incomplete..
+    	  (bgp_capability_mp) Much condensed.
+    	  (bgp_capability_orf_entry) New, process one ORF entry
+    	  (bgp_capability_orf) Condensed. Fixed to process all ORF entries.
+    	  (bgp_capability_restart) Condensed, and fixed to use a
+    	  cap-specific type, rather than abusing capability_mp.
+    	  (struct message capcode_str) added to aid generic logging.
+    	  (size_t cap_minsizes[]) added to aid generic validation of
+    	  capability length field.
+    	  (bgp_capability_parse) Generic logging and validation of TLV
+    	  consolidated here. Code compacted as much as possible.
+    	* bgp_packet.c: (bgp_open_receive) Capability parsers now use
+    	  streams, so no more need here to manually fudge the input stream
+    	  getp.
+    	  (bgp_capability_msg_parse) use struct capability_mp_data. Validate
+    	  lengths /before/ memcpy. Use bgp_afi_safi_valid_indices.
+    	  (bgp_capability_receive) Exported for use by test harness.
+    	* bgp_vty.c: (bgp_show_summary) fix conversion warning
+    	  (bgp_show_peer) ditto
+    	* bgp_debug.h: Fix storage 'extern' after type 'const'.
+            * lib/log.c: (mes_lookup) warning about code not being in
+              same-number array slot should be debug, not warning. E.g. BGP
+              has several discontigious number spaces, allocating from
+              different parts of a space is not uncommon (e.g. IANA
+              assigned versus vendor-assigned code points in some number
+              space).
+
+--- bgpd/bgp_debug.h
++++ bgpd/bgp_debug.h
+@@ -110,7 +110,7 @@ extern unsigned long term_bgp_debug_zebra;
+ #define BGP_DEBUG(a, b)		(term_bgp_debug_ ## a & BGP_DEBUG_ ## b)
+ #define CONF_BGP_DEBUG(a, b)    (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b)
+ 
+-const extern char *bgp_type_str[];
++extern const char *bgp_type_str[];
+ 
+ extern int bgp_dump_attr (struct peer *, struct attr *, char *, size_t);
+ extern void bgp_notify_print (struct peer *, struct bgp_notify *, const char *);
+diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
+index e44bd2a..d4f7cdf 100644
+--- bgpd/bgp_open.c
++++ bgpd/bgp_open.c
+@@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ #include "thread.h"
+ #include "log.h"
+ #include "command.h"
++#include "memory.h"
+ 
+ #include "bgpd/bgpd.h"
+ #include "bgpd/bgp_attr.h"
+@@ -50,25 +51,28 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)
+ {
+   char *pnt;
+   char *end;
+-  struct capability cap;
++  struct capability_mp_data mpc;
++  struct capability_header *hdr;
+ 
+   pnt = peer->notify.data;
+   end = pnt + peer->notify.length;
+-
++  
+   while (pnt < end)
+     {
+-      memcpy(&cap, pnt, sizeof(struct capability));
+-
+-      if (pnt + 2 > end)
++      if (pnt + sizeof (struct capability_mp_data) + 2 > end)
+ 	return;
+-      if (pnt + (cap.length + 2) > end)
++      
++      hdr = (struct capability_header *)pnt;
++      if (pnt + hdr->length + 2 > end)
+ 	return;
+ 
+-      if (cap.code == CAPABILITY_CODE_MP)
++      memcpy (&mpc, pnt + 2, sizeof(struct capability_mp_data));
++
++      if (hdr->code == CAPABILITY_CODE_MP)
+ 	{
+ 	  vty_out (vty, "  Capability error for: Multi protocol ");
+ 
+-	  switch (ntohs (cap.mpc.afi))
++	  switch (ntohs (mpc.afi))
+ 	    {
+ 	    case AFI_IP:
+ 	      vty_out (vty, "AFI IPv4, ");
+@@ -77,10 +81,10 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)
+ 	      vty_out (vty, "AFI IPv6, ");
+ 	      break;
+ 	    default:
+-	      vty_out (vty, "AFI Unknown %d, ", ntohs (cap.mpc.afi));
++	      vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi));
+ 	      break;
+ 	    }
+-	  switch (cap.mpc.safi)
++	  switch (mpc.safi)
+ 	    {
+ 	    case SAFI_UNICAST:
+ 	      vty_out (vty, "SAFI Unicast");
+@@ -95,88 +99,87 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)
+ 	      vty_out (vty, "SAFI MPLS-VPN");
+ 	      break;
+ 	    default:
+-	      vty_out (vty, "SAFI Unknown %d ", cap.mpc.safi);
++	      vty_out (vty, "SAFI Unknown %d ", mpc.safi);
+ 	      break;
+ 	    }
+ 	  vty_out (vty, "%s", VTY_NEWLINE);
+ 	}
+-      else if (cap.code >= 128)
++      else if (hdr->code >= 128)
+ 	vty_out (vty, "  Capability error: vendor specific capability code %d",
+-		 cap.code);
++		 hdr->code);
+       else
+ 	vty_out (vty, "  Capability error: unknown capability code %d", 
+-		 cap.code);
++		 hdr->code);
+ 
+-      pnt += cap.length + 2;
++      pnt += hdr->length + 2;
+     }
+ }
+ 
+-/* Set negotiated capability value. */
+-static int
+-bgp_capability_mp (struct peer *peer, struct capability *cap)
++static void 
++bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc)
+ {
+-  if (ntohs (cap->mpc.afi) == AFI_IP)
+-    {
+-      if (cap->mpc.safi == SAFI_UNICAST)
+-	{
+-	  peer->afc_recv[AFI_IP][SAFI_UNICAST] = 1;
+-
+-	  if (peer->afc[AFI_IP][SAFI_UNICAST])
+-	    peer->afc_nego[AFI_IP][SAFI_UNICAST] = 1;
+-	  else
+-	    return -1;
+-	}
+-      else if (cap->mpc.safi == SAFI_MULTICAST) 
+-	{
+-	  peer->afc_recv[AFI_IP][SAFI_MULTICAST] = 1;
+-
+-	  if (peer->afc[AFI_IP][SAFI_MULTICAST])
+-	    peer->afc_nego[AFI_IP][SAFI_MULTICAST] = 1;
+-	  else
+-	    return -1;
+-	}
+-      else if (cap->mpc.safi == BGP_SAFI_VPNV4)
+-	{
+-	  peer->afc_recv[AFI_IP][SAFI_MPLS_VPN] = 1;
++  mpc->afi = stream_getw (s);
++  mpc->reserved = stream_getc (s);
++  mpc->safi = stream_getc (s);
++}
+ 
+-	  if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
+-	    peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] = 1;
+-	  else
+-	    return -1;
+-	}
+-      else
+-	return -1;
+-    }
+-#ifdef HAVE_IPV6
+-  else if (ntohs (cap->mpc.afi) == AFI_IP6)
++int
++bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
++{
++  /* VPNvX are AFI specific */
++  if ((afi == AFI_IP6 && *safi == BGP_SAFI_VPNV4)
++      || (afi == AFI_IP && *safi == BGP_SAFI_VPNV6))
+     {
+-      if (cap->mpc.safi == SAFI_UNICAST)
+-	{
+-	  peer->afc_recv[AFI_IP6][SAFI_UNICAST] = 1;
+-
+-	  if (peer->afc[AFI_IP6][SAFI_UNICAST])
+-	    peer->afc_nego[AFI_IP6][SAFI_UNICAST] = 1;
+-	  else
+-	    return -1;
+-	}
+-      else if (cap->mpc.safi == SAFI_MULTICAST)
+-	{
+-	  peer->afc_recv[AFI_IP6][SAFI_MULTICAST] = 1;
+-
+-	  if (peer->afc[AFI_IP6][SAFI_MULTICAST])
+-	    peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = 1;
+-	  else
+-	    return -1;
+-	}
+-      else
+-	return -1;
++      zlog_warn ("Invalid afi/safi combination (%u/%u)", afi, *safi);
++      return 0;
+     }
+-#endif /* HAVE_IPV6 */
+-  else
++  
++  switch (afi)
+     {
+-      /* Unknown Address Family. */
+-      return -1;
++      case AFI_IP:
++#ifdef HAVE_IPV6
++      case AFI_IP6:
++#endif
++        switch (*safi)
++          {
++            /* BGP VPNvX SAFI isn't contigious with others, remap */
++            case BGP_SAFI_VPNV4:
++            case BGP_SAFI_VPNV6:
++              *safi = SAFI_MPLS_VPN;
++            case SAFI_UNICAST:
++            case SAFI_MULTICAST:
++            case SAFI_MPLS_VPN:
++              return 1;
++          }
+     }
++  zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi);
++  
++  return 0;
++}
++
++/* Set negotiated capability value. */
++static int
++bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
++{
++  struct capability_mp_data mpc;
++  struct stream *s = BGP_INPUT (peer);
++  
++  bgp_capability_mp_data (s, &mpc);
++  
++  if (BGP_DEBUG (normal, NORMAL))
++    zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
++               peer->host, mpc.afi, mpc.safi);
++  
++  if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi))
++    return -1;
++   
++  /* Now safi remapped, and afi/safi are valid array indices */
++  peer->afc_recv[mpc.afi][mpc.safi] = 1;
++  
++  if (peer->afc[mpc.afi][mpc.safi])
++    peer->afc_nego[mpc.safi][mpc.safi] = 1;
++  else 
++    return -1;
+ 
+   return 0;
+ }
+@@ -190,98 +193,133 @@ bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
+ 	       peer->host, afi, safi, type, mode);
+ }
+ 
++static struct message orf_type_str[] =
++{
++  { ORF_TYPE_PREFIX,		"Prefixlist"		},
++  { ORF_TYPE_PREFIX_OLD,	"Prefixlist (old)"	},
++};
++static int orf_type_str_max = sizeof(orf_type_str)/sizeof(orf_type_str[0]);
++
++static struct message orf_mode_str[] =
++{
++  { ORF_MODE_RECEIVE,	"Receive"	},
++  { ORF_MODE_SEND,	"Send"		},
++  { ORF_MODE_BOTH,	"Both"		},
++};
++static int orf_mode_str_max = sizeof(orf_mode_str)/sizeof(orf_mode_str[0]);
++
+ static int
+-bgp_capability_orf (struct peer *peer, struct capability *cap,
+-		    u_char *pnt)
++bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
+ {
+-  afi_t afi = ntohs(cap->mpc.afi);
+-  safi_t safi = cap->mpc.safi;
+-  u_char number_of_orfs;
++  struct stream *s = BGP_INPUT (peer);
++  struct capability_orf_entry entry;
++  afi_t afi;
++  safi_t safi;
+   u_char type;
+   u_char mode;
+   u_int16_t sm_cap = 0; /* capability send-mode receive */
+   u_int16_t rm_cap = 0; /* capability receive-mode receive */ 
+   int i;
+ 
+-  /* Check length. */
+-  if (cap->length < 7)
+-    {
+-      zlog_info ("%s ORF Capability length error %d",
+-		 peer->host, cap->length);
+-		 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+-      return -1;
+-    }
+-
++  /* ORF Entry header */
++  bgp_capability_mp_data (s, &entry.mpc);
++  entry.num = stream_getc (s);
++  afi = entry.mpc.afi;
++  safi = entry.mpc.safi;
++  
+   if (BGP_DEBUG (normal, NORMAL))
+-    zlog_debug ("%s OPEN has ORF CAP(%s) for afi/safi: %u/%u",
+-	       peer->host, (cap->code == CAPABILITY_CODE_ORF ?
+-                       "new" : "old"), afi, safi);
++    zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u",
++	        peer->host, entry.mpc.afi, entry.mpc.safi);
+ 
+   /* Check AFI and SAFI. */
+-  if ((afi != AFI_IP && afi != AFI_IP6)
+-      || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST
+-	  && safi != BGP_SAFI_VPNV4))
++  if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi))
++    {
++      zlog_info ("%s Addr-family %d/%d not supported."
++                 " Ignoring the ORF capability",
++                 peer->host, entry.mpc.afi, entry.mpc.safi);
++      return 0;
++    }
++  
++  /* validate number field */
++  if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length)
+     {
+-      zlog_info ("%s Addr-family %d/%d not supported. Ignoring the ORF capability",
+-                 peer->host, afi, safi);
++      zlog_info ("%s ORF Capability entry length error,"
++                 " Cap length %u, num %u",
++                 peer->host, hdr->length, entry.num);
++      bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+       return -1;
+     }
+ 
+-  number_of_orfs = *pnt++;
+-
+-  for (i = 0 ; i < number_of_orfs ; i++)
++  for (i = 0 ; i < entry.num ; i++)
+     {
+-      type = *pnt++;
+-      mode = *pnt++;
+-
++      type = stream_getc(s);
++      mode = stream_getc(s);
++      
+       /* ORF Mode error check */
+-      if (mode != ORF_MODE_BOTH && mode != ORF_MODE_SEND
+-	  && mode != ORF_MODE_RECEIVE)
+-	{
+-	  bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+-	  continue;
++      switch (mode)
++        {
++          case ORF_MODE_BOTH:
++          case ORF_MODE_SEND:
++          case ORF_MODE_RECEIVE:
++            break;
++          default:
++	    bgp_capability_orf_not_support (peer, afi, safi, type, mode);
++	    continue;
+ 	}
++      /* ORF Type and afi/safi error checks */
++      /* capcode versus type */
++      switch (hdr->code)
++        {
++          case CAPABILITY_CODE_ORF:
++            switch (type)
++              {
++                case ORF_TYPE_PREFIX:
++                  break;
++                default:
++                  bgp_capability_orf_not_support (peer, afi, safi, type, mode);
++                  continue;
++              }
++            break;
++          case CAPABILITY_CODE_ORF_OLD:
++            switch (type)
++              {
++                case ORF_TYPE_PREFIX_OLD:
++                  break;
++                default:
++                  bgp_capability_orf_not_support (peer, afi, safi, type, mode);
++                  continue;
++              }
++            break;
++          default:
++            bgp_capability_orf_not_support (peer, afi, safi, type, mode);
++            continue;
++        }
++                
++      /* AFI vs SAFI */
++      if (!((afi == AFI_IP && safi == SAFI_UNICAST)
++            || (afi == AFI_IP && safi == SAFI_MULTICAST)
++            || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
++        {
++          bgp_capability_orf_not_support (peer, afi, safi, type, mode);
++          continue;
++        }
++      
++      if (BGP_DEBUG (normal, NORMAL))
++        zlog_debug ("%s OPEN has %s ORF capability"
++                    " as %s for afi/safi: %d/%d",
++                    peer->host, LOOKUP (orf_type_str, type),
++                    LOOKUP (orf_mode_str, mode),
++                    entry.mpc.afi, safi);
+ 
+-      /* ORF Type and afi/safi error check */
+-      if (cap->code == CAPABILITY_CODE_ORF)
++      if (hdr->code == CAPABILITY_CODE_ORF)
+ 	{
+-	  if (type == ORF_TYPE_PREFIX &&
+-	      ((afi == AFI_IP && safi == SAFI_UNICAST)
+-		|| (afi == AFI_IP && safi == SAFI_MULTICAST)
+-		|| (afi == AFI_IP6 && safi == SAFI_UNICAST)))
+-	    {
+-	      sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
+-	      rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
+-	      if (BGP_DEBUG (normal, NORMAL))
+-		zlog_debug ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d",
+-			   peer->host, ORF_TYPE_PREFIX, (mode == ORF_MODE_SEND ? "SEND" :
+-			   mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi);
+-	    }
+-	  else
+-	    {
+-	      bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+-	      continue;
+-	    }
++          sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
++          rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
+ 	}
+-      else if (cap->code == CAPABILITY_CODE_ORF_OLD)
++      else if (hdr->code == CAPABILITY_CODE_ORF_OLD)
+ 	{
+-	  if (type == ORF_TYPE_PREFIX_OLD &&
+-	      ((afi == AFI_IP && safi == SAFI_UNICAST)
+-		|| (afi == AFI_IP && safi == SAFI_MULTICAST)
+-		|| (afi == AFI_IP6 && safi == SAFI_UNICAST)))
+-	    {
+-	      sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
+-	      rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
+-	      if (BGP_DEBUG (normal, NORMAL))
+-		zlog_debug ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d",
+-			   peer->host, ORF_TYPE_PREFIX_OLD, (mode == ORF_MODE_SEND ? "SEND" :
+-			   mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi);
+-	    }
+-	  else
+-	    {
+-	      bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+-	      continue;
+-	    }
++          sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
++          rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
+ 	}
+       else
+ 	{
+@@ -306,206 +344,258 @@ bgp_capability_orf (struct peer *peer, struct capability *cap,
+   return 0;
+ }
+ 
+-/* Parse given capability. */
+ static int
+-bgp_capability_parse (struct peer *peer, u_char *pnt, u_char length,
+-		      u_char **error)
++bgp_capability_orf (struct peer *peer, struct capability_header *hdr)
+ {
+-  int ret;
+-  u_char *end;
+-  struct capability cap;
+-
+-  end = pnt + length;
+-
+-  while (pnt < end)
++  struct stream *s = BGP_INPUT (peer);
++  size_t end = stream_get_getp (s) + hdr->length;
++  
++  assert (stream_get_getp(s) + sizeof(struct capability_orf_entry) <= end);
++  
++  /* We must have at least one ORF entry, as the caller has already done
++   * minimum length validation for the capability code - for ORF there must
++   * at least one ORF entry (header and unknown number of pairs of bytes).
++   */
++  do
+     {
+-      afi_t afi;
+-      safi_t safi;
++      if (bgp_capability_orf_entry (peer, hdr) == -1)
++        return -1;
++    } 
++  while (stream_get_getp(s) + sizeof(struct capability_orf_entry) < end);
++  
++  return 0;
++}
+ 
+-      /* Fetch structure to the byte stream. */
+-      memcpy (&cap, pnt, sizeof (struct capability));
++static int
++bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
++{
++  struct stream *s = BGP_INPUT (peer);
++  u_int16_t restart_flag_time;
++  int restart_bit = 0;
++  size_t end = stream_get_getp (s) + caphdr->length;
++
++  SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV);
++  restart_flag_time = stream_getw(s);
++  if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
++    restart_bit = 1;
++  UNSET_FLAG (restart_flag_time, 0xF000);
++  peer->v_gr_restart = restart_flag_time;
+ 
+-      afi = ntohs(cap.mpc.afi);
+-      safi = cap.mpc.safi;
++  if (BGP_DEBUG (normal, NORMAL))
++    {
++      zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
++      zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
++                  peer->host, restart_bit ? " " : " not ",
++                  peer->v_gr_restart);
++    }
+ 
+-      if (BGP_DEBUG (normal, NORMAL))
+-	zlog_debug ("%s OPEN has CAPABILITY code: %d, length %d",
+-		   peer->host, cap.code, cap.length);
++  while (stream_get_getp (s) + 4 < end)
++    {
++      afi_t afi = stream_getw (s);
++      safi_t safi = stream_getc (s);
++      u_char flag = stream_getc (s);
++      
++      if (!bgp_afi_safi_valid_indices (afi, &safi))
++        {
++          if (BGP_DEBUG (normal, NORMAL))
++            zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
++                        " Ignore the Graceful Restart capability",
++                        peer->host, afi, safi);
++        }
++      else if (!peer->afc[afi][safi])
++        {
++          if (BGP_DEBUG (normal, NORMAL))
++            zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
++                        " Ignore the Graceful Restart capability",
++                        peer->host, afi, safi);
++        }
++      else
++        {
++          if (BGP_DEBUG (normal, NORMAL))
++            zlog_debug ("%s Address family %s is%spreserved", peer->host,
++                        afi_safi_print (afi, safi),
++                        CHECK_FLAG (peer->af_cap[afi][safi],
++                                    PEER_CAP_RESTART_AF_PRESERVE_RCV)
++                        ? " " : " not ");
++
++          SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
++          if (CHECK_FLAG (flag, RESTART_F_BIT))
++            SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
++          
++        }
++    }
++  return 0;
++}
+ 
++static struct message capcode_str[] =
++{
++  { 0,	""},
++  { CAPABILITY_CODE_MP,			"MultiProtocol Extensions"	},
++  { CAPABILITY_CODE_REFRESH,		"Route Refresh"			},
++  { CAPABILITY_CODE_ORF,		"Cooperative Route Filtering" 	},
++  { CAPABILITY_CODE_RESTART,		"Graceful Restart"		},
++  { CAPABILITY_CODE_AS4,		"4-octet AS number"		},
++  { CAPABILITY_CODE_DYNAMIC,		"Dynamic"			},
++  { CAPABILITY_CODE_REFRESH_OLD,	"Route Refresh (Old)"		},
++  { CAPABILITY_CODE_ORF_OLD,		"ORF (Old)"			},
++};
++int capcode_str_max = sizeof(capcode_str)/sizeof(capcode_str[0]);
++
++/* Minimum sizes for length field of each cap (so not inc. the header) */
++static size_t cap_minsizes[] = 
++{
++  [CAPABILITY_CODE_MP]		= sizeof (struct capability_mp_data),
++  [CAPABILITY_CODE_REFRESH]	= CAPABILITY_CODE_REFRESH_LEN,
++  [CAPABILITY_CODE_ORF]		= sizeof (struct capability_orf_entry),
++  [CAPABILITY_CODE_RESTART]	= sizeof (struct capability_gr) - 2,
++  [CAPABILITY_CODE_AS4]		= CAPABILITY_CODE_AS4_LEN,
++  [CAPABILITY_CODE_DYNAMIC]	= CAPABILITY_CODE_DYNAMIC_LEN,
++  [CAPABILITY_CODE_REFRESH_OLD]	= CAPABILITY_CODE_REFRESH_LEN,
++  [CAPABILITY_CODE_ORF_OLD]	= sizeof (struct capability_orf_entry),
++};
++
++/* Parse given capability.
++ * XXX: This is reading into a stream, but not using stream API
++ */
++static int
++bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
++{
++  int ret;
++  struct stream *s = BGP_INPUT (peer);
++  size_t end = stream_get_getp (s) + length;
++  
++  assert (STREAM_READABLE (s) >= length);
++  
++  while (stream_get_getp (s) < end)
++    {
++      size_t start;
++      u_char *sp = stream_pnt (s);
++      struct capability_header caphdr;
++      
+       /* We need at least capability code and capability length. */
+-      if (pnt + 2 > end)
++      if (stream_get_getp(s) + 2 > end)
+ 	{
+-	  zlog_info ("%s Capability length error", peer->host);
++	  zlog_info ("%s Capability length error (< header)", peer->host);
+ 	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ 	  return -1;
+ 	}
+-
+-      /* Capability length check. */
+-      if (pnt + (cap.length + 2) > end)
++      
++      caphdr.code = stream_getc (s);
++      caphdr.length = stream_getc (s);
++      start = stream_get_getp (s);
++      
++      /* Capability length check sanity check. */
++      if (start + caphdr.length > end)
+ 	{
+-	  zlog_info ("%s Capability length error", peer->host);
++	  zlog_info ("%s Capability length error (< length)", peer->host);
+ 	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ 	  return -1;
+ 	}
+-
+-      /* We know MP Capability Code. */
+-      if (cap.code == CAPABILITY_CODE_MP)
+-	{
+-	  if (BGP_DEBUG (normal, NORMAL))
+-	    zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
+-		       peer->host, afi, safi);
+-
+-	  /* Ignore capability when override-capability is set. */
+-	  if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+-	    {
+-	      /* Set negotiated value. */
+-	      ret = bgp_capability_mp (peer, &cap);
+-
+-	      /* Unsupported Capability. */
+-	      if (ret < 0)
+-		{
+-		  /* Store return data. */
+-		  memcpy (*error, &cap, cap.length + 2);
+-		  *error += cap.length + 2;
+-		}
+-	    }
+-	}
+-      else if (cap.code == CAPABILITY_CODE_REFRESH
+-	       || cap.code == CAPABILITY_CODE_REFRESH_OLD)
+-	{
+-	  /* Check length. */
+-	  if (cap.length != CAPABILITY_CODE_REFRESH_LEN)
+-	    {
+-	      zlog_info ("%s Route Refresh Capability length error %d",
+-			 peer->host, cap.length);
+-	      bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+-	      return -1;
+-	    }
+-
+-	  if (BGP_DEBUG (normal, NORMAL))
+-	    zlog_debug ("%s OPEN has ROUTE-REFRESH capability(%s) for all address-families",
+-		       peer->host,
+-		       cap.code == CAPABILITY_CODE_REFRESH_OLD ? "old" : "new");
+-
+-	  /* BGP refresh capability */
+-	  if (cap.code == CAPABILITY_CODE_REFRESH_OLD)
+-	    SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
+-	  else
+-	    SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
+-	}
+-      else if (cap.code == CAPABILITY_CODE_ORF
+-	       || cap.code == CAPABILITY_CODE_ORF_OLD)
+-	bgp_capability_orf (peer, &cap, pnt + sizeof (struct capability));
+-      else if (cap.code == CAPABILITY_CODE_RESTART)
+-       {
+-         struct graceful_restart_af graf;
+-         u_int16_t restart_flag_time;
+-         int restart_bit = 0;
+-         u_char *restart_pnt;
+-         u_char *restart_end;
+-
+-         /* Check length. */
+-         if (cap.length < CAPABILITY_CODE_RESTART_LEN)
+-           {
+-             zlog_info ("%s Graceful Restart Capability length error %d",
+-                        peer->host, cap.length);
+-             bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+-             return -1;
+-           }
+-
+-         SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV);
+-         restart_flag_time = ntohs(cap.mpc.afi);
+-         if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
+-           restart_bit = 1;
+-         UNSET_FLAG (restart_flag_time, 0xF000);
+-	 peer->v_gr_restart = restart_flag_time;
+-
+-         if (BGP_DEBUG (normal, NORMAL))
+-           {
+-             zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
+-             zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
+-                        peer->host, restart_bit ? " " : " not ",
+-			peer->v_gr_restart);
+-           }
+-
+-         restart_pnt = pnt + 4;
+-         restart_end = pnt + cap.length + 2;
+-
+-         while (restart_pnt < restart_end)
+-           {
+-             memcpy (&graf, restart_pnt, sizeof (struct graceful_restart_af));
+-
+-             afi = ntohs(graf.afi);
+-             safi = graf.safi;
+-
+-             if (CHECK_FLAG (graf.flag, RESTART_F_BIT))
+-		SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
+-
+-             if (strcmp (afi_safi_print (afi, safi), "Unknown") == 0)
+-               {
+-                  if (BGP_DEBUG (normal, NORMAL))
+-                    zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported. I gnore the Graceful Restart capability",
+-                               peer->host, afi, safi);
+-               }
+-             else if (! peer->afc[afi][safi])
+-               {
+-                  if (BGP_DEBUG (normal, NORMAL))
+-                     zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled. Ignore the Graceful Restart capability",
+-                                peer->host, afi, safi);
+-               }
+-             else
+-               {
+-                 if (BGP_DEBUG (normal, NORMAL))
+-                   zlog_debug ("%s Address family %s is%spreserved", peer->host,
+-			       afi_safi_print (afi, safi),
+-			       CHECK_FLAG (peer->af_cap[afi][safi],
+-			       PEER_CAP_RESTART_AF_PRESERVE_RCV)
+-			       ? " " : " not ");
+-
+-                   SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
+-               }
+-             restart_pnt += 4;
+-           }
+-       }
+-      else if (cap.code == CAPABILITY_CODE_DYNAMIC)
+-	{
+-	  /* Check length. */
+-	  if (cap.length != CAPABILITY_CODE_DYNAMIC_LEN)
+-	    {
+-	      zlog_info ("%s Dynamic Capability length error %d",
+-			 peer->host, cap.length);
+-	      bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+-	      return -1;
+-	    }
+-
+-	  if (BGP_DEBUG (normal, NORMAL))
+-	    zlog_debug ("%s OPEN has DYNAMIC capability", peer->host);
+-
+-	  SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
+-	}
+- 
+-      else if (cap.code > 128)
+-	{
+-	  /* We don't send Notification for unknown vendor specific
+-	     capabilities.  It seems reasonable for now...  */
+-	  zlog_warn ("%s Vendor specific capability %d",
+-		     peer->host, cap.code);
+-	}
+-      else
+-	{
+-	  zlog_warn ("%s unrecognized capability code: %d - ignored",
+-		     peer->host, cap.code);
+-	  memcpy (*error, &cap, cap.length + 2);
+-	  *error += cap.length + 2;
+-	}
+-
+-      pnt += cap.length + 2;
++      
++      if (BGP_DEBUG (normal, NORMAL))
++	zlog_debug ("%s OPEN has %s capability (%u), length %u",
++		   peer->host,
++		   LOOKUP (capcode_str, caphdr.code),
++		   caphdr.code, caphdr.length);
++      
++      /* Length sanity check, type-specific, for known capabilities */
++      switch (caphdr.code)
++        {
++          case CAPABILITY_CODE_MP:
++          case CAPABILITY_CODE_REFRESH:
++          case CAPABILITY_CODE_REFRESH_OLD:
++          case CAPABILITY_CODE_ORF:
++          case CAPABILITY_CODE_ORF_OLD:
++          case CAPABILITY_CODE_RESTART:
++          case CAPABILITY_CODE_DYNAMIC:
++              /* Check length. */
++              if (caphdr.length < cap_minsizes[caphdr.code])
++                {
++                  zlog_info ("%s %s Capability length error: got %u,"
++                             " expected at least %u",
++                             peer->host, 
++                             LOOKUP (capcode_str, caphdr.code),
++                             caphdr.length, cap_minsizes[caphdr.code]);
++                  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
++                  return -1;
++                }
++          /* we deliberately ignore unknown codes, see below */
++          default:
++            break;
++        }
++      
++      switch (caphdr.code)
++        {
++          case CAPABILITY_CODE_MP:
++            {
++              /* Ignore capability when override-capability is set. */
++              if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
++                {
++                  /* Set negotiated value. */
++                  ret = bgp_capability_mp (peer, &caphdr);
++
++                  /* Unsupported Capability. */
++                  if (ret < 0)
++                    {
++                      /* Store return data. */
++                      memcpy (*error, sp, caphdr.length + 2);
++                      *error += caphdr.length + 2;
++                    }
++                }
++            }
++            break;
++          case CAPABILITY_CODE_REFRESH:
++          case CAPABILITY_CODE_REFRESH_OLD:
++            {
++              /* BGP refresh capability */
++              if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
++                SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
++              else
++                SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
++            }
++            break;
++          case CAPABILITY_CODE_ORF:
++          case CAPABILITY_CODE_ORF_OLD:
++            if (bgp_capability_orf (peer, &caphdr))
++              return -1;
++            break;
++          case CAPABILITY_CODE_RESTART:
++            if (bgp_capability_restart (peer, &caphdr))
++              return -1;
++            break;
++          case CAPABILITY_CODE_DYNAMIC:
++            SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
++            break;
++          default:
++            if (caphdr.code > 128)
++              {
++                /* We don't send Notification for unknown vendor specific
++                   capabilities.  It seems reasonable for now...  */
++                zlog_warn ("%s Vendor specific capability %d",
++                           peer->host, caphdr.code);
++              }
++            else
++              {
++                zlog_warn ("%s unrecognized capability code: %d - ignored",
++                           peer->host, caphdr.code);
++                memcpy (*error, sp, caphdr.length + 2);
++                *error += caphdr.length + 2;
++              }
++          }
++      if (stream_get_getp(s) != (start + caphdr.length))
++        {
++          if (stream_get_getp(s) > (start + caphdr.length))
++            zlog_warn ("%s Cap-parser for %s read past cap-length, %u!",
++                       peer->host, LOOKUP (capcode_str, caphdr.code),
++                       caphdr.length);
++          stream_set_getp (s, start + caphdr.length);
++        }
+     }
+   return 0;
+ }
+ 
+ static int
+-bgp_auth_parse (struct peer *peer, u_char *pnt, size_t length)
++bgp_auth_parse (struct peer *peer, size_t length)
+ {
+   bgp_notify_send (peer, 
+ 		   BGP_NOTIFY_OPEN_ERR, 
+@@ -530,30 +620,25 @@ int
+ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
+ {
+   int ret;
+-  u_char *end;
+-  u_char opt_type;
+-  u_char opt_length;
+-  u_char *pnt;
+   u_char *error;
+   u_char error_data[BGP_MAX_PACKET_SIZE];
+-
+-  /* Fetch pointer. */
+-  pnt = stream_pnt (peer->ibuf);
++  struct stream *s = BGP_INPUT(peer);
++  size_t end = stream_get_getp (s) + length;
+ 
+   ret = 0;
+-  opt_type = 0;
+-  opt_length = 0;
+-  end = pnt + length;
+   error = error_data;
+ 
+   if (BGP_DEBUG (normal, NORMAL))
+     zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
+ 	       peer->host, length);
+   
+-  while (pnt < end) 
++  while (stream_get_getp(s) < end)
+     {
+-      /* Check the length. */
+-      if (pnt + 2 > end)
++      u_char opt_type;
++      u_char opt_length;
++      
++      /* Must have at least an OPEN option header */
++      if (STREAM_READABLE(s) < 2)
+ 	{
+ 	  zlog_info ("%s Option length error", peer->host);
+ 	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+@@ -561,11 +646,11 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
+ 	}
+ 
+       /* Fetch option type and length. */
+-      opt_type = *pnt++;
+-      opt_length = *pnt++;
++      opt_type = stream_getc (s);
++      opt_length = stream_getc (s);
+       
+       /* Option length check. */
+-      if (pnt + opt_length > end)
++      if (STREAM_READABLE (s) < opt_length)
+ 	{
+ 	  zlog_info ("%s Option length error", peer->host);
+ 	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+@@ -582,10 +667,10 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
+       switch (opt_type)
+ 	{
+ 	case BGP_OPEN_OPT_AUTH:
+-	  ret = bgp_auth_parse (peer, pnt, opt_length);
++	  ret = bgp_auth_parse (peer, opt_length);
+ 	  break;
+ 	case BGP_OPEN_OPT_CAP:
+-	  ret = bgp_capability_parse (peer, pnt, opt_length, &error);
++	  ret = bgp_capability_parse (peer, opt_length, &error);
+ 	  *capability = 1;
+ 	  break;
+ 	default:
+@@ -602,9 +687,6 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
+          error and erro_data pointer, like below.  */
+       if (ret < 0)
+ 	return -1;
+-
+-      /* Forward pointer. */
+-      pnt += opt_length;
+     }
+ 
+   /* All OPEN option is parsed.  Check capability when strict compare
+diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
+index 7515d3f..436eb01 100644
+--- bgpd/bgp_open.h
++++ bgpd/bgp_open.h
+@@ -21,21 +21,32 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ #ifndef _QUAGGA_BGP_OPEN_H
+ #define _QUAGGA_BGP_OPEN_H
+ 
+-/* MP Capability information. */
+-struct capability_mp
++/* Standard header for capability TLV */
++struct capability_header
++{
++  u_char code;
++  u_char length;
++};
++
++/* Generic MP capability data */
++struct capability_mp_data
+ {
+   u_int16_t afi;
+   u_char reserved;
+   u_char safi;
+ };
+ 
+-/* BGP open message capability. */
+-struct capability
++#pragma pack(1)
++struct capability_orf_entry 
+ {
+-  u_char code;
+-  u_char length;
+-  struct capability_mp mpc;
+-};
++  struct capability_mp_data mpc;
++  u_char num;
++  struct {
++    u_char type;
++    u_char mode;
++  } orfs[];
++} __attribute__ ((packed));
++#pragma pack()
+ 
+ struct graceful_restart_af
+ {
+@@ -44,12 +55,18 @@ struct graceful_restart_af
+   u_char flag;
+ };
+ 
++struct capability_gr
++{
++  u_int16_t restart_flag_time;
++  struct graceful_restart_af gr[];
++};
++
+ /* Capability Code */
+ #define CAPABILITY_CODE_MP              1 /* Multiprotocol Extensions */
+ #define CAPABILITY_CODE_REFRESH         2 /* Route Refresh Capability */
+ #define CAPABILITY_CODE_ORF             3 /* Cooperative Route Filtering Capability */
+ #define CAPABILITY_CODE_RESTART        64 /* Graceful Restart Capability */
+-#define CAPABILITY_CODE_4BYTE_AS       65 /* 4-octet AS number Capability */
++#define CAPABILITY_CODE_AS4            65 /* 4-octet AS number Capability */
+ #define CAPABILITY_CODE_DYNAMIC        66 /* Dynamic Capability */
+ #define CAPABILITY_CODE_REFRESH_OLD   128 /* Route Refresh Capability(cisco) */
+ #define CAPABILITY_CODE_ORF_OLD       130 /* Cooperative Route Filtering Capability(cisco) */
+@@ -59,6 +76,7 @@ struct graceful_restart_af
+ #define CAPABILITY_CODE_REFRESH_LEN     0
+ #define CAPABILITY_CODE_DYNAMIC_LEN     0
+ #define CAPABILITY_CODE_RESTART_LEN     2 /* Receiving only case */
++#define CAPABILITY_CODE_AS4_LEN         4
+ 
+ /* Cooperative Route Filtering Capability.  */
+ 
+@@ -82,5 +100,6 @@ struct graceful_restart_af
+ extern int bgp_open_option_parse (struct peer *, u_char, int *);
+ extern void bgp_open_capability (struct stream *, struct peer *);
+ extern void bgp_capability_vty_out (struct vty *, struct peer *);
++extern int bgp_afi_safi_valid_indices (afi_t, safi_t *);
+ 
+ #endif /* _QUAGGA_BGP_OPEN_H */
+diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
+index 2653201..17ac1f7 100644
+--- bgpd/bgp_packet.c
++++ bgpd/bgp_packet.c
+@@ -1371,8 +1371,6 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
+       ret = bgp_open_option_parse (peer, optlen, &capability);
+       if (ret < 0)
+ 	return ret;
+-
+-      stream_forward_getp (peer->ibuf, optlen);
+     }
+   else
+     {
+@@ -1991,7 +1989,8 @@ static int
+ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
+ {
+   u_char *end;
+-  struct capability cap;
++  struct capability_mp_data mpc;
++  struct capability_header *hdr;
+   u_char action;
+   struct bgp *bgp;
+   afi_t afi;
+@@ -2001,7 +2000,7 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
+   end = pnt + length;
+ 
+   while (pnt < end)
+-    {
++    {      
+       /* We need at least action, capability code and capability length. */
+       if (pnt + 3 > end)
+         {
+@@ -2009,12 +2008,9 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
+           bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+           return -1;
+         }
+-
+       action = *pnt;
+-
+-      /* Fetch structure to the byte stream. */
+-      memcpy (&cap, pnt + 1, sizeof (struct capability));
+-
++      hdr = (struct capability_header *)(pnt + 1);
++      
+       /* Action value check.  */
+       if (action != CAPABILITY_ACTION_SET
+ 	  && action != CAPABILITY_ACTION_UNSET)
+@@ -2027,77 +2023,77 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
+ 
+       if (BGP_DEBUG (normal, NORMAL))
+ 	zlog_debug ("%s CAPABILITY has action: %d, code: %u, length %u",
+-		   peer->host, action, cap.code, cap.length);
++		   peer->host, action, hdr->code, hdr->length);
+ 
+       /* Capability length check. */
+-      if (pnt + (cap.length + 3) > end)
++      if ((pnt + hdr->length + 3) > end)
+         {
+           zlog_info ("%s Capability length error", peer->host);
+           bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+           return -1;
+         }
+ 
++      /* Fetch structure to the byte stream. */
++      memcpy (&mpc, pnt + 3, sizeof (struct capability_mp_data));
++
+       /* We know MP Capability Code. */
+-      if (cap.code == CAPABILITY_CODE_MP)
++      if (hdr->code == CAPABILITY_CODE_MP)
+         {
+-	  afi = ntohs (cap.mpc.afi);
+-	  safi = cap.mpc.safi;
++	  afi = ntohs (mpc.afi);
++	  safi = mpc.safi;
+ 
+           /* Ignore capability when override-capability is set. */
+           if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+ 	    continue;
+-
++          
++          if (!bgp_afi_safi_valid_indices (afi, &safi))
++            {
++              if (BGP_DEBUG (normal, NORMAL))
++                zlog_debug ("%s Dynamic Capability MP_EXT afi/safi invalid",
++                            peer->host, afi, safi);
++              continue;
++            }
++          
+ 	  /* Address family check.  */
+-	  if ((afi == AFI_IP 
+-	       || afi == AFI_IP6)
+-	      && (safi == SAFI_UNICAST 
+-		  || safi == SAFI_MULTICAST 
+-		  || safi == BGP_SAFI_VPNV4))
+-	    {
+-	      if (BGP_DEBUG (normal, NORMAL))
+-		zlog_debug ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u",
+-			   peer->host,
+-			   action == CAPABILITY_ACTION_SET 
+-			   ? "Advertising" : "Removing",
+-			   ntohs(cap.mpc.afi) , cap.mpc.safi);
+-		  
+-	      /* Adjust safi code. */
+-	      if (safi == BGP_SAFI_VPNV4)
+-		safi = SAFI_MPLS_VPN;
+-	      
+-	      if (action == CAPABILITY_ACTION_SET)
+-		{
+-		  peer->afc_recv[afi][safi] = 1;
+-		  if (peer->afc[afi][safi])
+-		    {
+-		      peer->afc_nego[afi][safi] = 1;
+-		      bgp_announce_route (peer, afi, safi);
+-		    }
+-		}
+-	      else
+-		{
+-		  peer->afc_recv[afi][safi] = 0;
+-		  peer->afc_nego[afi][safi] = 0;
+-
+-		  if (peer_active_nego (peer))
+-		    bgp_clear_route (peer, afi, safi);
+-		  else
+-		    BGP_EVENT_ADD (peer, BGP_Stop);
+-		} 
+-	    }
++          if (BGP_DEBUG (normal, NORMAL))
++            zlog_debug ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u",
++                       peer->host,
++                       action == CAPABILITY_ACTION_SET 
++                       ? "Advertising" : "Removing",
++                       ntohs(mpc.afi) , mpc.safi);
++              
++          if (action == CAPABILITY_ACTION_SET)
++            {
++              peer->afc_recv[afi][safi] = 1;
++              if (peer->afc[afi][safi])
++                {
++                  peer->afc_nego[afi][safi] = 1;
++                  bgp_announce_route (peer, afi, safi);
++                }
++            }
++          else
++            {
++              peer->afc_recv[afi][safi] = 0;
++              peer->afc_nego[afi][safi] = 0;
++
++              if (peer_active_nego (peer))
++                bgp_clear_route (peer, afi, safi);
++              else
++                BGP_EVENT_ADD (peer, BGP_Stop);
++            }
+         }
+       else
+         {
+           zlog_warn ("%s unrecognized capability code: %d - ignored",
+-                     peer->host, cap.code);
++                     peer->host, hdr->code);
+         }
+-      pnt += cap.length + 3;
++      pnt += hdr->length + 3;
+     }
+   return 0;
+ }
+ 
+ /* Dynamic Capability is received. */
+-static void
++int
+ bgp_capability_receive (struct peer *peer, bgp_size_t size)
+ {
+   u_char *pnt;
+@@ -2130,7 +2126,7 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size)
+     }
+ 
+   /* Parse packet. */
+-  ret = bgp_capability_msg_parse (peer, pnt, size);
++  return bgp_capability_msg_parse (peer, pnt, size);
+ }
+ 
+ /* BGP read utility function. */
+diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
+index 1e21c74..3eeb5f9 100644
+--- bgpd/bgp_vty.c
++++ bgpd/bgp_vty.c
+@@ -6681,14 +6681,14 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
+ 
+ 	  vty_out (vty, "4 ");
+ 
+-	  vty_out (vty, "%5d %7d %7d %8d %4d %4ld ",
++	  vty_out (vty, "%5d %7d %7d %8d %4d %4lu ",
+ 		   peer->as,
+ 		   peer->open_in + peer->update_in + peer->keepalive_in
+ 		   + peer->notify_in + peer->refresh_in + peer->dynamic_cap_in,
+ 		   peer->open_out + peer->update_out + peer->keepalive_out
+ 		   + peer->notify_out + peer->refresh_out
+ 		   + peer->dynamic_cap_out,
+-		   0, 0, peer->obuf->count);
++		   0, 0, (unsigned long)peer->obuf->count);
+ 
+ 	  vty_out (vty, "%8s", 
+ 		   peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN));
+@@ -7403,7 +7403,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
+   /* Packet counts. */
+   vty_out (vty, "  Message statistics:%s", VTY_NEWLINE);
+   vty_out (vty, "    Inq depth is 0%s", VTY_NEWLINE);
+-  vty_out (vty, "    Outq depth is %ld%s", p->obuf->count, VTY_NEWLINE);
++  vty_out (vty, "    Outq depth is %lu%s", (unsigned long)p->obuf->count, VTY_NEWLINE);
+   vty_out (vty, "                         Sent       Rcvd%s", VTY_NEWLINE);
+   vty_out (vty, "    Opens:         %10d %10d%s", p->open_out, p->open_in, VTY_NEWLINE);
+   vty_out (vty, "    Notifications: %10d %10d%s", p->notify_out, p->notify_in, VTY_NEWLINE);
+diff --git a/lib/log.c b/lib/log.c
+index cbf76af..ff47cae 100644
+--- lib/log.c
++++ lib/log.c
+@@ -769,7 +769,7 @@ mes_lookup (struct message *meslist, int max, int index)
+       {
+ 	if (meslist->key == index)
+ 	  {
+-	    zlog_warn("message index %d [%s] found in position %d (max is %d)",
++	    zlog_debug ("message index %d [%s] found in position %d (max is %d)",
+ 		      index, meslist->str, i, max);
+ 	    return meslist->str;
+ 	  }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/45-bgpd-capab-typo.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,27 @@
+commit 7b87b33fa53254f14b79e95bb8a0b24f8ef9e1c1
+Author: Paul Jakma <paul.jakma@sun.com>
+Date:   Mon Sep 17 13:51:28 2007 +0100
+
+    [bgpd] Fix typo, which prevented advertisement of MP (non-IPv4) prefixes
+    
+    2007-09-17 Paul Jakma <paul.jakma@sun.com>
+    
+    	* bgp_open.c: (bgp_capability_mp) We were setting
+    	  afc_nego[safi][safi] rather than afc_nego[afi][safi], thus
+    	  failling to announce any non-IPv4 prefixes. Remove the extra,
+    	  typo-ed character.
+    	* tests/bgp_capability_test.c: Test that peer's adv_recv and
+    	  adv_nego get set correctly for MP capability and given AFI/SAFI.
+    	  Colour OK/failed result so it's easier to find them.
+
+--- bgpd/bgp_open.c
++++ bgpd/bgp_open.c
+@@ -177,7 +177,7 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
+   peer->afc_recv[mpc.afi][mpc.safi] = 1;
+   
+   if (peer->afc[mpc.afi][mpc.safi])
+-    peer->afc_nego[mpc.safi][mpc.safi] = 1;
++    peer->afc_nego[mpc.afi][mpc.safi] = 1;
+   else 
+     return -1;
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/50-bgpd-nosub.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,27 @@
+commit 6d134fb4defecb16591adbf4acb020acd165a75a
+Author: Paul Jakma <paul.jakma@sun.com>
+Date:   Thu Aug 23 23:22:02 2007 +0000
+
+    [bgpd] Pass NOSUB to regexec
+    
+    2007-08-23 Paul Jakma <paul.jakma@sun.com>
+    
+    	* bgp_regex.c: (bgp_regcomp) Pass NOSUB flag to regcomp to
+    	  prevent parsing of substitutions, which can have profound
+    	  performance effects on bgpd and are of no use to the CLI
+    	  anyway. How much it helps depends on the regex
+    	  implementation.
+
+diff --git a/bgpd/bgp_regex.c b/bgpd/bgp_regex.c
+index be84d40..9b65f7c 100644
+--- bgpd/bgp_regex.c
++++ bgpd/bgp_regex.c
+@@ -66,7 +66,7 @@ bgp_regcomp (const char *regstr)
+ 
+   regex = XMALLOC (MTYPE_BGP_REGEXP, sizeof (regex_t));
+ 
+-  ret = regcomp (regex, magic_str, REG_EXTENDED);
++  ret = regcomp (regex, magic_str, REG_EXTENDED|REG_NOSUB);
+ 
+   XFREE (MTYPE_TMP, magic_str);
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/55-bgpd-rm-assert.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,217 @@
+commit 9eda90ce8094683a5315007fbd0f9249a284f36f
+Author: Paul Jakma <paul.jakma@sun.com>
+Date:   Thu Aug 30 13:36:17 2007 +0000
+
+    [bgpd] bug #398 Bogus free on out route-map, and assert() with rsclients
+    
+    2007-08-27 Paul Jakma <paul.jakma@sun.com>
+    
+    	* bgp_route.c: (bgp_announce_check) Fix bug #398, slight
+    	  modification of Vladimir Ivanov's suggested fix - to keep
+    	  memory alloc conditional.
+    	  (bgp_process_announce_selected) Don't take struct attr as
+    	  argument, none of the callers need it and it needlessly
+    	  distances allocation from use.
+    	  Free the extended attr, the attr itself is on the stack.
+    	  Fix bad indentation.
+    	* bgp_attr.c: (bgp_packet_attribute) Remove incorrect assert,
+    	  and adjust conditional to test attr->extra, diagnosis by
+    	  Vladimir Ivanov in bug #398.
+    
+    2007-08-27 Vladimir Ivanov <wawa@yandex-team.ru>
+    
+    	* bgp_route.c: (bgp_announce_check_rsclient) copy of
+    	  ri->attr is no longer deep enough, due to addition of
+    	  attr->extra. It should use bgp_attr_dup, as
+    	  bgp_announce_check() does.
+
+diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
+index 23d9586..ee17b6d 100644
+--- bgpd/bgp_attr.c
++++ bgpd/bgp_attr.c
+@@ -1625,8 +1625,6 @@
+       && from
+       && peer_sort (from) == BGP_PEER_IBGP)
+     {
+-      assert (attr->extra);
+-      
+       /* Originator ID. */
+       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+       stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
+@@ -1641,7 +1639,7 @@
+       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+       stream_putc (s, BGP_ATTR_CLUSTER_LIST);
+       
+-      if (attr->extra->cluster)
++      if (attr->extra && attr->extra->cluster)
+ 	{
+ 	  stream_putc (s, attr->extra->cluster->length + 4);
+ 	  /* If this peer configuration's parent BGP has cluster_id. */
+diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
+index 0f4da98..9ddeca5 100644
+--- bgpd/bgp_route.c
++++ bgpd/bgp_route.c
+@@ -999,11 +999,10 @@
+       || (ri->extra && ri->extra->suppress) )
+     {
+       struct bgp_info info;
+-      struct attr dummy_attr;
++      struct attr dummy_attr = { 0 };
+       
+       info.peer = peer;
+       info.attr = attr;
+-      
+ 
+       /* The route reflector is not allowed to modify the attributes
+ 	 of the reflected IBGP routes. */
+@@ -1010,9 +1009,8 @@
+       if (peer_sort (from) == BGP_PEER_IBGP 
+ 	  && peer_sort (peer) == BGP_PEER_IBGP)
+ 	{
+-	  dummy_attr.extra = NULL;
+ 	  bgp_attr_dup (&dummy_attr, attr);
+-	  info.attr = &dummy_attr; 
++	  info.attr = &dummy_attr;
+ 	}
+ 
+       SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT); 
+@@ -1024,7 +1022,8 @@
+ 
+       peer->rmap_type = 0;
+       
+-      bgp_attr_extra_free (&dummy_attr);
++      if (dummy_attr.extra)
++        bgp_attr_extra_free (&dummy_attr);
+       
+       if (ret == RMAP_DENYMATCH)
+ 	{
+@@ -1127,7 +1126,7 @@
+ #endif /* BGP_SEND_ASPATH_CHECK */
+ 
+   /* For modify attribute, copy it to temporary structure. */
+-  *attr = *ri->attr;
++  bgp_attr_dup (attr, ri->attr);
+ 
+   /* next-hop-set */
+   if ((p->family == AF_INET && attr->nexthop.s_addr == 0)
+@@ -1329,21 +1328,22 @@
+ 
+ static int
+ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected,
+-        struct bgp_node *rn, struct attr *attr, afi_t afi, safi_t safi)
+-    {
++                               struct bgp_node *rn, afi_t afi, safi_t safi)
++{
+   struct prefix *p;
++  struct attr attr = { 0 };
+ 
+   p = &rn->p;
+ 
+-      /* Announce route to Established peer. */
+-      if (peer->status != Established)
++  /* Announce route to Established peer. */
++  if (peer->status != Established)
+     return 0;
+ 
+-      /* Address family configuration check. */
+-      if (! peer->afc_nego[afi][safi])
++  /* Address family configuration check. */
++  if (! peer->afc_nego[afi][safi])
+     return 0;
+ 
+-      /* First update is deferred until ORF or ROUTE-REFRESH is received */
++  /* First update is deferred until ORF or ROUTE-REFRESH is received */
+   if (CHECK_FLAG (peer->af_sflags[afi][safi],
+       PEER_STATUS_ORF_WAIT_REFRESH))
+     return 0;
+@@ -1353,8 +1353,8 @@
+       case BGP_TABLE_MAIN:
+       /* Announcement to peer->conf.  If the route is filtered,
+          withdraw it. */
+-        if (selected && bgp_announce_check (selected, peer, p, attr, afi, safi))
+-          bgp_adj_out_set (rn, peer, p, attr, afi, safi, selected);
++        if (selected && bgp_announce_check (selected, peer, p, &attr, afi, safi))
++          bgp_adj_out_set (rn, peer, p, &attr, afi, safi, selected);
+         else
+           bgp_adj_out_unset (rn, peer, p, afi, safi);
+         break;
+@@ -1361,13 +1361,16 @@
+       case BGP_TABLE_RSCLIENT:
+         /* Announcement to peer->conf.  If the route is filtered, 
+            withdraw it. */
+-        if (selected && bgp_announce_check_rsclient
+-              (selected, peer, p, attr, afi, safi))
+-          bgp_adj_out_set (rn, peer, p, attr, afi, safi, selected);
+-      else
+-	bgp_adj_out_unset (rn, peer, p, afi, safi);
++        if (selected && 
++            bgp_announce_check_rsclient (selected, peer, p, &attr, afi, safi))
++          bgp_adj_out_set (rn, peer, p, &attr, afi, safi, selected);
++        else
++	  bgp_adj_out_unset (rn, peer, p, afi, safi);
+         break;
+     }
++  
++  bgp_attr_extra_free (&attr);
++  
+   return 0;
+ }
+ 
+@@ -1417,8 +1420,7 @@
+ 	      bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED);
+ 	    }
+ 
+-	  bgp_process_announce_selected (rsclient, new_select, rn, &attr,
+-					 afi, safi);
++	  bgp_process_announce_selected (rsclient, new_select, rn, afi, safi);
+ 	}
+     }
+   else
+@@ -1430,8 +1432,7 @@
+ 	  bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED);
+ 	  bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED);
+ 	}
+-      bgp_process_announce_selected (rsclient, new_select, rn,
+-				     &attr, afi, safi);
++      bgp_process_announce_selected (rsclient, new_select, rn, afi, safi);
+     }
+ 
+   if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
+@@ -1457,10 +1458,7 @@
+   struct bgp_info_pair old_and_new;
+   struct listnode *node, *nnode;
+   struct peer *peer;
+-  struct attr attr;
+   
+-  memset (&attr, 0, sizeof (struct attr));
+-  
+   /* Best path selection. */
+   bgp_best_selection (bgp, rn, &old_and_new);
+   old_select = old_and_new.old;
+@@ -1491,7 +1489,7 @@
+   /* Check each BGP peer. */
+   for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+     {
+-      bgp_process_announce_selected (peer, new_select, rn, &attr, afi, safi);
++      bgp_process_announce_selected (peer, new_select, rn, afi, safi);
+     }
+ 
+   /* FIB update. */
+@@ -1516,8 +1514,6 @@
+   if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
+     bgp_info_reap (rn, old_select);
+   
+-  bgp_attr_extra_free (&attr);
+-  
+   UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
+   return WQ_SUCCESS;
+ }
+@@ -5888,7 +5884,7 @@
+ 	      {
+ 		struct route_map *rmap = output_arg;
+ 		struct bgp_info binfo;
+-		struct attr dummy_attr; 
++		struct attr dummy_attr = { 0 }; 
+ 		int ret;
+ 
+ 		bgp_attr_dup (&dummy_attr, ri->attr);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/60-bgp-comm-crash.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,53 @@
+Author: Paul Jakma <paul.jakma@sun.com>
+Date:   Fri Sep 7 14:24:55 2007 +0000
+
+    [bgpd] low-impact DoS: crash on malformed community with debug set
+    
+    2007-09-07 Paul Jakma <paul.jakma@sun.com>
+    
+    	* (general) bgpd can be made crash by remote peers if debug
+    	  bgp updates is set, due to NULL pointer dereference.
+    	  Reported by "Mu Security Research Team",
+    	  <security@musecurity.com>.
+    	* bgp_attr.c: (bgp_attr_community) If community length is 0,
+    	  don't set the community-present attribute bit, just return
+    	  early.
+    	* bgp_debug.c: (community_str,community_com2str) Check com
+    	  pointer before dereferencing.
+
+--- bgpd/bgp_attr.c
++++ bgpd/bgp_attr.c
+@@ -962,7 +962,10 @@
+ 		    struct attr *attr, u_char flag)
+ {
+   if (length == 0)
+-    attr->community = NULL;
++    {
++      attr->community = NULL;
++      return 0;
++    }
+   else
+     {
+       attr->community = 
+--- bgpd/bgp_community.c
++++ bgpd/bgp_community.c
+@@ -206,6 +206,9 @@ community_com2str  (struct community *com)
+   u_int16_t as;
+   u_int16_t val;
+ 
++  if (!com)
++    return NULL;
++  
+   /* When communities attribute is empty.  */
+   if (com->size == 0)
+     {
+@@ -377,6 +380,9 @@ community_dup (struct community *com)
+ char *
+ community_str (struct community *com)
+ {
++  if (!com)
++    return NULL;
++  
+   if (! com->str)
+     com->str = community_com2str (com);
+   return com->str;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/65-isisd-iso-checksum.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,676 @@
+diff -ur quagga-0.99.8/ChangeLog quagga-unified-checksum/ChangeLog
+--- ChangeLog
++++ ChangeLog
+@@ -1,3 +1,18 @@
++2008-06-25 Jingjing Duan <jingjing.duan@sun.com>
++	* lib/checksum.[ch]: Add a consolidated checksum function to be
++	  used by both OSPF and IS-IS. The consolidated version also fixes
++	  the checksum byte-order checksum on big-endian architectures.
++	* isisd/iso_checksum.[ch]: Remove the old checksum implementation
++	  and use the consolidated version.
++	* isisd/isis_dlpi.c: Change ioctl from PFIOCSETF (transparent mode)
++	  to I_STR (non-transparent mode). The old code resulted in no
++	  filtering at all. 
++	* isisd/isis_dlpi.c: (open_dlpi_dev) Clearview-UV device nodes are
++	  under /dev/net, try opening there before attempting style 1 or 2
++	  names.
++	* ospfd/ospf_lsa.c: Remove the old checksum implementation and
++	  use the consolidated version.
++
+ 2007-08-07 James Carlson <james.d.carlson@sun.com>
+ 
+ 	* configure.ac: Added support for separate link-layer access
+diff -ur quagga-0.99.8/isisd/isis_dlpi.c quagga-unified-checksum/isisd/isis_dlpi.c
+--- isisd/isis_dlpi.c
++++ isisd/isis_dlpi.c
+@@ -42,8 +42,6 @@
+ #include "isisd/isis_circuit.h"
+ #include "isisd/isis_flags.h"
+ #include "isisd/isisd.h"
+-#include "isisd/isis_constants.h"
+-#include "isisd/isis_circuit.h"
+ #include "isisd/isis_network.h"
+ 
+ #include "privs.h"
+@@ -315,13 +313,24 @@
+ 	circuit->interface->name);
+       return ISIS_WARNING;
+     }
++  
++  /* Try the vanity node first, if permitted */
++  if (getenv("DLPI_DEVONLY") == NULL)
++    {
++      (void) snprintf (devpath, sizeof(devpath), "/dev/net/%s",
++                      circuit->interface->name);
++      fd = dlpiopen (devpath, &acklen);
++    }
++  
++  /* Now try as an ordinary Style 1 node */
++  if (fd == -1)
++    {
++      (void) snprintf (devpath, sizeof (devpath), "/dev/%s",
++                      circuit->interface->name);
++      unit = -1;
++      fd = dlpiopen (devpath, &acklen);
++    }
+ 
+-  /* Try first as Style 1 */
+-  (void) snprintf(devpath, sizeof (devpath), "/dev/%s",
+-    circuit->interface->name);
+-  unit = -1;
+-  fd = dlpiopen (devpath, &acklen);
+-
+   /* If that fails, try again as Style 2 */
+   if (fd == -1)
+     {
+@@ -452,11 +461,19 @@
+   if (ioctl (fd, I_PUSH, "pfmod") == 0)
+     {
+       struct packetfilt pfil;
++      struct strioctl sioc;
+ 
+       pfil.Pf_Priority = 0;
+       pfil.Pf_FilterLen = sizeof (pf_filter) / sizeof (u_short);
+       memcpy (pfil.Pf_Filter, pf_filter, sizeof (pf_filter));
+-      ioctl (fd, PFIOCSETF, &pfil);
++      /* pfmod does not support transparent ioctls */
++      sioc.ic_cmd = PFIOCSETF;
++      sioc.ic_timout = 5;
++      sioc.ic_len = sizeof (struct packetfilt);
++      sioc.ic_dp = (char *)&pfil;
++      if (ioctl (fd, I_STR, &sioc) == -1)
++         zlog_warn("%s: could not perform PF_IOCSETF on %s",
++           __func__, circuit->interface->name);
+     }
+ 
+   circuit->fd = fd;
+diff -ur quagga-0.99.8/isisd/isis_lsp.c quagga-unified-checksum/isisd/isis_lsp.c
+--- isisd/isis_lsp.c
++++ isisd/isis_lsp.c
+@@ -33,6 +33,7 @@
+ #include "command.h"
+ #include "hash.h"
+ #include "if.h"
++#include "checksum.h"
+ 
+ #include "isisd/dict.h"
+ #include "isisd/isis_constants.h"
+@@ -45,7 +46,6 @@
+ #include "isisd/isis_dynhn.h"
+ #include "isisd/isis_misc.h"
+ #include "isisd/isis_flags.h"
+-#include "isisd/iso_checksum.h"
+ #include "isisd/isis_csm.h"
+ #include "isisd/isis_adjacency.h"
+ #include "isisd/isis_spf.h"
+@@ -314,7 +314,7 @@
+     newseq = seq_num++;
+ 
+   lsp->lsp_header->seq_num = htonl (newseq);
+-  iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
++  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
+ 		   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+ 
+   return;
+@@ -1803,7 +1803,7 @@
+     tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
+ 
+   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
+-  iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
++  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
+ 		   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+ 
+   list_delete (adj_list);
+@@ -2071,7 +2071,7 @@
+       lsp->lsp_header->pdu_len =
+ 	htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+       lsp->purged = 0;
+-      iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
++      fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
+ 		       ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+       ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+     }
+diff -ur quagga-0.99.8/isisd/isis_pdu.c quagga-unified-checksum/isisd/isis_pdu.c
+--- isisd/isis_pdu.c
++++ isisd/isis_pdu.c
+@@ -32,6 +32,7 @@
+ #include "hash.c"
+ #include "prefix.h"
+ #include "if.h"
++#include "checksum.h"
+ 
+ #include "isisd/dict.h"
+ #include "isisd/include-netbsd/iso.h"
+@@ -1121,7 +1122,7 @@
+ 		  if (isis->debugs & DEBUG_UPDATE_PACKETS)
+ 		    zlog_debug ("LSP LEN: %d",
+ 				ntohs (lsp->lsp_header->pdu_len));
+-		  iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
++		  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
+ 				   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+ 		  ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ 		  if (isis->debugs & DEBUG_UPDATE_PACKETS)
+@@ -1164,7 +1165,7 @@
+ 	  /* 7.3.16.1  */
+ 	  lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
+ 
+-	  iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
++	  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
+ 			   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+ 
+ 	  ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+diff -ur quagga-0.99.8/isisd/iso_checksum.c quagga-unified-checksum/isisd/iso_checksum.c
+--- isisd/iso_checksum.c
++++ isisd/iso_checksum.c
+@@ -23,6 +23,7 @@
+ 
+ #include <zebra.h>
+ #include "iso_checksum.h"
++#include "checksum.h"
+ 
+ /*
+  * Calculations of the OSI checksum.
+@@ -47,14 +48,10 @@
+ int
+ iso_csum_verify (u_char * buffer, int len, uint16_t * csum)
+ {
+-  u_int8_t *p;
++  u_int16_t checksum;
+   u_int32_t c0;
+   u_int32_t c1;
+-  u_int16_t checksum;
+-  int i, partial_len;
+ 
+-  p = buffer;
+-  checksum = 0;
+   c0 = *csum & 0xff00;
+   c1 = *csum & 0x00ff;
+ 
+@@ -70,124 +69,8 @@
+   if (c0 == 0 || c1 == 0)
+     return 1;
+ 
+-  /*
+-   * Otherwise initialize to zero and calculate...
+-   */
+-  c0 = 0;
+-  c1 = 0;
+-
+-  while (len)
+-    {
+-      partial_len = MIN(len, 5803);
+-
+-      for (i = 0; i < partial_len; i++)
+-	{
+-	  c0 = c0 + *(p++);
+-	  c1 += c0;
+-	}
+-
+-      c0 = c0 % 255;
+-      c1 = c1 % 255;
+-
+-      len -= partial_len;
+-    }
+-
+-  if (c0 == 0 && c1 == 0)
+-    return 0;
+-
++  checksum = fletcher_checksum(buffer, len, (u_char *)csum - buffer);
++  if (checksum == *csum)
++      return 0;
+   return 1;
+ }
+-
+-/*
+- * Creates the checksum. *csum points to the position of the checksum in the 
+- * PDU. 
+- * Based on Annex C.4 of ISO/IEC 8473
+- */
+-#define FIXED_CODE
+-u_int16_t
+-iso_csum_create (u_char * buffer, int len, u_int16_t n)
+-{
+-
+-  u_int8_t *p;
+-  int x;
+-  int y;
+-  u_int32_t mul;
+-  u_int32_t c0;
+-  u_int32_t c1;
+-  u_int16_t checksum;
+-  u_int16_t *csum;
+-  int i, init_len, partial_len;
+-
+-  checksum = 0;
+-
+-  /*
+-   * Zero the csum in the packet.
+-   */
+-  csum = (u_int16_t *) (buffer + n);
+-  *(csum) = checksum;
+-
+-  p = buffer;
+-  c0 = 0;
+-  c1 = 0;
+-  init_len = len;
+-
+-  while (len != 0)
+-    {
+-      partial_len = MIN(len, 5803);
+-
+-      for (i = 0; i < partial_len; i++)
+-	{
+-	  c0 = c0 + *(p++);
+-	  c1 += c0;
+-	}
+-
+-      c0 = c0 % 255;
+-      c1 = c1 % 255;
+-
+-      len -= partial_len;
+-    }
+-
+-  mul = (init_len - n)*(c0);
+-
+-#ifdef FIXED_CODE
+-  x = mul - c0 - c1;
+-  y = c1 - mul - 1;
+-
+-  if (y > 0)
+-    y++;
+-  if (x < 0)
+-    x--;
+-
+-  x %= 255;
+-  y %= 255;
+-
+-  if (x == 0)
+-    x = 255;
+-  if (y == 0)
+-    y = 1;
+-
+-  checksum = (y << 8) | (x & 0xFF);
+-
+-#else
+-  x = mul - c0 - c1;
+-  x %= 255;
+-
+-  y = c1 - mul - 1;
+-  y %= 255;
+-
+-  if (x == 0)
+-    x = 255;
+-  if (y == 0)
+-    y = 255;
+-
+-  checksum = ((y << 8) | x);
+-#endif
+-
+-  /*
+-   * Now we write this to the packet
+-   */
+-  *(csum) = checksum;
+-
+-  /* return the checksum for user usage */
+-  return checksum;
+-}
+diff -ur quagga-0.99.8/isisd/iso_checksum.h quagga-unified-checksum/isisd/iso_checksum.h
+--- isisd/iso_checksum.h
++++ isisd/iso_checksum.h
+@@ -24,6 +24,5 @@
+ #define _ZEBRA_ISO_CSUM_H
+ 
+ int iso_csum_verify (u_char * buffer, int len, uint16_t * csum);
+-u_int16_t iso_csum_create (u_char * buffer, int len, u_int16_t n);
+ 
+ #endif /* _ZEBRA_ISO_CSUM_H */
+diff -ur quagga-0.99.8/lib/checksum.c quagga-unified-checksum/lib/checksum.c
+--- lib/checksum.c
++++ lib/checksum.c
+@@ -45,3 +45,82 @@
+ 	answer = ~sum;		/* ones-complement, then truncate to 16 bits */
+ 	return(answer);
+ }
++
++/* Fletcher Checksum -- Refer to RFC1008. */
++#define MODX                 4102   /* 5802 should be fine */
++
++/* To be consistent, offset is 0-based index, rather than the 1-based 
++   index required in the specification ISO 8473, Annex C.1 */
++u_int16_t
++fletcher_checksum(u_char * buffer, int len, u_int16_t offset)
++{
++  u_int8_t *p;
++  int x;
++  int y;
++  u_int32_t mul;
++  u_int32_t c0;
++  u_int32_t c1;
++  u_int16_t checksum;
++  u_int16_t *csum;
++  int i, init_len, partial_len;
++
++  checksum = 0;
++
++  /*
++   * Zero the csum in the packet.
++   */
++  csum = (u_int16_t *) (buffer + offset);
++  *(csum) = checksum;
++
++  p = buffer;
++  c0 = 0;
++  c1 = 0;
++  init_len = len;
++
++  while (len != 0)
++    {
++      partial_len = MIN(len, MODX);
++
++      for (i = 0; i < partial_len; i++)
++	{
++	  c0 = c0 + *(p++);
++	  c1 += c0;
++	}
++
++      c0 = c0 % 255;
++      c1 = c1 % 255;
++
++      len -= partial_len;
++    }
++
++  mul = (init_len - offset)*(c0);
++
++  x = mul - c0 - c1;
++  y = c1 - mul - 1;
++
++  if (y > 0)
++    y++;
++  if (x < 0)
++    x--;
++
++  x %= 255;
++  y %= 255;
++
++  if (x == 0)
++    x = 255;
++  if (y == 0)
++    y = 1;
++
++  /*
++   * Now we write this to the packet.
++   * We could skip this step too, since the checksum returned would
++   * be stored into the checksum field by the caller.
++   */
++  buffer[offset] = x;
++  buffer[offset + 1] = y;
++
++  /* Take care of the endian issue */
++  checksum = htons((x << 8) | (y & 0xFF));
++
++  return checksum;
++}
+diff -ur quagga-0.99.8/lib/checksum.h quagga-unified-checksum/lib/checksum.h
+--- lib/checksum.h
++++ lib/checksum.h
+@@ -1 +1,2 @@
+ extern int in_cksum(void *, int);
++extern u_int16_t fletcher_checksum(u_char * buffer, int len, u_int16_t offset);
+diff -ur quagga-0.99.8/ospfd/ospf_lsa.c quagga-unified-checksum/ospfd/ospf_lsa.c
+--- ospfd/ospf_lsa.c
++++ ospfd/ospf_lsa.c
+@@ -32,6 +32,7 @@
+ #include "thread.h"
+ #include "hash.h"
+ #include "sockunion.h"		/* for inet_aton() */
++#include "checksum.h"
+ 
+ #include "ospfd/ospfd.h"
+ #include "ospfd/ospf_interface.h"
+@@ -172,46 +173,22 @@
+ 
+ 
+ /* Fletcher Checksum -- Refer to RFC1008. */
+-#define MODX                 4102
+-#define LSA_CHECKSUM_OFFSET    15
+ 
++/* All the offsets are zero-based. The offsets in the RFC1008 are 
++   one-based. */
+ u_int16_t
+ ospf_lsa_checksum (struct lsa_header *lsa)
+ {
+-  u_char *sp, *ep, *p, *q;
+-  int c0 = 0, c1 = 0;
+-  int x, y;
+-  u_int16_t length;
+-
+-  lsa->checksum = 0;
+-  length = ntohs (lsa->length) - 2;
+-  sp = (u_char *) &lsa->options;
+-
+-  for (ep = sp + length; sp < ep; sp = q)
+-    {
+-      q = sp + MODX;
+-      if (q > ep)
+-        q = ep;
+-      for (p = sp; p < q; p++)
+-        {
+-          c0 += *p;
+-          c1 += c0;
+-        }
+-      c0 %= 255;
+-      c1 %= 255;
+-    }
++  u_char *buffer = (u_char *) &lsa->options;
++  int options_offset = buffer - (u_char *) &lsa->ls_age; /* should be 2 */
+ 
+-  x = (((int)length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255;
+-  if (x <= 0)
+-    x += 255;
+-  y = 510 - c0 - x;
+-  if (y > 255)
+-    y -= 255;
++  /* Skip the AGE field */
++  u_int16_t len = ntohs(lsa->length) - options_offset; 
+ 
+-  /* take care endian issue. */
+-  lsa->checksum = htons ((x << 8) + y);
++  /* Checksum offset starts from "options" field, not the beginning of the
++     lsa_header struct. The offset is 14, rather than 16. */
+ 
+-  return (lsa->checksum);
++  return fletcher_checksum(buffer, len, (u_char *) &lsa->checksum - buffer);
+ }
+ 
+ 
+diff -ur quagga-0.99.8/solaris/quagga.init.in quagga-unified-checksum/solaris/quagga.init.in
+--- solaris/quagga.init.in
++++ solaris/quagga.init.in
+@@ -134,7 +134,7 @@
+ case "${DAEMON}" in
+ 	bgpd)
+ 	;;
+-	zebra | ospfd | ospf6d | ripd | ripngd )
++	zebra | ospfd | ospf6d | ripd | ripngd | isisd)
+ 		quagga_is_globalzone || exit $SMF_EXIT_OK
+ 	;;
+ 	*)
+@@ -168,7 +168,7 @@
+ 	eval exec $DAEMON_PATH/$DAEMON $DAEMON_ARGS --pid_file ${PIDFILE} &
+ }
+ 
+-stop () {
++daemonstop () {
+ 	if [ -f "${PIDFILE}" ]; then
+ 		/usr/bin/kill -TERM `/usr/bin/cat "${PIDFILE}"`
+ 	fi
+@@ -179,7 +179,7 @@
+ 	start
+ 	;;
+ 'stop')
+-	stop
++	daemonstop
+ 	;;
+ 
+ *)
+diff -ur quagga-0.99.8/solaris/quagga.xml.in quagga-unified-checksum/solaris/quagga.xml.in
+--- solaris/quagga.xml.in
++++ solaris/quagga.xml.in
+@@ -187,7 +187,7 @@
+ 		<service_fmri value='svc:/network/routing-setup' />
+ 	</dependency>
+ 	
+-	<!-- ensure that restart of zebra is propogated to daemon -->
++	<!-- ensure that restart of zebra is propagated to daemon -->
+ 	<dependency
+ 		name='zebra'
+ 		grouping='optional_all'
+@@ -818,6 +818,148 @@
+ 			<manpage title='bgpd' section='1M'
+ 				manpath='@mandir@' />
+ 			<doc_link name='quagga.net' 
++				uri='http://www.quagga.net/' />
++		</documentation>
++	</template>
++	</instance>
++	<stability value='Unstable' />
++</service>
++
++<service
++	name='network/routing/isis'
++	type='service'
++	version='1'>
++
++	<instance name='quagga' enabled='false'>
++
++	<dependency name='fs'
++		grouping='require_all'
++		restart_on='none'
++		type='service'>
++		<service_fmri
++			value='svc:/system/filesystem/usr:default' />
++	</dependency>
++
++	<dependency
++		name='ipv6-forwarding'
++		grouping='optional_all'
++		restart_on='refresh'
++		type='service'>
++		<service_fmri value='svc:/network/ipv6-forwarding' />
++	</dependency>
++	
++	<dependency
++		name='ipv4-forwarding'
++		grouping='optional_all'
++		restart_on='refresh'
++		type='service'>
++		<service_fmri value='svc:/network/ipv4-forwarding' />
++	</dependency>
++
++	<!-- do not not run unless routing-setup has run -->
++	<dependency
++		name='network_routing_setup'
++		grouping='require_all'
++		restart_on='refresh'
++		type='service'>
++		<service_fmri value='svc:/network/routing-setup' />
++	</dependency>
++
++	<!-- ensure that restart of zebra is propogated to daemon -->
++	<dependency
++		name='zebra'
++		grouping='optional_all'
++		restart_on='restart'
++		type='service'>
++		<service_fmri value='svc:/network/routing/zebra:quagga' />
++	</dependency>
++
++	<exec_method
++		type='method'
++		name='start'
++		exec='/lib/svc/method/quagga isisd'
++		timeout_seconds='60'>
++		<method_context>
++		  <method_credential
++		   user='root' group='root'/>
++ 		</method_context>
++	</exec_method>
++
++	<!-- isisd can take a long time to shutdown, due to graceful 
++	     shutdown 
++	 -->
++	<exec_method
++		type='method'
++		name='stop'
++		exec=':kill'
++		timeout_seconds='60'>
++	</exec_method>
++
++	<property_group name='startd'
++		type='framework'>
++		<!-- sub-process core dumps shouldn't restart session -->
++		<propval name='ignore_error'
++		    type='astring' value='core,signal' />
++	</property_group>
++
++	<!-- Properties in this group are used by routeadm (1M) -->
++	<property_group name='routeadm' type='application'>
++		<stability value='Unstable' />
++		<!-- Identifies service as a routing service -->
++		<propval name='daemon' type='astring'
++			value='@sbindir@/isisd' />
++		<propval name='value_authorization' type='astring'
++			value='solaris.smf.value.routing' />
++		<property name='protocol' type='astring'>
++			<astring_list>
++				<value_node value='ipv4'/>
++				<value_node value='ipv6'/>
++			</astring_list>
++		</property>
++	</property_group>
++	
++	<!-- Properties in this group are modifiable via routeadm (1M) -->
++	<property_group name='routing' type='application'>
++		<propval name='value_authorization' type='astring' 
++		         value='solaris.smf.value.routing' />
++
++		<!-- Options common to Quagga daemons -->
++		<!-- The config file to use, if not the default -->
++		<propval name='config_file' type='astring' value=''/>
++		<!-- The vty_port to listen on if not the default.
++		     0 to disable --> 
++		<propval name='vty_port' type='integer' value='0' />
++		<!-- The address to bind the VTY interface to, if not any. -->
++		<propval name='vty_address' type='astring' value='' />
++		<!-- The user to switch to after startup, if not the default -->
++		<propval name='user' type='astring' value='' />
++		<!-- The group to switch to, if not the default.
++		     If user is specified, this defaults to a group with
++		     same name as user -->
++		<propval name='group' type='astring' value='' />
++		<!-- The pidfile to use, if not the default of
++		     @quagga_statedir@ -->
++		<propval name='pid_file' type='astring' value='' />
++	</property_group>
++
++	<property_group name='general' type='framework'>
++		<!-- to start stop routing services -->
++		<propval name='action_authorization' type='astring'
++			 value='solaris.smf.manage.routing' />
++		<propval name='value_authorization' type='astring'
++			 value='solaris.smf.manage.routing' />
++	</property_group>
++
++	<template>
++		<common_name>
++			<loctext xml:lang='C'>
++			Quagga: isisd, IS-IS routing protocol daemon.
++			</loctext>
++		</common_name>
++		<documentation>
++			<manpage title='isisd' section='1M'
++				manpath='@mandir@' />
++			<doc_link name='quagga.net' 
+ 				uri='http://www.quagga.net/' />
+ 		</documentation>
+ 	</template>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/70-isisd-trill.patch	Mon Jul 18 12:08:25 2011 -0700
@@ -0,0 +1,8495 @@
+diff --git configure.ac configure.ac
+index 78198cb..12e9729 100755
+--- configure.ac
++++ configure.ac
+@@ -197,6 +197,10 @@ AC_ARG_ENABLE(watchquagga,
+ [  --disable-watchquagga   do not build watchquagga])
+ AC_ARG_ENABLE(isisd,
+ [  --enable-isisd          build isisd])
++AC_ARG_ENABLE(trill,
++[  --enable-trill          include TRILL support])
++AC_ARG_ENABLE(solaris,
++[  --enable-solaris          build solaris])
+ AC_ARG_ENABLE(bgp-announce,
+ [  --disable-bgp-announce, turn off BGP route announcement])
+ AC_ARG_ENABLE(netlink,
+@@ -311,6 +315,30 @@ AC_SUBST(ISIS_TOPOLOGY_INCLUDES)
+ AC_SUBST(ISIS_TOPOLOGY_DIR)
+ AC_SUBST(ISIS_TOPOLOGY_LIB)
+ 
++if test "${enable_trill}" = "yes"; then
++  AC_CHECK_HEADER(net/trill.h)
++  AC_CHECK_LIB(dladm, dladm_valid_bridgename, libdladm=yes)
++  AC_MSG_CHECKING(TRILL IS-IS support)
++  if test $ac_cv_header_net_trill_h = no || \
++    test $ac_cv_lib_dladm_dladm_valid_bridgename = no; then
++    AC_MSG_RESULT(none)
++    AC_MSG_WARN([*** TRILL IS-IS support will not be built ***])
++    enable_trill=no
++  else
++    AC_MSG_RESULT(yes)
++    AC_DEFINE(HAVE_TRILL,,Enable TRILL support)
++  fi
++fi
++if test "${enable_trill}" = "yes"; then
++  ISIS_TARGETS="isisd trilld"
++  ISIS_LIBS=-ldladm
++else
++  ISIS_TARGETS="isisd"
++  ISIS_LIBS=
++fi
++AC_SUBST(ISIS_TARGETS)
++AC_SUBST(ISIS_LIBS)
++
+ if test "${enable_user}" = "yes" || test x"${enable_user}" = x""; then
+   enable_user="quagga"
+ elif test "${enable_user}" = "no"; then
+@@ -753,28 +781,31 @@ AC_SUBST(OTHER_METHOD)
+ dnl --------------------------
+ dnl Determine IS-IS I/O method
+ dnl --------------------------
+-AC_CHECK_HEADER(net/bpf.h)
+-AC_CHECK_HEADER(sys/dlpi.h)
+-AC_MSG_CHECKING(zebra IS-IS I/O method)
+-if test x"$opsys" = x"gnu-linux"; then
+-  AC_MSG_RESULT(pfpacket)
+-  ISIS_METHOD=isis_pfpacket.o
+-elif test x"$opsys" = x"sol2-6" -o x"$opsys" = x"sol8"; then
+-  AC_MSG_RESULT(DLPI)
+-  ISIS_METHOD="isis_dlpi.o"
+-else
+-  if test $ac_cv_header_net_bpf_h = no; then
+-    if test $ac_cv_header_sys_dlpi_h = no; then
+-      AC_MSG_RESULT(none)
+-      AC_MSG_WARN([*** IS-IS support will not be built ***])
+-      ISISD=""
+-    else
+-      AC_MSG_RESULT(DLPI)
+-    fi
++if test "${enable_isisd}" = "yes"; then
++  ISIS_METHOD=
++  AC_CHECK_HEADER(net/bpf.h)
++  AC_CHECK_HEADER(sys/dlpi.h)
++  AC_MSG_CHECKING(zebra IS-IS I/O method)
++  if test x"$opsys" = x"gnu-linux"; then
++    AC_MSG_RESULT(pfpacket)
++    ISIS_METHOD=isis_pfpacket.o
++  elif test x"$opsys" = x"sol2-6" -o x"$opsys" = x"sol8"; then
++    AC_MSG_RESULT(DLPI)
+     ISIS_METHOD="isis_dlpi.o"
+   else
+-    AC_MSG_RESULT(BPF)
+-    ISIS_METHOD="isis_bpf.o"
++    if test $ac_cv_header_net_bpf_h = no; then
++      if test $ac_cv_header_sys_dlpi_h = no; then
++	AC_MSG_RESULT(none)
++	AC_MSG_WARN([*** IS-IS support will not be built ***])
++	ISISD=""
++      else
++	AC_MSG_RESULT(DLPI)
++      fi
++      ISIS_METHOD="isis_dlpi.o"
++    else
++      AC_MSG_RESULT(BPF)
++      ISIS_METHOD="isis_bpf.o"
++    fi
+   fi
+ fi
+ AC_SUBST(ISIS_METHOD)
+diff --git isisd/Makefile.am isisd/Makefile.am
+index 859facd..9adcc05 100644
+--- isisd/Makefile.am
++++ isisd/Makefile.am
+@@ -4,10 +4,11 @@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib \
+ 	   @ISIS_TOPOLOGY_INCLUDES@
+ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+ INSTALL_SDATA=@INSTALL@ -m 600
+-LIBS = @LIBS@ 
++LIBS = @LIBS@ @ISIS_LIBS@
+ noinst_LIBRARIES = libisis.a
+-sbin_PROGRAMS = isisd 
++sbin_PROGRAMS = @ISIS_TARGETS@
+ SUBDIRS = topology
++EXTRA_PROGRAMS = isisd trilld
+ 
+ isis_method = @ISIS_METHOD@
+ 
+@@ -23,16 +24,24 @@ noinst_HEADERS = \
+ 	isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \
+ 	isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \
+ 	iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_route.h \
++	isis_trill.h \
+ 	include-netbsd/clnp.h include-netbsd/esis.h include-netbsd/iso.h
+ 
+ isisd_SOURCES = \
+-	isis_main.c $(libisis_a_SOURCES)
++	isis_main.c $(libisis_a_SOURCES) isis_trilldummy.c
+ 
+-isisd_LDADD = $(isis_method) @ISIS_TOPOLOGY_LIB@ ../lib/libzebra.la @LIBCAP@
++isisd_LDADD = $(isis_method) @ISIS_TOPOLOGY_LIB@ ../lib/libzebra.la @LIBCAP@ @LIBM@
+ 
+ isisd_DEPENDENCIES = $(isis_method)
+ 
+-EXTRA_DIST = isis_bpf.c isis_dlpi.c isis_pfpacket.c
++trilld_SOURCES = \
++	isis_main.c $(libisis_a_SOURCES) isis_trill.c isis_trillio.c \
++	isis_trillvlans.c isis_trillbpdu.c
++
++trilld_LDADD = @ISIS_TOPOLOGY_LIB@ ../lib/libzebra.la @LIBCAP@ @LIBM@
++
++EXTRA_DIST = isis_bpf.c isis_dlpi.c isis_pfpacket.c isis_trill.c \
++	isis_trillio.c isis_trillvlans.c isis_trillbpdu.c
+ 
+ examplesdir = $(exampledir)
+ dist_examples_DATA = isisd.conf.sample
+diff --git isisd/bool.h isisd/bool.h
+new file mode 100644
+index 0000000..e713d65
+--- /dev/null
++++ isisd/bool.h
+@@ -0,0 +1,25 @@
++/*
++ * IS-IS Rout(e)ing protocol               - bool.h
++ *
++ * This program is free software; you can redistribute it and/or modify it 
++ * under the terms of the GNU General Public Licenseas published by the Free 
++ * Software Foundation; either version 2 of the License, or (at your option) 
++ * any later version.
++ *
++ * This program 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 this program; if not, write to the Free Software Foundation, Inc., 
++ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ */
++
++#ifndef _ZEBRA_ISIS_BOOL_H
++#define _ZEBRA_ISIS_BOOL_H
++
++#define FALSE 0
++#define TRUE 1
++
++#endif
+diff --git isisd/dict.h isisd/dict.h
+index 9395d1c..0a5382c 100644
+--- isisd/dict.h
++++ isisd/dict.h
+@@ -124,6 +124,11 @@ extern void dict_load_next(dict_load_t *, dnode_t *, const void *);
+ extern void dict_load_end(dict_load_t *);
+ extern void dict_merge(dict_t *, dict_t *);
+ 
++#define ALL_DICT_NODES_RO(D,dnode,data) \
++  (dnode) = dict_first((D)); \
++  (dnode) != NULL && ((data) = dnode_get((dnode)), 1); \
++  (dnode) = dict_next((D),(dnode))
++
+ #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
+ #ifdef KAZLIB_SIDEEFFECT_DEBUG
+ #define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount)
+diff --git isisd/isis_adjacency.c isisd/isis_adjacency.c
+index aab8d1a..4b2159b 100644
+--- isisd/isis_adjacency.c
++++ isisd/isis_adjacency.c
+@@ -43,6 +43,9 @@
+ #include "isisd/isis_dr.h"
+ #include "isisd/isis_dynhn.h"
+ #include "isisd/isis_pdu.h"
++#include "isisd/isis_tlv.h"
++#include "isisd/isis_lsp.h"
++#include "isisd/isis_vlans.h"
+ 
+ extern struct isis *isis;
+ 
+@@ -53,6 +56,10 @@ adj_alloc (u_char * id)
+ 
+   adj = XCALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency));
+   memcpy (adj->sysid, id, ISIS_SYS_ID_LEN);
++  adj->lsps = list_new();
++#ifdef HAVE_TRILL
++  adj->vlans = XCALLOC (MTYPE_ISIS_TRILL_ADJVLANS, sizeof (struct trill_adj_vlans));
++#endif
+ 
+   return adj;
+ }
+@@ -127,6 +134,9 @@ isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb)
+ void
+ isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb)
+ {
++  struct listnode *node;
++  struct isis_lsp *lsp;
++
+   if (!adj)
+     return;
+   /* When we recieve a NULL list, we will know its p2p. */
+@@ -141,7 +151,18 @@ isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb)
+   if (adj->ipv6_addrs)
+     list_delete (adj->ipv6_addrs);
+ #endif
+-  
++
++  /* clear adj LSPs list (tracks LSPs recvd from the adj) */
++  if (adj->lsps)
++    {
++      for (ALL_LIST_ELEMENTS_RO (adj->lsps, node, lsp))
++        lsp->adj = NULL;
++      list_delete (adj->lsps);
++    }
++
++#ifdef HAVE_VLAN
++  XFREE (MTYPE_ISIS_TRILL_ADJVLANS, adj->vlans);
++#endif
+   XFREE (MTYPE_ISIS_ADJACENCY, adj);
+   return;
+ }
+@@ -179,6 +200,10 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,
+       list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
+       isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
+ 				 circuit->u.bc.lan_neighs[level - 1]);
++
++      /* On adjacency state change send new pseudo LSP if we are the DR */
++      if (circuit->u.bc.is_dr[level - 1])
++        lsp_pseudo_regenerate (circuit, level);
+     }
+   else if (state == ISIS_ADJ_UP)
+     {				/* p2p interface */
+@@ -302,6 +327,11 @@ isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
+   struct isis_dynhn *dyn;
+   int level;
+   struct listnode *node;
++#ifdef HAVE_TRILL
++  int vlan_count = 0;
++  int vlan_set;
++  int vlan;
++#endif
+ 
+   dyn = dynhn_find_by_id (adj->sysid);
+   if (dyn)
+@@ -388,6 +418,38 @@ isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
+ 	    }
+ 	}
+ #endif /* HAVE_IPV6 */
++
++#ifdef HAVE_TRILL
++      vty_out (vty, "    Designated VLAN: %d", adj->vlans->designated);
++      vty_out (vty, "%s    VLAN Forwarder: ", VTY_NEWLINE);
++      EACH_VLAN_SET(adj->vlans->forwarder, vlan, vlan_set)
++        {
++	   vlan_count++;
++	   if (vlan_count % 8 == 0)
++             vty_out(vty, "%s                     ", VTY_NEWLINE);
++           vty_out (vty, "%d ", vlan); 
++        }
++      vty_out (vty, "%s    Enabled VLANs: ", VTY_NEWLINE);
++      vlan_count = 0;
++      EACH_VLAN_SET(adj->vlans->enabled, vlan, vlan_set)
++        {
++	   vlan_count++;
++	   if (vlan_count % 8 == 0)
++             vty_out(vty, "%s                     ", VTY_NEWLINE);
++           vty_out (vty, "%d ", vlan); 
++        }
++      vty_out (vty, "%s    Rx VLANs: ", VTY_NEWLINE);
++      vlan_count = 0;
++      EACH_VLAN_SET(adj->vlans->seen, vlan, vlan_set)
++        {
++	   vlan_count++;
++	   if (vlan_count % 8 == 0)
++             vty_out(vty, "%s                     ", VTY_NEWLINE);
++           vty_out (vty, "%d ", vlan); 
++        }
++      vty_out (vty, "%s", VTY_NEWLINE);
++#endif /* HAVE_TRILL */
++
+       vty_out (vty, "%s", VTY_NEWLINE);
+     }
+   return;
+diff --git isisd/isis_adjacency.h isisd/isis_adjacency.h
+index 99a8bb2..b966230 100644
+--- isisd/isis_adjacency.h
++++ isisd/isis_adjacency.h
+@@ -96,6 +96,11 @@ struct isis_adjacency
+   int flaps;			/* number of adjacency flaps  */
+   struct thread *t_expire;	/* expire after hold_time  */
+   struct isis_circuit *circuit;	/* back pointer */
++  struct list *lsps;		/* LSPs marked with this adjacency */
++
++#ifdef HAVE_TRILL
++  struct trill_adj_vlans *vlans;
++#endif
+ };
+ 
+ struct isis_adjacency *isis_adj_lookup (u_char * sysid, struct list *adjdb);
+diff --git isisd/isis_circuit.c isisd/isis_circuit.c
+index af24988..8de3622 100644
+--- isisd/isis_circuit.c
++++ isisd/isis_circuit.c
+@@ -58,6 +58,11 @@
+ #include "isisd/isis_csm.h"
+ #include "isisd/isis_events.h"
+ 
++#ifdef HAVE_TRILL
++#include "isisd/isis_vlans.h"
++#include "isisd/isis_trill.h"
++#endif
++
+ extern struct thread_master *master;
+ extern struct isis *isis;
+ 
+@@ -87,6 +92,11 @@ isis_circuit_new ()
+ 	  circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED;
+ 	  circuit->te_metric[i] = DEFAULT_CIRCUIT_METRICS;
+ 	}
++
++#ifdef HAVE_TRILL
++      circuit->vlans = XCALLOC (MTYPE_ISIS_TRILL_VLANS,
++          sizeof(struct trill_circuit_vlans));
++#endif
+     }
+   else
+     {
+@@ -126,6 +136,13 @@ isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area)
+     }
+   circuit->lsp_interval = LSP_INTERVAL;
+ 
++#ifdef HAVE_TRILL
++  circuit->vlans->pvid = DFLT_VLAN;
++  circuit->vlans->designated = DFLT_VLAN;
++  circuit->vlans->our_designated = DFLT_VLAN;
++  SET_VLAN(circuit->vlans->enabled, DFLT_VLAN);
++#endif
++
+   /*
+    * Add the circuit into area
+    */
+@@ -216,6 +233,26 @@ isis_circuit_del (struct isis_circuit *circuit)
+     list_delete (circuit->ipv6_non_link);
+ #endif /* HAVE_IPV6 */
+ 
++#ifdef HAVE_TRILL
++  if (circuit->vlans != NULL)
++    {
++      struct trill_circuit_vlans *cvlans = circuit->vlans;
++
++      if (cvlans->appvlanfwders != NULL)
++	list_delete (cvlans->appvlanfwders);
++      if (cvlans->enabled_vlans != NULL)
++	list_delete (cvlans->enabled_vlans);
++      if (cvlans->inhibit_vlans != NULL)
++	list_delete (cvlans->inhibit_vlans);
++      if (cvlans->inhibit_thread != NULL)
++	thread_cancel (cvlans->inhibit_thread);
++      XFREE (MTYPE_ISIS_TRILL_VLANS, cvlans);
++    }
++
++  if (circuit->tc_thread != NULL)
++    thread_cancel (circuit->tc_thread);
++#endif
++
+   /* and lastly the circuit itself */
+   XFREE (MTYPE_ISIS_CIRCUIT, circuit);
+ 
+@@ -374,7 +411,7 @@ isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp)
+   circuit->interface = ifp;
+   ifp->info = circuit;
+ 
+-  circuit->circuit_id = ifp->ifindex % 255;	/* FIXME: Why not ? */
++  circuit->circuit_id = (ifp->ifindex % 255) + 1; /* FIXME: Why not ? */
+ 
+   /*  isis_circuit_update_addrs (circuit, ifp); */
+ 
+@@ -436,7 +473,7 @@ isis_circuit_update_params (struct isis_circuit *circuit,
+     {
+       zlog_warn ("changing circuit_id %d->%d", circuit->circuit_id,
+ 		 ifp->ifindex);
+-      circuit->circuit_id = ifp->ifindex % 255;
++      circuit->circuit_id = (ifp->ifindex % 255) + 1;
+     }
+ 
+   /* FIXME: Why is this needed? shouldn't we compare to the area's mtu */
+@@ -500,9 +537,10 @@ isis_circuit_if_del (struct isis_circuit *circuit)
+   return;
+ }
+ 
+-void
++int
+ isis_circuit_up (struct isis_circuit *circuit)
+ {
++  int retv;
+ 
+   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+     {
+@@ -565,43 +603,57 @@ isis_circuit_up (struct isis_circuit *circuit)
+ 		       isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
+     }
+ 
+-  /* initialize the circuit streams */
++  /* unified init for circuits; ignore warnings below this level */
++  retv = isis_sock_init (circuit);
++  if (retv == ISIS_ERROR)
++    {
++      isis_circuit_down (circuit);
++      return retv;
++    }
++
++  /* initialize the circuit streams after opening connection */
+   if (circuit->rcv_stream == NULL)
+     circuit->rcv_stream = stream_new (ISO_MTU (circuit));
+ 
+   if (circuit->snd_stream == NULL)
+     circuit->snd_stream = stream_new (ISO_MTU (circuit));
+ 
+-  /* unified init for circuits */
+-  isis_sock_init (circuit);
+-
+-#ifdef GNU_LINUX
++#if defined(GNU_LINUX) || defined(SUNOS_5)
+   THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
+ 		  circuit->fd);
+ #else
+   THREAD_TIMER_ON (master, circuit->t_read, isis_receive, circuit,
+ 		   circuit->fd);
+ #endif
+-  return;
++  return ISIS_OK;
+ }
+ 
+ void
+ isis_circuit_down (struct isis_circuit *circuit)
+ {
+   /* Cancel all active threads -- FIXME: wrong place */
+-  /* HT: Read thread if GNU_LINUX, TIMER thread otherwise. */
++  /* HT: Read thread if GNU_LINUX or SUNOS_5, TIMER thread otherwise. */
+   THREAD_OFF (circuit->t_read);
++  THREAD_TIMER_OFF (circuit->t_send_csnp[0]);
++  THREAD_TIMER_OFF (circuit->t_send_csnp[1]);
++  THREAD_TIMER_OFF (circuit->t_send_psnp[0]);
++  THREAD_TIMER_OFF (circuit->t_send_psnp[1]);
+   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+     {
+       THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[0]);
+       THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[1]);
+       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]);
+       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
++      THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[0]);
++      THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[1]);
+     }
+   else if (circuit->circ_type == CIRCUIT_T_P2P)
+     {
+       THREAD_TIMER_OFF (circuit->u.p2p.t_send_p2p_hello);
+     }
++#ifdef HAVE_TRILL
++  THREAD_TIMER_OFF (circuit->tc_thread);
++#endif
+   /* close the socket */
+   close (circuit->fd);
+ 
+diff --git isisd/isis_circuit.h isisd/isis_circuit.h
+index a7e719f..fd26a27 100644
+--- isisd/isis_circuit.h
++++ isisd/isis_circuit.h
+@@ -137,6 +137,14 @@ struct isis_circuit
+   u_int32_t ctrl_pdus_txed;	/* controlPDUsSent */
+   u_int32_t desig_changes[2];	/* lanLxDesignatedIntermediateSystemChanges */
+   u_int32_t rej_adjacencies;	/* rejectedAdjacencies */
++
++#ifdef HAVE_TRILL
++  struct trill_circuit_vlans *vlans;	/* TRILL VLANs */
++  u_int8_t root_bridge[8];		/* STP Root Bridge */
++  time_t root_expire;			/* time when root expires */
++  int tc_count;
++  struct thread *tc_thread;
++#endif
+ };
+ 
+ void isis_circuit_init (void);
+@@ -147,7 +155,7 @@ struct isis_circuit *circuit_scan_by_ifp (struct interface *ifp);
+ void isis_circuit_del (struct isis_circuit *circuit);
+ void isis_circuit_configure (struct isis_circuit *circuit,
+ 			     struct isis_area *area);
+-void isis_circuit_up (struct isis_circuit *circuit);
++int isis_circuit_up (struct isis_circuit *circuit);
+ void isis_circuit_deconfigure (struct isis_circuit *circuit,
+ 			       struct isis_area *area);
+ 
+diff --git isisd/isis_common.h isisd/isis_common.h
+index 2633855..29baf1e 100644
+--- isisd/isis_common.h
++++ isisd/isis_common.h
+@@ -21,6 +21,9 @@
+  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  */
+ 
++#ifndef ISIS_COMMON_H
++#define ISIS_COMMON_H
++
+ /*
+  * Area Address
+  */
+@@ -72,3 +75,5 @@ struct flags
+   int maxindex;
+   struct list *free_idcs;
+ };
++
++#endif
+diff --git isisd/isis_constants.h isisd/isis_constants.h
+index 1b75ba6..50a526c 100644
+--- isisd/isis_constants.h
++++ isisd/isis_constants.h
+@@ -102,6 +102,10 @@
+ #define IS_LEVEL_2       2
+ #define IS_LEVEL_1_AND_2 3
+ 
++#ifdef HAVE_TRILL
++#define TRILL_ISIS_LEVEL  IS_LEVEL_1		/* Use ISIS level 1 for TRILL */
++#endif
++
+ #define SNPA_ADDRSTRLEN 18
+ #define ISIS_SYS_ID_LEN  6
+ #define SYSID_STRLEN    24
+diff --git isisd/isis_csm.c isisd/isis_csm.c
+index 80d0c90..c5bb42d 100644
+--- isisd/isis_csm.c
++++ isisd/isis_csm.c
+@@ -110,7 +110,11 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
+ 	{
+ 	case ISIS_ENABLE:
+ 	  isis_circuit_configure (circuit, (struct isis_area *) arg);
+-	  isis_circuit_up (circuit);
++	  if (isis_circuit_up (circuit) != ISIS_OK)
++	    {
++	      isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
++	      break;
++	    }
+ 	  circuit->state = C_STATE_UP;
+ 	  isis_event_circuit_state_change (circuit, 1);
+ 	  listnode_delete (isis->init_circ_list, circuit);
+@@ -137,7 +141,11 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
+ 	  break;
+ 	case IF_UP_FROM_Z:
+ 	  isis_circuit_if_add (circuit, (struct interface *) arg);
+-	  isis_circuit_up (circuit);
++	  if (isis_circuit_up (circuit) != ISIS_OK)
++	    {
++	      isis_circuit_if_del (circuit);
++	      break;
++	    }
+ 	  circuit->state = C_STATE_UP;
+ 	  isis_event_circuit_state_change (circuit, 1);
+ 	  break;
+@@ -161,12 +169,14 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
+ 	  zlog_warn ("circuit already connected");
+ 	  break;
+ 	case ISIS_DISABLE:
++	  isis_circuit_down (circuit);
+ 	  isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
+ 	  listnode_add (isis->init_circ_list, circuit);
+ 	  circuit->state = C_STATE_INIT;
+ 	  isis_event_circuit_state_change (circuit, 0);
+ 	  break;
+ 	case IF_DOWN_FROM_Z:
++	  isis_circuit_down (circuit);
+ 	  isis_circuit_if_del (circuit);
+ 	  circuit->state = C_STATE_CONF;
+ 	  isis_event_circuit_state_change (circuit, 0);
+diff --git isisd/isis_dlpi.c isisd/isis_dlpi.c
+index 07ab547..5837201 100644
+--- isisd/isis_dlpi.c
++++ isisd/isis_dlpi.c
+@@ -21,6 +21,8 @@
+  */
+ 
+ #include <zebra.h>
++#include <vty.h>
++
+ #include <net/if.h>
+ #include <netinet/if_ether.h>
+ #include <sys/types.h>
+@@ -301,7 +303,7 @@ dlpiaddr (int fd, u_char *addr)
+ static int
+ open_dlpi_dev (struct isis_circuit *circuit)
+ {
+-  int fd, unit, retval;
++  int fd = -1, unit, retval;
+   char devpath[MAXPATHLEN];
+   dl_info_ack_t *dia = (dl_info_ack_t *)dlpi_ctl;
+   ssize_t acklen;
+@@ -313,20 +315,21 @@ open_dlpi_dev (struct isis_circuit *circuit)
+ 	circuit->interface->name);
+       return ISIS_WARNING;
+     }
+-  
++
++  /* Try first as Style 1 */
+   /* Try the vanity node first, if permitted */
+   if (getenv("DLPI_DEVONLY") == NULL)
+     {
+-      (void) snprintf (devpath, sizeof(devpath), "/dev/net/%s",
+-                      circuit->interface->name);
+-      fd = dlpiopen (devpath, &acklen);
++      (void) snprintf(devpath, sizeof(devpath), "/dev/net/%s",
++        circuit->interface->name);
++      fd = dlpiopen(devpath, &acklen);
+     }
+-  
++
+   /* Now try as an ordinary Style 1 node */
+   if (fd == -1)
+     {
+-      (void) snprintf (devpath, sizeof (devpath), "/dev/%s",
+-                      circuit->interface->name);
++      (void) snprintf(devpath, sizeof (devpath), "/dev/%s",
++        circuit->interface->name);
+       unit = -1;
+       fd = dlpiopen (devpath, &acklen);
+     }
+@@ -402,8 +405,8 @@ open_dlpi_dev (struct isis_circuit *circuit)
+     case DL_100BT:
+       break;
+     default:
+-      zlog_warn ("%s: unexpected mac type on %s: %d", __func__,
+-	circuit->interface->name, dia->dl_mac_type);
++      zlog_warn ("%s: unexpected mac type on %s: %ld", __func__,
++	circuit->interface->name, (u_long)dia->dl_mac_type);
+       close (fd);
+       return ISIS_WARNING;
+     }
+@@ -471,9 +474,9 @@ open_dlpi_dev (struct isis_circuit *circuit)
+       sioc.ic_timout = 5;
+       sioc.ic_len = sizeof (struct packetfilt);
+       sioc.ic_dp = (char *)&pfil;
+-      if (ioctl (fd, I_STR, &sioc) == -1)
++      if (ioctl (fd, I_STR, &sioc) == -1) 
+          zlog_warn("%s: could not perform PF_IOCSETF on %s",
+-           __func__, circuit->interface->name);
++   	    __func__, circuit->interface->name);
+     }
+ 
+   circuit->fd = fd;
+diff --git isisd/isis_dr.c isisd/isis_dr.c
+index 8d306c8..a481142 100644
+--- isisd/isis_dr.c
++++ isisd/isis_dr.c
+@@ -207,17 +207,16 @@ isis_dr_elect (struct isis_circuit *circuit, int level)
+       || (adj_dr->prio[level - 1] == own_prio
+ 	  && memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0))
+     {
+-      if (!circuit->u.bc.is_dr[level - 1])
+-	{
+-	  /*
+-	   * We are the DR
+-	   */
++      adj_dr->dis_record[level - 1].dis = ISIS_IS_NOT_DIS;
++      adj_dr->dis_record[level - 1].last_dis_change = time (NULL);
+ 
+-	  /* rotate the history log */
+-	  for (ALL_LIST_ELEMENTS_RO (list, node, adj))
+-            isis_check_dr_change (adj, level);
++      /* rotate the history log */
++      for (ALL_LIST_ELEMENTS_RO (list, node, adj))
++        isis_check_dr_change (adj, level);
+ 
+-	  /* commence */
++      if (!circuit->u.bc.is_dr[level - 1])
++	{
++	  /* We are the DR, commence DR */
+ 	  list_delete (list);
+ 	  return isis_dr_commence (circuit, level);
+ 	}
+diff --git isisd/isis_flags.h isisd/isis_flags.h
+index 13dd9e1..4346eb7 100644
+--- isisd/isis_flags.h
++++ isisd/isis_flags.h
+@@ -27,6 +27,7 @@
+ /* The grand plan is to support 1024 circuits so we have 32*32 bit flags
+  * the support will be achived using the newest drafts */
+ #define ISIS_MAX_CIRCUITS 32 /* = 1024 */	/*FIXME:defined in lsp.h as well */
++#define ISIS_MAX_CIRCUITS_COUNT 32 * ISIS_MAX_CIRCUITS  /* total count of max circuits */
+ 
+ void flags_initialize (struct flags *flags);
+ struct flags *new_flags (int size);
+diff --git isisd/isis_lsp.c isisd/isis_lsp.c
+index 48e3147..53430a7 100644
+--- isisd/isis_lsp.c
++++ isisd/isis_lsp.c
+@@ -38,17 +38,22 @@
+ #include "isisd/dict.h"
+ #include "isisd/isis_constants.h"
+ #include "isisd/isis_common.h"
++#include "isisd/isis_flags.h"
+ #include "isisd/isis_circuit.h"
+-#include "isisd/isisd.h"
+ #include "isisd/isis_tlv.h"
+ #include "isisd/isis_lsp.h"
++#ifdef HAVE_TRILL
++#include "isisd/isis_vlans.h"
++#include "isisd/isis_trill.h"
++#endif
++#include "isisd/isisd.h"
+ #include "isisd/isis_pdu.h"
+ #include "isisd/isis_dynhn.h"
+ #include "isisd/isis_misc.h"
+-#include "isisd/isis_flags.h"
+ #include "isisd/isis_csm.h"
+ #include "isisd/isis_adjacency.h"
+ #include "isisd/isis_spf.h"
++#include "isisd/bool.h"
+ 
+ #ifdef TOPOLOGY_GENERATE
+ #include "spgrid.h"
+@@ -138,18 +143,34 @@ lsp_clear_data (struct isis_lsp *lsp)
+   if (lsp->tlv_data.ipv6_reachs)
+     list_delete (lsp->tlv_data.ipv6_reachs);
+ #endif /* HAVE_IPV6 */
++  if (lsp->tlv_data.router_capabilities)
++    list_delete (lsp->tlv_data.router_capabilities);
+ 
+   memset (&lsp->tlv_data, 0, sizeof (struct tlvs));
+ 
+   return;
+ }
+ 
++/*
++ * clearnick is set by callers to indicate it is
++ * also safe to clear any nickname that was learnt from
++ * the LSP. LSP purge case is safe but LSP destroyed before
++ * replaced by a new LSP from the other RBridge is not. 
++ */
+ static void
+-lsp_destroy (struct isis_lsp *lsp)
++lsp_destroy (struct isis_lsp *lsp, int clearnick)
+ {
+   if (!lsp)
+     return;
+ 
++#ifdef HAVE_TRILL
++  if (clearnick)
++    trill_nick_destroy(lsp);
++#endif
++
++  if (lsp->adj != NULL && lsp->adj->lsps != NULL)
++    listnode_delete(lsp->adj->lsps, lsp);
++
+   lsp_clear_data (lsp);
+ 
+   if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags)
+@@ -173,7 +194,7 @@ lsp_db_destroy (dict_t * lspdb)
+     {
+       next = dict_next (lspdb, dnode);
+       lsp = dnode_get (dnode);
+-      lsp_destroy (lsp);
++      lsp_destroy (lsp, TRUE);
+       dict_delete_free (lspdb, dnode);
+       dnode = next;
+     }
+@@ -187,7 +208,7 @@ lsp_db_destroy (dict_t * lspdb)
+  * Remove all the frags belonging to the given lsp
+  */
+ static void
+-lsp_remove_frags (struct list *frags, dict_t * lspdb)
++lsp_remove_frags (struct list *frags, dict_t * lspdb, int clearnick)
+ {
+   dnode_t *dnode;
+   struct listnode *lnode, *lnnode;
+@@ -196,7 +217,7 @@ lsp_remove_frags (struct list *frags, dict_t * lspdb)
+   for (ALL_LIST_ELEMENTS (frags, lnode, lnnode, lsp))
+     {
+       dnode = dict_lookup (lspdb, lsp->lsp_header->lsp_id);
+-      lsp_destroy (lsp);
++      lsp_destroy (lsp, clearnick);
+       dnode_destroy (dict_delete (lspdb, dnode));
+     }
+ 
+@@ -222,7 +243,7 @@ lsp_search_and_destroy (u_char * id, dict_t * lspdb)
+       if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0)
+ 	{
+ 	  if (lsp->lspu.frags)
+-	    lsp_remove_frags (lsp->lspu.frags, lspdb);
++	    lsp_remove_frags (lsp->lspu.frags, lspdb, FALSE);
+ 	}
+       else
+ 	{
+@@ -232,7 +253,7 @@ lsp_search_and_destroy (u_char * id, dict_t * lspdb)
+ 	  if (lsp->lspu.zero_lsp && lsp->lspu.zero_lsp->lspu.frags)
+ 	    listnode_delete (lsp->lspu.zero_lsp->lspu.frags, lsp);
+ 	}
+-      lsp_destroy (lsp);
++      lsp_destroy (lsp, FALSE);
+       dnode_destroy (node);
+     }
+ }
+@@ -314,7 +335,7 @@ lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
+     newseq = seq_num++;
+ 
+   lsp->lsp_header->seq_num = htonl (newseq);
+-  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
++  fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
+ 		   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+ 
+   return;
+@@ -367,6 +388,8 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
+   int retval;
+ 
+   /* copying only the relevant part of our stream */
++  if (lsp->pdu != NULL)
++    stream_free (lsp->pdu);
+   lsp->pdu = stream_dup (stream);
+   
+   /* setting pointers to the correct place */
+@@ -414,6 +437,10 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
+ 			   (lsp->lsp_header->lsp_bits & LSPBIT_IST));
+     }
+ 
++#ifdef HAVE_TRILL
++  if (isis->trill_active)
++    trill_parse_router_capability_tlvs (area, lsp);
++#endif
+ }
+ 
+ void
+@@ -428,7 +455,6 @@ lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr,
+     dnode_destroy (dict_delete (area->lspdb[level - 1], dnode));
+ 
+   /* free the old lsp data */
+-  XFREE (MTYPE_STREAM_DATA, lsp->pdu);
+   lsp_clear_data (lsp);
+ 
+   /* rebuild the lsp data */
+@@ -852,11 +878,9 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
+   if (lsp->tlv_data.te_is_neighs)
+     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
+     {
+-      uint32_t metric;
+-      memcpy (&metric, te_is_neigh->te_metric, 3);
+       lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
+       vty_out (vty, "  Metric: %-10d IS-Extended %s%s",
+-	       ntohl (metric << 8), LSPid, VTY_NEWLINE);
++	       GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
+     }
+ 
+   /* TE IPv4 tlv */
+@@ -933,16 +957,32 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
+   if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))
+     {
+       tlv_build_func (*from, lsp->pdu);
+-      *to = *from;
+-      *from = NULL;
++      if (listcount (*to) != 0)
++	{
++	  struct listnode *node, *nextnode;
++	  void *elem;
++
++	  for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
++	    {
++	      listnode_add (*to, elem);
++	      list_delete_node (*from, node);
++	    }
++	}
++      else
++	{
++	  list_free (*to);
++	  *to = *from;
++	  *from = NULL;
++	}
+     }
+   else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2))
+     {
+       /* fit all we can */
+       count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
+ 	(STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
+-      if (count)
+-	count = count / tlvsize;
++      count = count / tlvsize;
++      if (count > (int)listcount (*from))
++	count = listcount (*from);
+       for (i = 0; i < count; i++)
+ 	{
+ 	  listnode_add (*to, listgetdata (listhead (*from)));
+@@ -972,7 +1012,7 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
+       lsp_clear_data (lsp);
+       if (lsp0->tlv_data.auth_info.type)
+ 	{
+-	  memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,
++	  memcpy (&lsp->tlv_data.auth_info, &lsp0->tlv_data.auth_info,
+ 		  sizeof (struct isis_passwd));
+ 	  tlv_add_authinfo (lsp->tlv_data.auth_info.type,
+ 			    lsp->tlv_data.auth_info.len,
+@@ -991,7 +1031,7 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
+    */
+   if (lsp0->tlv_data.auth_info.type)
+     {
+-      memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,
++      memcpy (&lsp->tlv_data.auth_info, &lsp0->tlv_data.auth_info,
+ 	      sizeof (struct isis_passwd));
+       tlv_add_authinfo (lsp->tlv_data.auth_info.type,
+ 			lsp->tlv_data.auth_info.len,
+@@ -1094,6 +1134,11 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
+   if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0)
+     tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
+ 
++#ifdef HAVE_TRILL
++  if (isis->trill_active && CHECK_FLAG (area->trill->status, TRILL_NICK_SET))
++      tlv_add_trill_nickname (&(area->trill->nick), lsp->pdu, area);
++#endif
++
+   /* IPv4 address and TE router ID TLVs. In case of the first one we don't
+    * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into
+    * LSP and this address is same as router id. */
+@@ -1281,13 +1326,11 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
+ 		    memcpy (te_is_neigh->neigh_id,
+ 			    circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
+ 		  if (area->oldmetric)
+-		    metric =
+-		      ((htonl(circuit->metrics[level - 1].metric_default) >> 8)
+-			      & 0xffffff);
++		    metric = circuit->metrics[level - 1].metric_default;
+ 		  else
+-		    metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff);
++		    metric = circuit->te_metric[level - 1];
+ 
+-		  memcpy (te_is_neigh->te_metric, &metric, 3);
++		  SET_TE_METRIC(te_is_neigh, metric);
+ 		  listnode_add (tlv_data.te_is_neighs, te_is_neigh);
+ 		}
+ 	    }
+@@ -1320,8 +1363,8 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
+ 		  te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
+ 					 sizeof (struct te_is_neigh));
+ 		  memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
+-		  metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff);
+-		  memcpy (te_is_neigh->te_metric, &metric, 3);
++		  metric = circuit->te_metric[level - 1];
++		  SET_TE_METRIC(te_is_neigh, metric);
+ 		  listnode_add (tlv_data.te_is_neighs, te_is_neigh);
+ 		}
+ 	    }
+@@ -1539,6 +1582,10 @@ lsp_non_pseudo_regenerate (struct isis_area *area, int level)
+   if (area->ipv6_circuits)
+     isis_spf_schedule6 (area, level);
+ #endif
++#ifdef HAVE_TRILL
++  if (isis->trill_active)
++    isis_spf_schedule_trill (area);
++#endif
+   return ISIS_OK;
+ }
+ 
+@@ -1803,7 +1850,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
+     tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
+ 
+   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
+-  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
++  fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
+ 		   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+ 
+   list_delete (adj_list);
+@@ -1811,7 +1858,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
+   return;
+ }
+ 
+-static int
++int
+ lsp_pseudo_regenerate (struct isis_circuit *circuit, int level)
+ {
+   dict_t *lspdb = circuit->area->lspdb[level - 1];
+@@ -2022,8 +2069,8 @@ lsp_tick (struct thread *thread)
+ 		  if (lsp->from_topology)
+ 		    THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
+ #endif /* TOPOLOGY_GENERATE */
+-		  lsp_destroy (lsp);
+-		  dict_delete (area->lspdb[level], dnode);
++		  lsp_destroy (lsp, TRUE);
++		  dict_delete_free (area->lspdb[level], dnode);
+ 		}
+ 	      else if (flags_any_set (lsp->SRMflags))
+ 		listnode_add (lsp_list, lsp);
+@@ -2071,7 +2118,7 @@ lsp_purge_dr (u_char * id, struct isis_circuit *circuit, int level)
+       lsp->lsp_header->pdu_len =
+ 	htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+       lsp->purged = 0;
+-      fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
++      fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
+ 		       ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+       ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+     }
+@@ -2227,7 +2274,7 @@ remove_topology_lsps (struct isis_area *area)
+       if (lsp->from_topology)
+ 	{
+ 	  THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
+-	  lsp_destroy (lsp);
++	  lsp_destroy (lsp, TRUE);
+ 	  dict_delete (area->lspdb[0], dnode);
+ 	}
+       dnode = dnode_next;
+@@ -2325,8 +2372,6 @@ build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,
+ 
+       if (area->newmetric)
+ 	{
+-	  uint32_t metric;
+-
+ 	  if (tlv_data.te_is_neighs == NULL)
+ 	    {
+ 	      tlv_data.te_is_neighs = list_new ();
+@@ -2337,8 +2382,7 @@ build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,
+ 		  ISIS_SYS_ID_LEN);
+ 	  te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
+ 	  te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
+-	  metric = ((htonl(arc->distance) >> 8) & 0xffffff);
+-	  memcpy (te_is_neigh->te_metric, &metric, 3);
++	  SET_TE_METRIC(te_is_neigh, arc->distance);
+ 	  listnode_add (tlv_data.te_is_neighs, te_is_neigh);
+ 	}
+     }
+diff --git isisd/isis_lsp.h isisd/isis_lsp.h
+index adbde78..4112681 100644
+--- isisd/isis_lsp.h
++++ isisd/isis_lsp.h
+@@ -74,6 +74,7 @@ int lsp_refresh_l1 (struct thread *thread);
+ int lsp_refresh_l2 (struct thread *thread);
+ int lsp_regenerate_schedule (struct isis_area *area);
+ 
++int lsp_pseudo_regenerate (struct isis_circuit *circuit, int level);
+ int lsp_l1_pseudo_generate (struct isis_circuit *circuit);
+ int lsp_l2_pseudo_generate (struct isis_circuit *circuit);
+ int lsp_l1_refresh_pseudo (struct thread *thread);
+diff --git isisd/isis_main.c isisd/isis_main.c
+index 2411518..a75281d 100644
+--- isisd/isis_main.c
++++ isisd/isis_main.c
+@@ -43,6 +43,14 @@
+ #include "isisd/isis_circuit.h"
+ #include "isisd/isisd.h"
+ #include "isisd/isis_dynhn.h"
++#include "isisd/isis_spf.h"
++#include "isisd/isis_route.h"
++#include "isisd/isis_zebra.h"
++#ifdef HAVE_TRILL
++#include "isisd/isis_tlv.h"
++#include "isisd/isis_vlans.h"
++#include "isisd/isis_trill.h"
++#endif
+ 
+ /* Default configuration file name */
+ #define ISISD_DEFAULT_CONFIG "isisd.conf"
+@@ -51,8 +59,12 @@
+ 
+ /* isisd privileges */
+ zebra_capabilities_t _caps_p[] = {
++#ifdef HAVE_TRILL
++  ZCAP_DL_CONFIG,
++#endif
+   ZCAP_NET_RAW,
+-  ZCAP_BIND
++  ZCAP_BIND,
++  ZCAP_EXEC
+ };
+ 
+ struct zebra_privs_t isisd_privs = {
+@@ -66,7 +78,7 @@ struct zebra_privs_t isisd_privs = {
+   .vty_group = VTY_GROUP,
+ #endif
+   .caps_p = _caps_p,
+-  .cap_num_p = 2,
++  .cap_num_p = sizeof (_caps_p) / sizeof (*_caps_p),
+   .cap_num_i = 0
+ };
+ 
+@@ -151,7 +163,10 @@ reload ()
+   zlog_debug ("Reload");
+   /* FIXME: Clean up func call here */
+   vty_reset ();
++  (void) isisd_privs.change (ZPRIVS_RAISE);
+   execve (_progpath, _argv, _envp);
++  zlog_err ("Reload failed: cannot exec %s: %s", _progpath,
++      safe_strerror (errno));
+ }
+ 
+ static void
+@@ -168,6 +183,9 @@ void
+ sighup (void)
+ {
+   zlog_debug ("SIGHUP received");
++#ifdef HAVE_TRILL
++  if (!trill_reload())
++#endif
+   reload ();
+ 
+   return;
+@@ -227,6 +245,11 @@ main (int argc, char **argv, char **envp)
+   char *vty_addr = NULL;
+   int dryrun = 0;
+ 
++#if defined(__sparc) && __GNUC__ == 3
++  /* work around alignment problems in gcc 3.x on SPARC */
++  asm("ta\t6");
++#endif
++
+   /* Get the programname without the preceding path. */
+   progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+ 
+@@ -319,6 +342,22 @@ main (int argc, char **argv, char **envp)
+   memory_init ();
+   access_list_init();
+   isis_init ();
++  isis_circuit_init ();
++  isis_spf_cmds_init ();
++#ifdef HAVE_TRILL
++  install_trill_elements ();
++#endif
++
++  /* create the global 'isis' instance */
++  isis_new (0);
++
++#ifdef HAVE_TRILL
++  trill_read_config (&config_file, argc, argv);
++  /* we use the routing socket (zebra) only if TRILL is not enabled */
++  if (!isis->trill_active)
++#endif
++  isis_zebra_init ();
++
+   dyn_cache_init ();
+   sort_node ();
+ 
+@@ -337,7 +376,8 @@ main (int argc, char **argv, char **envp)
+     daemon (0, 0);
+ 
+   /* Process ID file creation. */
+-  pid_output (pid_file);
++  if (pid_file[0] != '\0')
++    pid_output (pid_file);
+ 
+   /* Make isis vty socket. */
+   vty_serv_sock (vty_addr, vty_port, ISIS_VTYSH_PATH);
+diff --git isisd/isis_misc.c isisd/isis_misc.c
+index 6b565bc..dbfb601 100644
+--- isisd/isis_misc.c
++++ isisd/isis_misc.c
+@@ -29,6 +29,7 @@
+ #include "if.h"
+ #include "command.h"
+ 
++#include "isisd/bool.h"
+ #include "isisd/dict.h"
+ #include "isisd/isis_constants.h"
+ #include "isisd/isis_common.h"
+@@ -38,8 +39,12 @@
+ 
+ #include "isisd/isis_tlv.h"
+ #include "isisd/isis_lsp.h"
++#include "isisd/isis_flags.h"
++#include "isisd/isis_vlans.h"
++#include "isisd/isis_trill.h"
+ #include "isisd/isis_constants.h"
+ #include "isisd/isis_adjacency.h"
++#include "isisd/isis_dynhn.h"
+ 
+ /* staticly assigned vars for printing purposes */
+ struct in_addr new_prefix;
+@@ -99,10 +104,10 @@ isonet_print (u_char * from, int len)
+  * extract dot from the dotted str, and insert all the number in a buff 
+  */
+ int
+-dotformat2buff (u_char * buff, const u_char * dotted)
++dotformat2buff (u_char * buff, const char * dotted)
+ {
+   int dotlen, len = 0;
+-  const u_char *pos = dotted;
++  const char *pos = dotted;
+   u_char number[3];
+   int nextdotpos = 2;
+ 
+@@ -157,10 +162,10 @@ dotformat2buff (u_char * buff, const u_char * dotted)
+  * conversion of XXXX.XXXX.XXXX to memory
+  */
+ int
+-sysid2buff (u_char * buff, const u_char * dotted)
++sysid2buff (u_char * buff, const char * dotted)
+ {
+   int len = 0;
+-  const u_char *pos = dotted;
++  const char *pos = dotted;
+   u_char number[3];
+ 
+   number[2] = '\0';
+@@ -254,6 +259,11 @@ speaks (struct nlpids *nlpids, int family)
+ {
+   int i, speaks = 0;
+ 
++#ifdef HAVE_TRILL
++  /* TRILL has no nlpid defined */
++  if (family == AF_TRILL && isis->trill_active)
++    return TRUE;
++#endif
+   if (nlpids == (struct nlpids *) NULL)
+     return speaks;
+   for (i = 0; i < nlpids->count; i++)
+@@ -271,7 +281,7 @@ speaks (struct nlpids *nlpids, int family)
+  * Returns 0 on error, IS-IS Circuit Type on ok
+  */
+ int
+-string2circuit_t (const u_char * str)
++string2circuit_t (const char * str)
+ {
+ 
+   if (!str)
+@@ -498,7 +508,6 @@ unix_hostname (void)
+ {
+   static struct utsname names;
+   const char *hostname;
+-  extern struct host host;
+ 
+   hostname = host.name;
+   if (!hostname)
+@@ -509,3 +518,26 @@ unix_hostname (void)
+ 
+   return hostname;
+ }
++
++/*
++ * Returns the dynamic hostname associated with the passed system ID.
++ * If no dynamic hostname found then returns formatted system ID.
++ */
++const char *
++print_sys_hostname (u_char *sysid)
++{
++  struct isis_dynhn *dyn;
++
++  if (!sysid)
++    return "nullsysid";
++
++  /* For our system ID return our host name */
++  if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0)
++    return unix_hostname();
++
++  dyn = dynhn_find_by_id (sysid);
++  if (dyn)
++    return (const char *)dyn->name.name;
++
++  return sysid_print (sysid);
++}
+diff --git isisd/isis_misc.h isisd/isis_misc.h
+index d5003a8..2db48aa 100644
+--- isisd/isis_misc.h
++++ isisd/isis_misc.h
+@@ -24,7 +24,7 @@
+ #ifndef _ZEBRA_ISIS_MISC_H
+ #define _ZEBRA_ISIS_MISC_H
+ 
+-int string2circuit_t (const u_char *);
++int string2circuit_t (const char *);
+ const char *circuit_t2string (int);
+ const char *syst2string (int);
+ struct in_addr newprefix2inaddr (u_char * prefix_start,
+@@ -33,8 +33,8 @@ struct in_addr newprefix2inaddr (u_char * prefix_start,
+  * Converting input to memory stored format
+  * return value of 0 indicates wrong input
+  */
+-int dotformat2buff (u_char *, const u_char *);
+-int sysid2buff (u_char *, const u_char *);
++int dotformat2buff (u_char *, const char *);
++int sysid2buff (u_char *, const char *);
+ 
+ /*
+  * Printing functions
+@@ -46,6 +46,7 @@ const char *rawlspid_print (u_char *);
+ const char *time2string (u_int32_t);
+ /* typedef struct nlpids nlpids; */
+ char *nlpid2string (struct nlpids *);
++const char *print_sys_hostname (u_char *sysid);
+ 
+ /*
+  * misc functions
+diff --git isisd/isis_pdu.c isisd/isis_pdu.c
+index 4311a90..d8573aa 100644
+--- isisd/isis_pdu.c
++++ isisd/isis_pdu.c
+@@ -52,6 +52,11 @@
+ #include "isisd/iso_checksum.h"
+ #include "isisd/isis_csm.h"
+ #include "isisd/isis_events.h"
++#ifdef HAVE_TRILL
++#include <net/trill.h>
++#include "isisd/isis_vlans.h"
++#include "isisd/isis_trill.h"
++#endif
+ 
+ extern struct thread_master *master;
+ extern struct isis *isis;
+@@ -787,9 +792,14 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
+ 
+   /*
+    * check if it's own interface ip match iih ip addrs
++   * If TRILL enabled bypass this check as IS-IS is used at layer-2
+    */
+-  if (!(found & TLVFLAG_IPV4_ADDR)
+-      || !ip_match (circuit->ip_addrs, tlvs.ipv4_addrs))
++  if (
++#ifdef HAVE_TRILL
++    !isis->trill_active &&
++#endif
++    (!(found & TLVFLAG_IPV4_ADDR)
++      || !ip_match (circuit->ip_addrs, tlvs.ipv4_addrs)))
+     {
+       zlog_debug
+ 	("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",
+@@ -884,7 +894,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
+       if (adj->adj_state != ISIS_ADJ_UP)
+ 	{
+ 	  for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
+-	    if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
++ 	    if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
+ 	    {
+ 	      isis_adj_state_change (adj, ISIS_ADJ_UP,
+ 				     "own SNPA found in LAN Neighbours TLV");
+@@ -892,6 +902,11 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
+ 	}
+     }
+ 
++#ifdef HAVE_TRILL
++  if (found & TLVFLAG_PORT_CAPABILITY && (tlvs.port_capabilities != NULL))
++    trill_process_hello(adj, tlvs.port_capabilities);
++#endif
++
+ out:
+   /* DEBUG_ADJ_PACKETS */
+   if (isis->debugs & DEBUG_ADJ_PACKETS)
+@@ -1054,6 +1069,7 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
+ 	      ((level == 2) &&
+ 	       (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1)))
+ 	    return ISIS_WARNING;	/* Silently discard */
++	  adj = circuit->u.p2p.neighbor;
+ 	}
+     }
+ dontcheckadj:
+@@ -1251,7 +1267,12 @@ dontcheckadj:
+ 	}
+     }
+   if (lsp)
+-    lsp->adj = adj;
++    {
++      /* store the adjacency in LSP and add LSP to adj's LSP list */
++      lsp->adj = adj;
++      if (adj)
++        listnode_add (adj->lsps, lsp);  
++    }
+   return retval;
+ }
+ 
+@@ -1534,7 +1555,11 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
+ 	ISIS_SET_FLAG (lsp->SRMflags, circuit);
+       }
+       /* lets free it */
+-      list_free (lsp_list);
++      list_delete (lsp_list);
++
++#ifdef HAVE_TRILL
++      trill_lspdb_acquire_event (circuit, CSNPRCV);
++#endif
+     }
+ 
+   free_tlvs (&tlvs);
+@@ -1653,6 +1678,11 @@ isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
+ 
+   int retval = ISIS_OK;
+ 
++#ifdef HAVE_TRILL
++  if (isis->trill_active && circuit->vlans->rx_tci == TRILL_TCI_BPDU)
++    return trill_process_bpdu (circuit, ssnpa);
++#endif
++
+   /*
+    * Let's first read data from stream to the header
+    */
+@@ -1767,7 +1797,7 @@ isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
+   return retval;
+ }
+ 
+-#ifdef GNU_LINUX
++#if defined(GNU_LINUX) || defined(SUNOS_5)
+ int
+ isis_receive (struct thread *thread)
+ {
+@@ -1791,6 +1821,8 @@ isis_receive (struct thread *thread)
+ 
+   if (retval == ISIS_OK)
+     retval = isis_handle_pdu (circuit, ssnpa);
++  else
++    zlog_debug("isis_receive: error %d from circuit->rx", retval);
+ 
+   /* 
+    * prepare for next packet. 
+@@ -1879,6 +1911,10 @@ fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type)
+   hdr->id_len = 0;		/* ISIS_SYS_ID_LEN -  0==6 */
+   hdr->version2 = 1;
+   hdr->max_area_addrs = 0;	/* isis->max_area_addrs -  0==3 */
++#ifdef HAVE_TRILL
++  if (isis->trill_active)
++    hdr->max_area_addrs = isis->max_area_addrs;
++#endif
+ }
+ 
+ /*
+@@ -2017,6 +2053,12 @@ send_hello (struct isis_circuit *circuit, int level)
+       return ISIS_WARNING;
+ #endif /* HAVE_IPV6 */
+ 
++#ifdef HAVE_TRILL
++  if (level == TRILL_ISIS_LEVEL)
++    if (tlv_add_trill_vlans(circuit))
++      return ISIS_WARNING;
++#endif
++
+   if (circuit->u.bc.pad_hellos)
+     if (tlv_add_padding (circuit->snd_stream))
+       return ISIS_WARNING;
+@@ -2027,7 +2069,8 @@ send_hello (struct isis_circuit *circuit, int level)
+ 
+   retval = circuit->tx (circuit, level);
+   if (retval)
+-    zlog_warn ("sending of LAN Level %d Hello failed", level);
++    zlog_warn ("sending of LAN Level %d Hello failed on %s", level,
++      circuit->interface->name);
+ 
+   /* DEBUG_ADJ_PACKETS */
+   if (isis->debugs & DEBUG_ADJ_PACKETS)
+@@ -2070,7 +2113,12 @@ send_lan_l1_hello (struct thread *thread)
+   if (circuit->u.bc.run_dr_elect[0])
+     retval = isis_dr_elect (circuit, 1);
+ 
++#ifdef HAVE_TRILL
++  send_trill_vlan_hellos(circuit);
++  retval = ISIS_OK;
++#else
+   retval = send_lan_hello (circuit, 1);
++#endif
+ 
+   /* set next timer thread */
+   THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0],
+@@ -2252,6 +2300,9 @@ send_l1_csnp (struct thread *thread)
+   /* set next timer thread */
+   THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
+ 		   isis_jitter (circuit->csnp_interval[0], CSNP_JITTER));
++#ifdef HAVE_TRILL
++  trill_lspdb_acquire_event (circuit, CSNPSND);
++#endif
+ 
+   return retval;
+ }
+@@ -2274,6 +2325,9 @@ send_l2_csnp (struct thread *thread)
+   /* set next timer thread */
+   THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
+ 		   isis_jitter (circuit->csnp_interval[1], CSNP_JITTER));
++#ifdef HAVE_TRILL
++  trill_lspdb_acquire_event (circuit, CSNPSND);
++#endif
+ 
+   return retval;
+ }
+@@ -2399,6 +2453,10 @@ send_psnp (int level, struct isis_circuit *circuit)
+ 		}
+ 	    }
+ 	  list_delete (list);
++#ifdef HAVE_TRILL
++          if (circuit->circ_type != CIRCUIT_T_BROADCAST)
++	    trill_lspdb_acquire_event (circuit, PSNPSNDTRY);
++#endif
+ 	}
+     }
+ 
+diff --git isisd/isis_spf.c isisd/isis_spf.c
+index 5d7e9da..6e53601 100644
+--- isisd/isis_spf.c
++++ isisd/isis_spf.c
+@@ -37,21 +37,24 @@
+ #include "isis_constants.h"
+ #include "isis_common.h"
+ #include "dict.h"
++#include "isis_flags.h"
++#include "isis_circuit.h"
++#include "isis_tlv.h"
++#include "isis_lsp.h"
++#ifdef HAVE_TRILL
++#include "isis_vlans.h"
++#include "isis_trill.h"
++#endif
+ #include "isisd.h"
+ #include "isis_misc.h"
+ #include "isis_adjacency.h"
+-#include "isis_circuit.h"
+-#include "isis_tlv.h"
+ #include "isis_pdu.h"
+-#include "isis_lsp.h"
+ #include "isis_dynhn.h"
+ #include "isis_spf.h"
+ #include "isis_route.h"
+ #include "isis_csm.h"
+ 
+-extern struct isis *isis;
+ extern struct thread_master *master;
+-extern struct host host;
+ 
+ int isis_run_spf_l1 (struct thread *thread);
+ int isis_run_spf_l2 (struct thread *thread);
+@@ -188,7 +191,7 @@ vid2string (struct isis_vertex *vertex, u_char * buff)
+ }
+ #endif /* EXTREME_DEBUG */
+ 
+-static struct isis_spftree *
++struct isis_spftree *
+ isis_spftree_new ()
+ {
+   struct isis_spftree *tree;
+@@ -209,14 +212,14 @@ static void
+ isis_vertex_del (struct isis_vertex *vertex)
+ {
+   list_delete (vertex->Adj_N);
++  list_delete (vertex->children);
+ 
+   XFREE (MTYPE_ISIS_VERTEX, vertex);
+ 
+   return;
+ }
+ 
+-#if 0 /* HT: Not used yet. */
+-static void
++void
+ isis_spftree_del (struct isis_spftree *spftree)
+ {
+   spftree->tents->del = (void (*)(void *)) isis_vertex_del;
+@@ -229,7 +232,6 @@ isis_spftree_del (struct isis_spftree *spftree)
+ 
+   return;
+ }
+-#endif 
+ 
+ void
+ spftree_area_init (struct isis_area *area)
+@@ -258,6 +260,28 @@ spftree_area_init (struct isis_area *area)
+   return;
+ }
+ 
++void
++spftree_area_del (struct isis_area *area)
++{
++  if ((area->is_type & IS_LEVEL_1) && area->spftree[0] != NULL)
++    {
++      isis_spftree_del (area->spftree[0]);
++#ifdef HAVE_IPV6
++      isis_spftree_del (area->spftree6[0]);
++#endif
++    }
++
++  if ((area->is_type & IS_LEVEL_2) && area->spftree[1] != NULL)
++    {
++      isis_spftree_del (area->spftree[1]);
++#ifdef HAVE_IPV6
++      isis_spftree_del (area->spftree6[1]);
++#endif
++    }
++
++  return;
++}
++
+ static struct isis_vertex *
+ isis_vertex_new (void *id, enum vertextype vtype)
+ {
+@@ -297,36 +321,47 @@ isis_vertex_new (void *id, enum vertextype vtype)
+     }
+ 
+   vertex->Adj_N = list_new ();
++  vertex->children = list_new ();
+ 
+   return vertex;
+ }
+ 
++/* 
++ * Find the system LSP: returns the LSP in our LSP database 
++ * associated with the given system ID.
++ */
++static struct isis_lsp *
++isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid)
++{
++  u_char lspid[ISIS_SYS_ID_LEN + 2];
++
++  memcpy (lspid, sysid, ISIS_SYS_ID_LEN);
++  LSP_PSEUDO_ID (lspid) = 0;
++  LSP_FRAGMENT (lspid) = 0;
++  return (lsp_search (lspid, area->lspdb[level - 1]));
++}
++
+ /*
+  * Add this IS to the root of SPT
+  */
+-static void
+-isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area,
+-		   int level)
++static struct isis_vertex *
++isis_spf_add_root (struct isis_spftree *spftree, struct isis_area *area,
++		   int level, u_char *sysid)
+ {
+   struct isis_vertex *vertex;
+   struct isis_lsp *lsp;
+-  u_char lspid[ISIS_SYS_ID_LEN + 2];
+ #ifdef EXTREME_DEBUG
+   u_char buff[BUFSIZ];
+ #endif /* EXTREME_DEBUG */
+-  memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
+-  LSP_PSEUDO_ID (lspid) = 0;
+-  LSP_FRAGMENT (lspid) = 0;
+-
+-  lsp = lsp_search (lspid, area->lspdb[level - 1]);
+ 
++  lsp = isis_root_system_lsp (area, level, sysid);
+   if (lsp == NULL)
+     zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
+ 
+   if (!area->oldmetric)
+-    vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_TE_IS);
++    vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS);
+   else
+-    vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_IS);
++    vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS);
+ 
+   vertex->lsp = lsp;
+ 
+@@ -338,7 +373,7 @@ isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area,
+ 	      vertex->depth, vertex->d_N);
+ #endif /* EXTREME_DEBUG */
+ 
+-  return;
++  return vertex;
+ }
+ 
+ static struct isis_vertex *
+@@ -391,7 +426,8 @@ isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
+ static struct isis_vertex *
+ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
+ 		   void *id, struct isis_adjacency *adj, u_int32_t cost,
+-		   int depth, int family)
++		   int depth, int family, struct isis_vertex *parent,
++		   struct isis_lsp *lsp)
+ {
+   struct isis_vertex *vertex, *v;
+   struct listnode *node;
+@@ -402,21 +438,28 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
+   vertex = isis_vertex_new (id, vtype);
+   vertex->d_N = cost;
+   vertex->depth = depth;
++  vertex->parent = parent;
++  if (parent && (listnode_lookup (parent->children, vertex) == NULL))
++    listnode_add (parent->children, vertex);
++  /* Store the LSP we learnt the vertex from */
++  vertex->lsp = lsp;
+ 
+   if (adj)
+     listnode_add (vertex->Adj_N, adj);
+ #ifdef EXTREME_DEBUG
+-  zlog_debug ("ISIS-Spf: add to TENT  %s %s depth %d dist %d",
++  zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d",
++              print_sys_hostname (vertex->N.id),
+ 	      vtype2string (vertex->type), vid2string (vertex, buff),
+ 	      vertex->depth, vertex->d_N);
+ #endif /* EXTREME_DEBUG */
+-  listnode_add (spftree->tents, vertex);
++
+   if (list_isempty (spftree->tents))
+     {
+       listnode_add (spftree->tents, vertex);
+       return vertex;
+     }
+-  
++
++  listnode_add (spftree->tents, vertex);
+   /* XXX: This cant use the standard ALL_LIST_ELEMENT macro */
+   for (node = listhead (spftree->tents); node; node = listnextnode (node))
+     {
+@@ -454,7 +497,8 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
+ static struct isis_vertex *
+ isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
+ 		    void *id, struct isis_adjacency *adj, u_int32_t cost,
+-		    int family)
++		    int family, struct isis_vertex *parent,
++		    struct isis_lsp *lsp)
+ {
+   struct isis_vertex *vertex;
+ 
+@@ -482,13 +526,13 @@ isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
+     }
+ 
+ add2tent:
+-  return isis_spf_add2tent (spftree, vtype, id, adj, cost, 1, family);
++  return isis_spf_add2tent (spftree, vtype, id, adj, cost, 1, family, parent, lsp);
+ }
+ 
+ static void
+ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
+ 	   u_int16_t dist, u_int16_t depth, struct isis_adjacency *adj,
+-	   int family)
++	   int family, struct isis_vertex *parent, struct isis_lsp *lsp)
+ {
+   struct isis_vertex *vertex;
+ #ifdef EXTREME_DEBUG
+@@ -503,7 +547,8 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
+   if (vertex)
+     {
+ #ifdef EXTREME_DEBUG
+-      zlog_debug ("ISIS-Spf: process_N  %s %s dist %d already found from PATH",
++      zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH",
++	          print_sys_hostname (vertex->N.id),
+ 		  vtype2string (vtype), vid2string (vertex, buff), dist);
+ #endif /* EXTREME_DEBUG */
+       assert (dist >= vertex->d_N);
+@@ -516,7 +561,8 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
+     {
+       /*        1) */
+ #ifdef EXTREME_DEBUG
+-      zlog_debug ("ISIS-Spf: process_N  %s %s dist %d",
++      zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d",
++	          print_sys_hostname (vertex->N.id),
+ 		  vtype2string (vtype), vid2string (vertex, buff), dist);
+ #endif /* EXTREME_DEBUG */
+       if (vertex->d_N == dist)
+@@ -540,7 +586,13 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
+ 	}
+     }
+ 
+-  isis_spf_add2tent (spftree, vtype, id, adj, dist, depth, family);
++#ifdef EXTREME_DEBUG
++      zlog_debug ("ISIS-Spf: process_N add2tent %s %s dist %d",
++		  print_sys_hostname(id), 
++		  vtype2string (vtype), dist);
++#endif /* EXTREME_DEBUG */
++
++  isis_spf_add2tent (spftree, vtype, id, adj, dist, depth, family, parent, lsp);
+   return;
+ }
+ 
+@@ -549,7 +601,8 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
+  */
+ static int
+ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
+-		      uint32_t cost, uint16_t depth, int family)
++		      uint32_t cost, uint16_t depth, int family,
++		      u_char *root_sysid, struct isis_vertex *parent)
+ {
+   struct listnode *node, *fragnode = NULL;
+   u_int16_t dist;
+@@ -562,13 +615,27 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
+ #ifdef HAVE_IPV6
+   struct ipv6_reachability *ip6reach;
+ #endif /* HAVE_IPV6 */
++  struct isis_adjacency *adj = NULL;
++  static const u_char null_sysid[ISIS_SYS_ID_LEN];
+ 
+-
+-  if (!lsp->adj)
+-    return ISIS_WARNING;
+-  if (lsp->tlv_data.nlpids == NULL || !speaks (lsp->tlv_data.nlpids, family))
++  if (!speaks (lsp->tlv_data.nlpids, family))
+     return ISIS_OK;
+ 
++  /* 
++   * Note the adjacency (the neighboring system we received the LSP from) when computing 
++   * the SPF with our system as the root. Adjacencies computed are used for TRILL forwarding.
++   */
++  if (memcmp (root_sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0)
++    {
++      /* 
++       * lsp->adj can be NULL if computing SPF for other TRILL RBridges
++       * when lsp->adj is NULL during processing of lsps created by us.
++       */ 
++      if (!lsp->adj)
++        return ISIS_WARNING;
++      adj = lsp->adj;
++    }
++
+ lspfragloop:
+   if (lsp->lsp_header->seq_num == 0)
+     {
+@@ -577,6 +644,10 @@ lspfragloop:
+       return ISIS_WARNING;
+     }
+ 
++#ifdef EXTREME_DEBUG
++      zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id));
++#endif /* EXTREME_DEBUG */
++
+   if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
+     {
+       if (lsp->tlv_data.is_neighs)
+@@ -585,13 +656,15 @@ lspfragloop:
+ 	    {
+ 	      /* C.2.6 a) */
+ 	      /* Two way connectivity */
+-	      if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
++	      if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
++		continue;
++	      if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
+ 		continue;
+ 	      dist = cost + is_neigh->metrics.metric_default;
+ 	      vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
+ 		: VTYPE_NONPSEUDO_IS;
+ 	      process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
+-			 depth + 1, lsp->adj, family);
++			 depth + 1, adj, family, parent, lsp);
+ 	    }
+ 	}
+       if (lsp->tlv_data.te_is_neighs)
+@@ -599,15 +672,15 @@ lspfragloop:
+ 	  for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
+ 				     te_is_neigh))
+ 	    {
+-	      uint32_t metric;
+-	      if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
++	      if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
++		continue;
++	      if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
+ 		continue;
+-	      memcpy (&metric, te_is_neigh->te_metric, 3);
+-	      dist = cost + ntohl (metric << 8);
++	      dist = cost + GET_TE_METRIC(te_is_neigh);
+ 	      vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
+ 		: VTYPE_NONPSEUDO_TE_IS;
+ 	      process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
+-			 depth + 1, lsp->adj, family);
++			 depth + 1, adj, family, parent, lsp);
+ 	    }
+ 	}
+       if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
+@@ -621,7 +694,7 @@ lspfragloop:
+ 	      prefix.u.prefix4 = ipreach->prefix;
+ 	      prefix.prefixlen = ip_masklen (ipreach->mask);
+ 	      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+-			 lsp->adj, family);
++			 adj, family, parent, lsp);
+ 	    }
+ 	}
+ 
+@@ -636,7 +709,7 @@ lspfragloop:
+ 	      prefix.u.prefix4 = ipreach->prefix;
+ 	      prefix.prefixlen = ip_masklen (ipreach->mask);
+ 	      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+-			 lsp->adj, family);
++			 adj, family, parent, lsp);
+ 	    }
+ 	}
+       if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs)
+@@ -651,7 +724,7 @@ lspfragloop:
+ 						   te_ipv4_reach->control);
+ 	      prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
+ 	      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+-			 lsp->adj, family);
++			 adj, family, parent, lsp);
+ 	    }
+ 	}
+ #ifdef HAVE_IPV6
+@@ -668,7 +741,7 @@ lspfragloop:
+ 	      memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
+ 		      PSIZE (ip6reach->prefix_len));
+ 	      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+-			 lsp->adj, family);
++			 adj, family, parent, lsp);
+ 	    }
+ 	}
+ #endif /* HAVE_IPV6 */
+@@ -691,12 +764,22 @@ lspfragloop:
+ static int
+ isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
+ 			     struct isis_lsp *lsp, uint16_t cost,
+-			     uint16_t depth, int family)
++			     uint16_t depth, int family,
++			     u_char *root_sysid,
++			     struct isis_vertex *parent)
+ {
+   struct listnode *node, *fragnode = NULL;
+   struct is_neigh *is_neigh;
+   struct te_is_neigh *te_is_neigh;
+   enum vertextype vtype;
++  struct isis_adjacency *adj = NULL;
++
++  /* 
++   * Note the adjacency (the neighboring system we received the LSP from) when computing 
++   * the SPF with our system as the root. Adjacencies computed are used for TRILL forwarding.
++   */
++  if (memcmp (root_sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0)
++    adj = lsp->adj;
+ 
+ pseudofragloop:
+ 
+@@ -707,13 +790,17 @@ pseudofragloop:
+       return ISIS_WARNING;
+     }
+ 
++#ifdef EXTREME_DEBUG
++      zlog_debug ("ISIS-Spf: process_pseudo_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id));
++#endif /* EXTREME_DEBUG */
++
+   if (lsp->tlv_data.is_neighs)
+     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
+       {
+ 	vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
+ 	  : VTYPE_NONPSEUDO_IS;
+ 	/* Two way connectivity */
+-	if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
++	if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
+ 	  continue;
+ 	if (isis_find_vertex
+ 	    (spftree->tents, (void *) is_neigh->neigh_id, vtype) == NULL
+@@ -721,8 +808,8 @@ pseudofragloop:
+ 			       vtype) == NULL)
+ 	  {
+ 	    /* C.2.5 i) */
+-	    isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, lsp->adj,
+-			     cost, depth, family);
++	    isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, adj,
++			     cost, depth, family, parent, lsp);
+ 	  }
+       }
+   if (lsp->tlv_data.te_is_neighs)
+@@ -731,7 +818,7 @@ pseudofragloop:
+ 	vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
+ 	  : VTYPE_NONPSEUDO_TE_IS;
+ 	/* Two way connectivity */
+-	if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
++	if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
+ 	  continue;
+ 	if (isis_find_vertex
+ 	    (spftree->tents, (void *) te_is_neigh->neigh_id, vtype) == NULL
+@@ -739,8 +826,8 @@ pseudofragloop:
+ 				 vtype) == NULL)
+ 	  {
+ 	    /* C.2.5 i) */
+-	    isis_spf_add2tent (spftree, vtype, te_is_neigh->neigh_id, lsp->adj,
+-			       cost, depth, family);
++	    isis_spf_add2tent (spftree, vtype, te_is_neigh->neigh_id, adj,
++			       cost, depth, family, parent, lsp);
+ 	  }
+       }
+ 
+@@ -760,23 +847,67 @@ pseudofragloop:
+ 
+ static int
+ isis_spf_preload_tent (struct isis_spftree *spftree,
+-		       struct isis_area *area, int level, int family)
++		       struct isis_area *area, int level, 
++		       int family, u_char *root_sysid,
++		       struct isis_vertex *parent)
+ {
+   struct isis_vertex *vertex;
+   struct isis_circuit *circuit;
+   struct listnode *cnode, *anode, *ipnode;
+   struct isis_adjacency *adj;
+   struct isis_lsp *lsp;
++  struct isis_lsp *root_lsp;
+   struct list *adj_list;
+   struct list *adjdb;
+   struct prefix_ipv4 *ipv4;
+   struct prefix prefix;
+   int retval = ISIS_OK;
+   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
++  static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
+ #ifdef HAVE_IPV6
+   struct prefix_ipv6 *ipv6;
+ #endif /* HAVE_IPV6 */
+ 
++#ifdef HAVE_TRILL
++  /* 
++   * Check if computing SPF tree for another system. If computing SPF
++   * tree for another system (for TRILL) preload TENT by determining
++   * the neighboring systems of the root system by processing the root 
++   * system LSP.
++   */
++  if (isis->trill_active &&
++      memcmp (root_sysid, isis->sysid, ISIS_SYS_ID_LEN) != 0)
++    {
++      dnode_t *dnode;
++
++      memcpy (lsp_id, root_sysid, ISIS_SYS_ID_LEN);
++      LSP_PSEUDO_ID (lsp_id) = 0;
++      LSP_FRAGMENT (lsp_id) = 0;
++
++      /* should add at least one */
++      retval = ISIS_WARNING;
++      for (ALL_DICT_NODES_RO(area->lspdb[level-1], dnode, lsp))
++        {
++          if (LSP_FRAGMENT (lsp->lsp_header->lsp_id))
++            continue;
++          if (memcmp(lsp_id, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN) != 0)
++            continue;
++
++	  if (LSP_PSEUDO_ID (lsp->lsp_header->lsp_id))
++            retval = isis_spf_process_pseudo_lsp (spftree, lsp, 
++			    DEFAULT_CIRCUIT_METRICS, 0, AF_TRILL, 
++			    root_sysid, parent);
++	  else
++            retval = isis_spf_process_lsp (spftree, lsp,
++					   DEFAULT_CIRCUIT_METRICS, 1,
++					   AF_TRILL, root_sysid, parent);
++        }
++      return retval;
++    }
++#endif
++
++  root_lsp = isis_root_system_lsp (area, level, root_sysid);
++
+   for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
+     {
+       if (circuit->state != C_STATE_UP)
+@@ -800,7 +931,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
+ 	      prefix.u.prefix4 = ipv4->prefix;
+ 	      prefix.prefixlen = ipv4->prefixlen;
+ 	      isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
+-				  NULL, 0, family);
++				  NULL, 0, family, parent, root_lsp);
+ 	    }
+ 	}
+ #ifdef HAVE_IPV6
+@@ -812,7 +943,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
+ 	      prefix.prefixlen = ipv6->prefixlen;
+ 	      prefix.u.prefix6 = ipv6->prefix;
+ 	      isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
+-				  &prefix, NULL, 0, family);
++				  &prefix, NULL, 0, family, parent, root_lsp);
+ 	    }
+ 	}
+ #endif /* HAVE_IPV6 */
+@@ -845,21 +976,27 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
+ 		{
+ 		case ISIS_SYSTYPE_ES:
+ 		  isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
+-				      circuit->te_metric[level - 1], family);
++				      circuit->te_metric[level - 1],
++				      family, parent, root_lsp);
+ 		  break;
+ 		case ISIS_SYSTYPE_IS:
+ 		case ISIS_SYSTYPE_L1_IS:
+ 		case ISIS_SYSTYPE_L2_IS:
+ 		  vertex =
+-		    isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS,
++		    isis_spf_add_local (spftree,
++					area->oldmetric ? VTYPE_NONPSEUDO_IS :
++					VTYPE_NONPSEUDO_TE_IS,
+ 					adj->sysid, adj,
+-					circuit->te_metric[level - 1], family);
++					circuit->te_metric[level - 1],
++					family, parent, root_lsp);
+ 		  memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
+ 		  LSP_PSEUDO_ID (lsp_id) = 0;
+ 		  LSP_FRAGMENT (lsp_id) = 0;
+ 		  lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
+ 		  if (!lsp)
+-		    zlog_warn ("No lsp found for IS adjacency");
++		    zlog_warn ("No LSP %s found for IS adjacency L%d on %s (ID %u)",
++			rawlspid_print (lsp_id), level,
++			circuit->interface->name, circuit->circuit_id);
+ 		  /*          else {
+ 		     isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family);
+ 		     } */
+@@ -878,22 +1015,34 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
+ 	    memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
+ 	  else
+ 	    memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
++	  /* can happen during DR reboot */
++	  if (memcmp (lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1) == 0)
++	    {
++	      if (isis->debugs & DEBUG_SPF_EVENTS)
++		zlog_debug ("ISIS-Spf: no L%d DR on %s (ID %d)",
++		    level, circuit->interface->name, circuit->circuit_id);
++	      continue;
++	    }
+ 	  lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
+ 	  adj = isis_adj_lookup (lsp_id, adjdb);
+ 	  /* if no adj, we are the dis or error */
+ 	  if (!adj && !circuit->u.bc.is_dr[level - 1])
+ 	    {
+-	      zlog_warn ("ISIS-Spf: No adjacency found for DR");
++	      zlog_warn ("ISIS-Spf: No adjacency found for L%d DR SPF-root:%s on %s (ID %d)",
++		  level, print_sys_hostname(root_sysid),
++		  circuit->interface->name, circuit->circuit_id);
+ 	    }
+ 	  if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
+ 	    {
+-	      zlog_warn ("ISIS-Spf: No lsp found for DR");
++	      zlog_warn ("ISIS-Spf: No lsp found for L%d DR SPF-root:%s on %s (ID %d)",
++		  level, print_sys_hostname(root_sysid),
++		  circuit->interface->name, circuit->circuit_id);
+ 	    }
+ 	  else
+ 	    {
+ 	      isis_spf_process_pseudo_lsp (spftree, lsp,
+-				  circuit->te_metric[level - 1], 0, family);
+-
++				  circuit->te_metric[level - 1], 0,
++				  family, root_sysid, parent);
+ 	    }
+ 	}
+       else if (circuit->circ_type == CIRCUIT_T_P2P)
+@@ -905,19 +1054,22 @@ isis_spf_preload_tent (struct isis_spftree *spftree,
+ 	    {
+ 	    case ISIS_SYSTYPE_ES:
+ 	      isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
+-				  circuit->te_metric[level - 1], family);
++				  circuit->te_metric[level - 1], family,
++				  parent, root_lsp);
+ 	      break;
+ 	    case ISIS_SYSTYPE_IS:
+ 	    case ISIS_SYSTYPE_L1_IS:
+ 	    case ISIS_SYSTYPE_L2_IS:
+ 	      if (speaks (&adj->nlpids, family))
+-		isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS, adj->sysid,
++		isis_spf_add_local (spftree,
++				    area->oldmetric ? VTYPE_NONPSEUDO_IS :
++				    VTYPE_NONPSEUDO_TE_IS, adj->sysid,
+ 				    adj, circuit->te_metric[level - 1],
+-				    family);
++				    family, parent, root_lsp);
+ 	      break;
+ 	    case ISIS_SYSTYPE_UNKNOWN:
+ 	    default:
+-	      zlog_warn ("isis_spf_preload_tent unknow adj type");
++	      zlog_warn ("isis_spf_preload_tent unknown adj type");
+ 	      break;
+ 	    }
+ 	}
+@@ -946,11 +1098,17 @@ add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
+   listnode_add (spftree->paths, vertex);
+ 
+ #ifdef EXTREME_DEBUG
+-  zlog_debug ("ISIS-Spf: added  %s %s depth %d dist %d to PATHS",
++  zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
++              print_sys_hostname (vertex->N.id),
+ 	      vtype2string (vertex->type), vid2string (vertex, buff),
+ 	      vertex->depth, vertex->d_N);
+ #endif /* EXTREME_DEBUG */
++
++#ifdef HAVE_TRILL
++  if (!isis->trill_active && vertex->type > VTYPE_ES)
++#else
+   if (vertex->type > VTYPE_ES)
++#endif
+     {
+       if (listcount (vertex->Adj_N) > 0)
+ 	isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N,
+@@ -969,16 +1127,17 @@ init_spt (struct isis_spftree *spftree)
+   list_delete_all_node (spftree->tents);
+   list_delete_all_node (spftree->paths);
+   spftree->tents->del = spftree->paths->del = NULL;
+-
+   return;
+ }
+ 
+ static int
+-isis_run_spf (struct isis_area *area, int level, int family)
++isis_run_spf (struct isis_area *area, int level, int family,
++		u_char *sysid, struct isis_spftree *calc_spftree)
+ {
+   int retval = ISIS_OK;
+   struct listnode *node;
+   struct isis_vertex *vertex;
++  struct isis_vertex *root_vertex;
+   struct isis_spftree *spftree = NULL;
+   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+   struct isis_lsp *lsp;
+@@ -986,47 +1145,63 @@ isis_run_spf (struct isis_area *area, int level, int family)
+   struct route_node *rode;
+   struct isis_route_info *rinfo;
+ 
+-  if (family == AF_INET)
++  if (calc_spftree)
++    spftree = calc_spftree;
++#ifdef HAVE_TRILL
++  else if (family == AF_TRILL)
++    spftree = area->spftree[level - 1];
++#endif
++  else if (family == AF_INET)
+     spftree = area->spftree[level - 1];
+ #ifdef HAVE_IPV6
+   else if (family == AF_INET6)
+     spftree = area->spftree6[level - 1];
+ #endif
+-
+   assert (spftree);
++  assert (sysid);
+ 
+-  /* Make all routes in current route table inactive. */
+-  if (family == AF_INET)
+-    table = area->route_table[level - 1];
++#ifdef HAVE_TRILL
++  if (family != AF_TRILL)
++#endif
++   {
++     /* Make all routes in current route table inactive. */
++     if (family == AF_INET)
++       table = area->route_table[level - 1];
+ #ifdef HAVE_IPV6
+-  else if (family == AF_INET6)
+-    table = area->route_table6[level - 1];
++     else if (family == AF_INET6)
++       table = area->route_table6[level - 1];
+ #endif
+ 
+-  for (rode = route_top (table); rode; rode = route_next (rode))
+-    {
+-      if (rode->info == NULL)
+-        continue;
+-      rinfo = rode->info;
++    for (rode = route_top (table); rode; rode = route_next (rode))
++      {
++        if (rode->info == NULL)
++          continue;
++        rinfo = rode->info;
+ 
+-      UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
+-    }
++        UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
++      }
++   }
+ 
+   /*
+    * C.2.5 Step 0
+    */
+   init_spt (spftree);
+   /*              a) */
+-  isis_spf_add_self (spftree, area, level);
++  root_vertex = isis_spf_add_root (spftree, area, level, sysid);
+   /*              b) */
+-  retval = isis_spf_preload_tent (spftree, area, level, family);
++  retval = isis_spf_preload_tent (spftree, area, level, family, sysid, root_vertex);
++  if (retval != ISIS_OK)
++    {
++      zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid));
++      goto out;
++    }
+ 
+   /*
+    * C.2.7 Step 2
+    */
+   if (listcount (spftree->tents) == 0)
+     {
+-      zlog_warn ("ISIS-Spf: TENT is empty");
++      zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid));
+       goto out;
+     }
+ 
+@@ -1034,14 +1209,24 @@ isis_run_spf (struct isis_area *area, int level, int family)
+     {
+       node = listhead (spftree->tents);
+       vertex = listgetdata (node);
++
++#ifdef EXTREME_DEBUG
++  zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
++              print_sys_hostname (vertex->N.id),
++	      vtype2string (vertex->type), vertex->depth, vertex->d_N);
++#endif /* EXTREME_DEBUG */
++
+       /* Remove from tent list */
+       list_delete_node (spftree->tents, node);
+       if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
+ 	continue;
+       add_to_paths (spftree, vertex, area, level);
+-      if (vertex->type == VTYPE_PSEUDO_IS ||
+-	  vertex->type == VTYPE_NONPSEUDO_IS)
+-	{
++      switch (vertex->type)
++        {
++	case VTYPE_PSEUDO_IS:
++	case VTYPE_NONPSEUDO_IS:
++	case VTYPE_PSEUDO_TE_IS:
++	case VTYPE_NONPSEUDO_TE_IS:
+ 	  memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
+ 	  LSP_FRAGMENT (lsp_id) = 0;
+ 	  lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
+@@ -1050,13 +1235,12 @@ isis_run_spf (struct isis_area *area, int level, int family)
+ 	      if (LSP_PSEUDO_ID (lsp_id))
+ 		{
+ 		  isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
+-					       vertex->depth, family);
+-
++					       vertex->depth, family, sysid, vertex);
+ 		}
+ 	      else
+ 		{
+ 		  isis_spf_process_lsp (spftree, lsp, vertex->d_N,
+-					vertex->depth, family);
++					vertex->depth, family, sysid, vertex);
+ 		}
+ 	    }
+ 	  else
+@@ -1064,11 +1248,16 @@ isis_run_spf (struct isis_area *area, int level, int family)
+ 	      zlog_warn ("ISIS-Spf: No LSP found for %s",
+ 			 rawlspid_print (lsp_id));
+ 	    }
++	  break;
++	default:;
+ 	}
+     }
+ 
+ out:
+-  thread_add_event (master, isis_route_validate, area, 0);
++#ifdef HAVE_TRILL
++  if (family != AF_TRILL)
++#endif
++    thread_add_event (master, isis_route_validate, area, 0);
+   spftree->lastrun = time (NULL);
+   spftree->pending = 0;
+ 
+@@ -1098,7 +1287,7 @@ isis_run_spf_l1 (struct thread *thread)
+     zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
+ 
+   if (area->ip_circuits)
+-    retval = isis_run_spf (area, 1, AF_INET);
++    retval = isis_run_spf (area, 1, AF_INET, isis->sysid, NULL);
+ 
+   THREAD_TIMER_ON (master, area->spftree[0]->t_spf, isis_run_spf_l1, area,
+ 		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+@@ -1128,7 +1317,7 @@ isis_run_spf_l2 (struct thread *thread)
+     zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
+ 
+   if (area->ip_circuits)
+-    retval = isis_run_spf (area, 2, AF_INET);
++    retval = isis_run_spf (area, 2, AF_INET, isis->sysid, NULL);
+ 
+   THREAD_TIMER_ON (master, area->spftree[1]->t_spf, isis_run_spf_l2, area,
+ 		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+@@ -1153,9 +1342,8 @@ isis_spf_schedule (struct isis_area *area, int level)
+     {
+       if (level == 1)
+ 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, 60);
+-      else
+-	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, 60);
+-
++      else 
++	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, 60); 
+       spftree->pending = 1;
+       return retval;
+     }
+@@ -1176,7 +1364,9 @@ isis_spf_schedule (struct isis_area *area, int level)
+   else
+     {
+       spftree->pending = 0;
+-      retval = isis_run_spf (area, level, AF_INET);
++
++      retval = isis_run_spf (area, level, AF_INET, isis->sysid, NULL);
++
+       if (level == 1)
+ 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
+ 			 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+@@ -1211,7 +1401,7 @@ isis_run_spf6_l1 (struct thread *thread)
+     zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
+ 
+   if (area->ipv6_circuits)
+-    retval = isis_run_spf (area, 1, AF_INET6);
++    retval = isis_run_spf (area, 1, AF_INET6, isis->sysid, NULL);
+ 
+   THREAD_TIMER_ON (master, area->spftree6[0]->t_spf, isis_run_spf6_l1, area,
+ 		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+@@ -1241,7 +1431,7 @@ isis_run_spf6_l2 (struct thread *thread)
+     zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag);
+ 
+   if (area->ipv6_circuits)
+-    retval = isis_run_spf (area, 2, AF_INET6);
++    retval = isis_run_spf (area, 2, AF_INET6, isis->sysid, NULL);
+ 
+   THREAD_TIMER_ON (master, area->spftree6[1]->t_spf, isis_run_spf6_l2, area,
+ 		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+@@ -1289,7 +1479,7 @@ isis_spf_schedule6 (struct isis_area *area, int level)
+   else
+     {
+       spftree->pending = 0;
+-      retval = isis_run_spf (area, level, AF_INET6);
++      retval = isis_run_spf (area, level, AF_INET6, isis->sysid, NULL);
+ 
+       if (level == 1)
+ 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
+@@ -1303,51 +1493,174 @@ isis_spf_schedule6 (struct isis_area *area, int level)
+ }
+ #endif
+ 
++#ifdef HAVE_TRILL
++static int
++trill_complete_spf(struct isis_area *area)
++{
++  int retval;
++  dnode_t *dnode;
++  nicknode_t *tnode;
++
++  retval = isis_run_spf (area, TRILL_ISIS_LEVEL, AF_TRILL, isis->sysid, NULL);
++  if (retval != ISIS_OK)
++    zlog_warn ("ISIS-Spf running spf for system returned:%d", retval);
++
++  /* 
++   * Run SPF for all other RBridges in the campus as well to
++   * compute the distribution trees with other RBridges in
++   * the campus as root. 
++   */
++  for (ALL_DICT_NODES_RO(area->trill->nickdb, dnode, tnode))
++    {
++      retval = isis_run_spf (area, TRILL_ISIS_LEVEL, AF_TRILL,
++	                tnode->info.sysid, tnode->rdtree);
++      if (isis->debugs & DEBUG_SPF_EVENTS)
++        zlog_debug ("ISIS-Spf running spf for:%s",
++                        print_sys_hostname (tnode->info.sysid));
++      if (retval != ISIS_OK)
++        zlog_warn ("ISIS-Spf running spf for:%s returned:%d",
++                        print_sys_hostname (tnode->info.sysid), retval);
++    }
++
++  /* 
++   * Process computed SPF trees to create TRILL 
++   * forwarding and adjacency tables.
++   */
++  trill_process_spf (area);
++  return retval;
++}
++
++static int
++isis_run_spf_trill (struct thread *thread)
++{
++  struct isis_area *area;
++  int retval;
++
++  area = THREAD_ARG (thread);
++  assert (area);
++
++  area->spftree[0]->t_spf = NULL;
++
++  if (!(area->is_type & IS_LEVEL_1))
++    {
++      if (isis->debugs & DEBUG_SPF_EVENTS)
++	zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
++      return ISIS_WARNING;
++    }
++
++  if (isis->debugs & DEBUG_SPF_EVENTS)
++    zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
++
++  retval = trill_complete_spf(area);
++
++  THREAD_TIMER_ON (master, area->spftree[0]->t_spf, isis_run_spf_trill, area,
++		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
++
++  return retval;
++}
++
++int
++isis_spf_schedule_trill (struct isis_area *area)
++{
++  int retval = ISIS_OK;
++  struct isis_spftree *spftree = area->spftree[TRILL_ISIS_LEVEL - 1];
++  time_t diff, now = time (NULL);
++
++  if (spftree->pending)
++    return retval;
++
++  diff = now - spftree->lastrun;
++
++  /* FIXME: let's wait a minute before doing the SPF */
++  if (now - isis->uptime < 60 || isis->uptime == 0)
++    {
++      THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_trill, area, 60);
++
++      spftree->pending = 1;
++      return retval;
++    }
++
++  THREAD_TIMER_OFF (spftree->t_spf);
++
++  if (diff < MINIMUM_SPF_INTERVAL)
++    {
++      THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_trill, area,
++		       MINIMUM_SPF_INTERVAL - diff);
++
++      spftree->pending = 1;
++    }
++  else
++    {
++      spftree->pending = 0;
++
++      retval = trill_complete_spf(area);
++
++      THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_trill, area,
++		       isis_jitter (PERIODIC_SPF_INTERVAL, 10));
++    }
++
++  return retval;
++}
++#endif /* HAVE_TRILL */
++
+ static void
+-isis_print_paths (struct vty *vty, struct list *paths)
++isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid)
+ {
+   struct listnode *node;
++  struct listnode *cnode;
+   struct isis_vertex *vertex;
+-  struct isis_dynhn *dyn, *nh_dyn = NULL;
++  struct isis_vertex *cvertex;
+   struct isis_adjacency *adj;
+ #if 0
+   u_char buff[255];
+ #endif /* 0 */
+ 
+   vty_out (vty, "System Id            Metric     Next-Hop"
+-	   "             Interface   SNPA%s", VTY_NEWLINE);
++	   "             Interface     SNPA        Tree%s", VTY_NEWLINE);
+ 
+   for (ALL_LIST_ELEMENTS_RO (paths, node, vertex))
+     {
+-      if (vertex->type != VTYPE_NONPSEUDO_IS)
++      if (vertex->type != VTYPE_NONPSEUDO_IS &&
++	  vertex->type != VTYPE_NONPSEUDO_TE_IS)
+ 	continue;
+-      if (memcmp (vertex->N.id, isis->sysid, ISIS_SYS_ID_LEN) == 0)
++      if (memcmp (vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0)
+ 	{
+-	  vty_out (vty, "%s             --%s", host.name?host.name:"",
+-		   VTY_NEWLINE);
++	  vty_out (vty, "%-20s %-10s", print_sys_hostname (root_sysid), "--");
++	  vty_out (vty, "%-48s", "");
+ 	}
+       else
+ 	{
+-	  dyn = dynhn_find_by_id ((u_char *) vertex->N.id);
+-	  adj = listgetdata (listhead (vertex->Adj_N));
+-	  if (adj)
++	  if (listhead (vertex->Adj_N) &&
++	       (adj = listgetdata (listhead (vertex->Adj_N))))
+ 	    {
+-	      nh_dyn = dynhn_find_by_id (adj->sysid);
+-	      vty_out (vty, "%-20s %-10u %-20s %-11s %-5s%s",
+-		       (dyn != NULL) ? dyn->name.name :
+-		       (const u_char *)rawlspid_print ((u_char *) vertex->N.id),
+-		       vertex->d_N, (nh_dyn != NULL) ? nh_dyn->name.name :
+-		       (const u_char *)rawlspid_print (adj->sysid),
++	      vty_out (vty, "%-20s %-10u %-20s %-11s %-8s",
++                       print_sys_hostname (vertex->N.id),
++		       vertex->d_N, print_sys_hostname (adj->sysid),
+ 		       adj->circuit->interface->name,
+-		       snpa_print (adj->snpa), VTY_NEWLINE);
++		       snpa_print (adj->snpa));
+ 	    }
+ 	  else
+ 	    {
+-	      vty_out (vty, "%s              %u %s", dyn ? dyn->name.name :
+-		       (const u_char *) rawlspid_print (vertex->N.id),
+-		       vertex->d_N, VTY_NEWLINE);
++	      vty_out (vty, "%-20s %-10u %-48s ", 
++		      print_sys_hostname (vertex->N.id), 
++		      vertex->d_N, "");
+ 	    }
+ 	}
++
++      if (vertex->parent)
++        vty_out (vty, " %s(%d) :-> ",
++		print_sys_hostname (vertex->parent->N.id), vertex->type);
++      else
++        vty_out (vty, " :> ");
++
++      if (listcount (vertex->children) > 0)
++        {
++          for (ALL_LIST_ELEMENTS_RO (vertex->children, cnode, cvertex))
++	    vty_out (vty, "%s(%d),", 
++	         print_sys_hostname(cvertex->N.id), cvertex->type);
++	}
++      vty_out (vty, "%s", VTY_NEWLINE);
++
+ #if 0
+       vty_out (vty, "%s %s %u %s", vtype2string (vertex->type),
+ 	       vid2string (vertex, buff), vertex->d_N, VTY_NEWLINE);
+@@ -1355,6 +1668,26 @@ isis_print_paths (struct vty *vty, struct list *paths)
+     }
+ }
+ 
++#ifdef HAVE_TRILL
++static void
++trill_print_paths (struct vty *vty, struct isis_area *area)
++{
++  dnode_t *dnode;
++  nicknode_t *tnode;
++
++  for (ALL_DICT_NODES_RO(area->trill->nickdb, dnode, tnode))
++  {
++    if (tnode->rdtree && tnode->rdtree->paths->count > 0)
++    {
++      vty_out (vty, "%sRBridge distribution paths for RBridge:%s%s",
++       	       VTY_NEWLINE, print_sys_hostname (tnode->info.sysid),
++	       VTY_NEWLINE);
++      isis_print_paths (vty, tnode->rdtree->paths, tnode->info.sysid);
++    }
++  }
++}
++#endif /* HAVE_TRILL */
++
+ DEFUN (show_isis_topology,
+        show_isis_topology_cmd,
+        "show isis topology",
+@@ -1381,7 +1714,7 @@ DEFUN (show_isis_topology,
+ 	    {
+ 	      vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
+ 		       level + 1, VTY_NEWLINE);
+-	      isis_print_paths (vty, area->spftree[level]->paths);
++	      isis_print_paths (vty, area->spftree[level]->paths, isis->sysid);
+ 	    }
+ #ifdef HAVE_IPV6
+ 	  if (area->ipv6_circuits > 0 && area->spftree6[level]
+@@ -1390,10 +1723,15 @@ DEFUN (show_isis_topology,
+ 	      vty_out (vty,
+ 		       "IS-IS paths to level-%d routers that speak IPv6%s",
+ 		       level + 1, VTY_NEWLINE);
+-	      isis_print_paths (vty, area->spftree6[level]->paths);
++	      isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid);
+ 	    }
+ #endif /* HAVE_IPV6 */
+ 	}
++
++#ifdef HAVE_TRILL
++      if (isis->trill_active)
++	trill_print_paths (vty, area);
++#endif
+     }
+ 
+   return CMD_SUCCESS;
+@@ -1423,7 +1761,7 @@ DEFUN (show_isis_topology_l1,
+ 	{
+ 	  vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
+ 		   VTY_NEWLINE);
+-	  isis_print_paths (vty, area->spftree[0]->paths);
++	  isis_print_paths (vty, area->spftree[0]->paths, isis->sysid);
+ 	}
+ #ifdef HAVE_IPV6
+       if (area->ipv6_circuits > 0 && area->spftree6[0]
+@@ -1431,9 +1769,13 @@ DEFUN (show_isis_topology_l1,
+ 	{
+ 	  vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
+ 		   VTY_NEWLINE);
+-	  isis_print_paths (vty, area->spftree6[0]->paths);
++	  isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid);
+ 	}
+ #endif /* HAVE_IPV6 */
++#ifdef HAVE_TRILL
++      if (isis->trill_active)
++	trill_print_paths (vty, area);
++#endif
+     }
+ 
+   return CMD_SUCCESS;
+@@ -1463,7 +1805,7 @@ DEFUN (show_isis_topology_l2,
+ 	{
+ 	  vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
+ 		   VTY_NEWLINE);
+-	  isis_print_paths (vty, area->spftree[1]->paths);
++	  isis_print_paths (vty, area->spftree[1]->paths, isis->sysid);
+ 	}
+ #ifdef HAVE_IPV6
+       if (area->ipv6_circuits > 0 && area->spftree6[1]
+@@ -1471,7 +1813,7 @@ DEFUN (show_isis_topology_l2,
+ 	{
+ 	  vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
+ 		   VTY_NEWLINE);
+-	  isis_print_paths (vty, area->spftree6[1]->paths);
++	  isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid);
+ 	}
+ #endif /* HAVE_IPV6 */
+     }
+diff --git isisd/isis_spf.h isisd/isis_spf.h
+index 6bdab2d..ece9896 100644
+--- isisd/isis_spf.h
++++ isisd/isis_spf.h
+@@ -54,11 +54,12 @@ struct isis_vertex
+     struct prefix prefix;
+   } N;
+ 
+-  struct isis_lsp *lsp;
++  struct isis_lsp *lsp;         /* referring LSP (the LSP this vertex was learnt from) */
+   u_int32_t d_N;		/* d(N) Distance from this IS      */
+   u_int16_t depth;		/* The depth in the imaginary tree */
+-
+-  struct list *Adj_N;		/* {Adj(N)}  */
++  struct list *Adj_N;		/* {Adj(N)} next hop or neighbor list */
++  struct isis_vertex *parent;   /* parent and child links used to find adjacencies on tree */
++  struct list *children;
+ };
+ 
+ struct isis_spftree
+@@ -72,10 +73,16 @@ struct isis_spftree
+   u_int32_t timerun;		/* statistics */
+ };
+ 
++struct isis_spftree * isis_spftree_new (void);
++void isis_spftree_del (struct isis_spftree *spftree);
+ void spftree_area_init (struct isis_area *area);
++void spftree_area_del (struct isis_area *area);
+ int isis_spf_schedule (struct isis_area *area, int level);
+ void isis_spf_cmds_init (void);
+ #ifdef HAVE_IPV6
+ int isis_spf_schedule6 (struct isis_area *area, int level);
+ #endif
++#ifdef HAVE_TRILL
++int isis_spf_schedule_trill (struct isis_area *area);
++#endif
+ #endif /* _ZEBRA_ISIS_SPF_H */
+diff --git isisd/isis_tlv.c isisd/isis_tlv.c
+index 94fa65e..0690243 100644
+--- isisd/isis_tlv.c
++++ isisd/isis_tlv.c
+@@ -43,13 +43,6 @@
+ #include "isisd/isis_pdu.h"
+ #include "isisd/isis_lsp.h"
+ 
+-extern struct isis *isis;
+-
+-/*
+- * Prototypes.
+- */
+-int add_tlv (u_char, u_char, u_char *, struct stream *);
+-
+ void
+ free_tlv (void *val)
+ {
+@@ -93,7 +86,10 @@ free_tlvs (struct tlvs *tlvs)
+   if (tlvs->ipv6_reachs)
+     list_delete (tlvs->ipv6_reachs);
+ #endif /* HAVE_IPV6 */
+-  
++  if (tlvs->router_capabilities)
++    list_delete (tlvs->router_capabilities);
++  if (tlvs->port_capabilities)
++    list_delete (tlvs->port_capabilities);
+   return;
+ }
+ 
+@@ -714,6 +710,28 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
+ 	  pnt += length;
+ 	  break;
+ 
++        case ROUTER_CAPABILITY:
++	  /* +------+------+------+------+------+-------+
++	   * |Length|          Router ID        | Flags |
++	   * +------+------+------+------+------+-------+
++	   * |    optional sub-TLVs (0-250 octets)      |
++	   * +------+------+------+------+------+-------+
++	   */
++	  *found |= TLVFLAG_ROUTER_CAPABILITY;
++	  if (tlvs->router_capabilities == NULL)
++              tlvs->router_capabilities = list_new ();
++	  listnode_add (tlvs->router_capabilities, (pnt - 1));
++	  pnt += length;
++	  break;
++
++        case PORT_CAPABILITY:
++	  *found |= TLVFLAG_PORT_CAPABILITY;
++	  if (tlvs->port_capabilities == NULL)
++	      tlvs->port_capabilities  = list_new ();
++	  listnode_add (tlvs->port_capabilities, (pnt - 1));
++	  pnt += length;
++	  break;
++
+ 	default:
+ 	  zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
+ 		     areatag, type, length);
+@@ -731,7 +749,8 @@ int
+ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
+ {
+ 
+-  if (STREAM_SIZE (stream) - stream_get_endp (stream) < (unsigned) len + 2)
++  if (STREAM_SIZE (stream) - stream_get_endp (stream) <
++      (unsigned) len + TLFLDS_LEN)
+     {
+       zlog_warn ("No room for TLV of type %d", tag);
+       return ISIS_WARNING;
+@@ -739,7 +758,8 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
+ 
+   stream_putc (stream, tag);	/* TAG */
+   stream_putc (stream, len);	/* LENGTH */
+-  stream_put (stream, value, (int) len);	/* VALUE */
++  if (len > 0)
++    stream_put (stream, value, (int) len);	/* VALUE */
+ 
+ #ifdef EXTREME_DEBUG
+   zlog_debug ("Added TLV %d len %d", tag, len);
+@@ -747,6 +767,52 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
+   return ISIS_OK;
+ }
+ 
++/*
++ * Add a subTLV to an existing TLV.  Returns ISIS_ERROR if it can't fit in the
++ * stream at all.  Returns ISIS_WARNING if it doesn't fit in the current TLV
++ * (but may fit in another one).
++ */
++int
++add_subtlv (u_char tag, u_char len, u_char * value, size_t tlvpos,
++    struct stream *stream)
++{
++  unsigned newlen;
++
++  /* Compute new outer TLV length */
++  newlen = stream_getc_from(stream, tlvpos + 1) + (unsigned) len + TLFLDS_LEN;
++
++  /* Check if it's possible to fit the subTLV in the stream at all */
++  if (STREAM_SIZE (stream) - stream_get_endp (stream) <
++      (unsigned) len + TLFLDS_LEN ||
++      len > 255 - TLFLDS_LEN)
++    {
++      zlog_debug ("No room for subTLV %d len %d", tag, len);
++      return ISIS_ERROR;
++    }
++
++  /* Check if it'll fit in the current TLV */
++  if (newlen > 255)
++    {
++#ifdef EXTREME_DEBUG
++      /* extreme debug only, because repeating TLV is usually possible */
++      zlog_debug ("No room for subTLV %d len %d in TLV %d", tag, len,
++		  stream_getc_from(stream, tlvpos));
++#endif /* EXTREME DEBUG */
++      return ISIS_WARNING;
++    }
++
++  stream_putc (stream, tag);	/* TAG */
++  stream_putc (stream, len);	/* LENGTH */
++  stream_put (stream, value, (int) len);	/* VALUE */
++  stream_putc_at (stream,  tlvpos + 1, newlen);
++
++#ifdef EXTREME_DEBUG
++  zlog_debug ("Added subTLV %d len %d to TLV %d", tag, len,
++	      stream_getc_from(stream, tlvpos));
++#endif /* EXTREME DEBUG */
++  return ISIS_OK;
++}
++
+ int
+ tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
+ {
+diff --git isisd/isis_tlv.h isisd/isis_tlv.h
+index fc9f35f..f421627 100644
+--- isisd/isis_tlv.h
++++ isisd/isis_tlv.h
+@@ -60,6 +60,7 @@
+  * P2P Adjacency State      240   y   n   n  RFC3373
+  * IIH Sequence Number      241   y   n   n  draft-shen-isis-iih-sequence
+  * Router Capability        242   -   -   -  draft-ietf-isis-caps
++ * Port Capability	    243   n   y   n  draft-eastlake-trill-bridge-isis
+  *
+  * 
+  * IS Reachability sub-TLVs we (should) support.
+@@ -85,6 +86,28 @@
+  * 32bit administrative tag           1   draft-ietf-isis-admin-tags
+  * 64bit administrative tag           2   draft-ietf-isis-admin-tags
+  * Management prefix color          117   draft-ietf-isis-wg-multi-topology
++ *
++ *
++ * Router Capability sub-TLVs we support (Values TBD, temporary for now).
++ * ____________________________________________________________________________
++ * Name                           Value   Status
++ * ____________________________________________________________________________
++ * TRILL Flags			     21	  draft-ietf-trill-rbridge-protocol
++ * TRILL Nickname and Tree Root	     22	  draft-ietf-trill-rbridge-protocol
++ * TRILL Distribution Tree Roots     23	  draft-ietf-trill-rbridge-protocol
++ * TRILL VLANs and Bridge Roots	     24	  draft-ietf-trill-rbridge-protocol
++ * TRILL ESADI Participation	     25	  draft-ietf-trill-rbridge-protocol
++ * TRILL VLAN Groups		     26	  draft-ietf-trill-rbridge-protocol
++ * TRILL VLAN Mapping		     27	  draft-ietf-trill-rbridge-protocol
++ *
++ *
++ * Port Capability sub-TLVs we support
++ * ____________________________________________________________________________
++ * Name                           Value   Status
++ * ____________________________________________________________________________
++ * TRILL Special VLANs and Flags     10	  draft-ietf-trill-rbridge-protocol
++ * TRILL Enabled VLANs		     11	  draft-ietf-trill-rbridge-protocol
++ * TRILL Appointed Forwarders	     12	  draft-ietf-trill-rbridge-protocol
+  */
+ 
+ #define AREA_ADDRESSES            1
+@@ -109,12 +132,44 @@
+ #define IPV6_ADDR                 232
+ #define IPV6_REACHABILITY         236
+ #define WAY3_HELLO                240
++#define ROUTER_CAPABILITY	  242
++#define PORT_CAPABILITY		  243   /* TBD TRILL port capability TLV */
++
++/* ROUTER_CAPABILITY sub-TLVs for TRILL */
++#define	RCSTLV_TRILL_FLAGS	  21	/* TBD Flags */
++#define RCSTLV_TRILL_NICKNAME	  22	/* TBD Nickname and Tree Root */
++#define RCSTLV_TRILL_TREE_ROOTS	  23	/* TBD Distribution Tree Roots */
++#define RCSTLV_TRILL_VLANSROOTS	  24	/* TBD VLANs and Bridge Roots */
++#define RCSTLV_TRILL_ESADI	  25	/* TBD ESADI Participation */
++#define RCSTLV_TRILL_VLANGROUPS	  26	/* TBD VLAN Groups */
++#define RCSTLV_TRILL_VLANMAPPING  27	/* TBD VLAN Mapping */
++
++/* PORT_CAPABILITY sub-TLVs for TRILL */
++#define PCSTLV_VLANS		  10	/* Special VLANs and Flags */
++#define PCSTLV_ENABLEDVLANS	  11	/* Enabled VLANs */
++#define PCSTLV_APPFORWARDERS	  12	/* Appointed Forwarders */
+ 
+ #define IS_NEIGHBOURS_LEN (ISIS_SYS_ID_LEN + 5)
+ #define LAN_NEIGHBOURS_LEN 6
+ #define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN)	/* FIXME: should be entry */
+ #define IPV4_REACH_LEN 12
+ #define IPV6_REACH_LEN 22
++#define TLFLDS_LEN 2			         /* Length of Type & Len 8-bit fields */	
++#define ROUTER_CAPABILITY_MIN_LEN  5		 /* Min len of router capability TLV */
++#define ROUTER_CAPABILITY_MAX_LEN  250 		 /* Max len of router capability TLV */
++
++/* TRILL Flags sub-TLV */
++#define TRILL_FLAGS_SUBTLV_MIN_LEN 1 		 /* Len of sub-TLV val */
++#define	TRILL_FLAGS_V0	0x80
++#define	TRILL_FLAGS_V1	0x40
++#define	TRILL_FLAGS_V2	0x20
++#define	TRILL_FLAGS_V3	0x10
++
++#define TRILL_NICKNAME_SUBTLV_MIN_LEN 7 	 /* Len of TRILL nickname sub-TLV value field */
++#define TRILL_VLANSNBRIROOTS_SUBTLV_MIN_LEN 4    /* Len of variable len TRILL VLANs and Bridge Roots sub-TLV value field */
++#define PCSTLV_VLANS_LEN	 4		 /* Exact len of port capability VLANs sub-TLV */
++#define PCSTLV_VLANFWDERS_MIN_LEN 6		 /* Min. len of each appointed forwarders sub-TLV */
++#define PCSTLV_ENABLEDVLANS_MIN_LEN 3		 /* Min. len of enabled VLANS sub-TLV */
+ 
+ /* struct for neighbor */
+ struct is_neigh
+@@ -131,6 +186,15 @@ struct te_is_neigh
+   u_char sub_tlvs_length;
+ };
+ 
++/* Decode and encode three-octet metric into host byte order integer */
++#define GET_TE_METRIC(t) \
++  (((unsigned)(t)->te_metric[0]<<16) | ((t)->te_metric[1]<<8) | \
++   (t)->te_metric[2])
++#define SET_TE_METRIC(t, m) \
++  (((t)->te_metric[0] = (m) >> 16), \
++   ((t)->te_metric[1] = (m) >> 8), \
++   ((t)->te_metric[2] = (m)))
++
+ /* struct for es neighbors */
+ struct es_neigh
+ {
+@@ -213,7 +277,6 @@ struct ipv6_reachability
+   u_char prefix_len;
+   u_char prefix[16];
+ };
+-#endif /* HAVE_IPV6 */
+ 
+ /* bits in control_info */
+ #define CTRL_INFO_DIRECTION    0x80
+@@ -223,6 +286,92 @@ struct ipv6_reachability
+ #define DISTRIBUTION_INTERNAL  0
+ #define DISTRIBUTION_EXTERNAL  1
+ #define CTRL_INFO_SUBTLVS      0x20
++#endif /* HAVE_IPV6 */
++
++/* internal trill nickname struct */
++struct trill_nickname
++{
++  u_int16_t name;		/* network byte order */
++  u_int8_t priority;
++};
++
++/* Router Capability TLV: used in LSPs */
++struct router_capability_tlv
++{
++  u_char router_id[4];		   /* 4 octet Router ID */
++  u_int8_t flags;		   /* 1 octet flags */
++};
++
++/* internal router capability struct, includes tlv length */
++struct router_capability
++{
++  u_int8_t len;  		/* total length of the TLV */
++  struct router_capability_tlv rt_cap_tlv;
++};
++
++/* Port Capability TLV: used in Hellos */
++struct port_capability_tlv
++{
++  u_int8_t len;
++  u_int8_t value[1];
++};
++
++#ifdef __SUNPRO_C
++#pragma pack(1)
++#endif
++
++/* LSP: ROUTER_CAPABILITY RCSTLV_TRILL_NICKNAME */
++struct trill_nickname_subtlv
++{
++    u_int8_t tn_priority;
++    u_int16_t tn_nickname;
++    u_int16_t tn_trootpri;
++    u_int16_t tn_treecount;
++} __attribute__ ((packed));
++
++#ifdef __SUNPRO_C
++#pragma pack()
++#endif
++
++/* LSP: ROUTER_CAPABILITY RCSTLV_TRILL_VLANSROOTS */
++struct trill_vlan_bridge_roots_subtlv
++{
++    u_int16_t vlan_start;
++    u_int16_t vlan_end;
++};
++
++/* flags for vlan_start */
++#define	TVRFS_M4	0x8000
++#define	TVRFS_M6	0x4000
++#define	TVRFS_OM	0x2000
++#define	TVRFS_R		0x1000
++
++/* Hello: PORT_CAPABILITY PCSTLV_VLANS */
++struct trill_vlanflags_subtlv
++{
++    u_int16_t outer_vlan;
++    u_int16_t desig_vlan;
++};
++
++/* flags for outer_vlan */
++#define	TVFFO_AF	0x8000
++#define	TVFFO_AC	0x4000
++#define	TVFFO_VM	0x2000
++#define	TVFFO_R		0x1000
++
++/* Hello: PORT_CAPABILITY PCSTLV_APPFORWARDERS */
++struct appointed_vlanfwder_subtlv
++{
++    u_int16_t appointee_nick;
++    u_int16_t vlan_start;
++    u_int16_t vlan_end;
++};
++
++/* Hello: PORT_CAPABILITY PCSTLV_ENABLEDVLANS */
++struct trill_enabledvlans_subtlv
++{
++    u_int16_t start_vlan;
++};
+ 
+ /*
+  * Pointer to each tlv type, filled by parse_tlvs()
+@@ -249,6 +398,8 @@ struct tlvs
+   struct list *ipv6_reachs;
+ #endif
+   struct isis_passwd auth_info;
++  struct list *router_capabilities;
++  struct list *port_capabilities;
+ };
+ 
+ /*
+@@ -277,6 +428,8 @@ struct tlvs
+ #define TLVFLAG_TE_ROUTER_ID              (1<<19)
+ #define TLVFLAG_CHECKSUM                  (1<<20)
+ #define TLVFLAG_GRACEFUL_RESTART          (1<<21)
++#define TLVFLAG_ROUTER_CAPABILITY         (1<<22)
++#define TLVFLAG_PORT_CAPABILITY	          (1<<23)
+ 
+ void init_tlvs (struct tlvs *tlvs, uint32_t expected);
+ void free_tlvs (struct tlvs *tlvs);
+@@ -284,6 +437,11 @@ int parse_tlvs (char *areatag, u_char * stream, int size,
+ 		u_int32_t * expected, u_int32_t * found, struct tlvs *tlvs);
+ void free_tlv (void *val);
+ 
++int add_tlv (u_char, u_char, u_char *, struct stream *);
++int add_subtlv (u_char, u_char, u_char *, size_t, struct stream *);
++
++int tlv_add_trill_nickname (struct trill_nickname *nick_info, struct stream *stream,
++		struct isis_area *area);
+ int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream);
+ int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream);
+ int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream);
+@@ -304,6 +462,7 @@ int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream);
+ int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream);
+ #endif /* HAVE_IPV6 */
+ 
++int tlv_add_trill_vlans(struct isis_circuit *);
+ int tlv_add_padding (struct stream *stream);
+ 
+ #endif /* _ZEBRA_ISIS_TLV_H */
+diff --git isisd/isis_trill.c isisd/isis_trill.c
+new file mode 100644
+index 0000000..3a38660
+--- /dev/null
++++ isisd/isis_trill.c
+@@ -0,0 +1,2346 @@
++/*
++ * IS-IS Rout(e)ing protocol - isis_trill.c
++ *
++ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it 
++ * under the terms of the GNU General Public Licenseas published by the Free 
++ * Software Foundation; either version 2 of the License, or (at your option) 
++ * any later version.
++ *
++ * This program 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 this program; if not, write to the Free Software Foundation, Inc., 
++ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ */
++#include <zebra.h>
++#include <libdladm.h>
++#include <libdllink.h>
++#include <libdlbridge.h>
++#include <libdlvlan.h>
++#include <net/trill.h>
++
++#include "thread.h"
++#include "linklist.h"
++#include "stream.h"
++#include "vty.h"
++#include "log.h"
++#include "command.h"
++#include "memory.h"
++#include "prefix.h"
++#include "hash.h"
++#include "if.h"
++#include "table.h"
++#include "privs.h"
++
++#include "isisd/dict.h"
++#include "isisd/isis_common.h"
++#include "isisd/isis_constants.h"
++#include "isisd/isis_circuit.h"
++#include "isisd/isis_flags.h"
++#include "isisd/isis_tlv.h"
++#include "isisd/isis_lsp.h"
++#include "isisd/isis_vlans.h"
++#include "isisd/isis_trill.h"
++#include "isisd/isisd.h"
++#include "isisd/isis_misc.h"
++#include "isisd/isis_pdu.h"
++#include "isisd/isis_events.h"
++#include "isisd/bool.h"
++#include "isisd/isis_spf.h"
++#include "isisd/isis_adjacency.h"
++#include "isisd/isis_csm.h"
++
++extern struct zebra_privs_t isisd_privs;
++
++/* Number of available (randomly-assigned) nicknames, not counting reserved */
++static int nickavailcnt;
++
++/* Vector with bits set to indicate nicknames in use */
++static u_char nickbitvector[NICKNAMES_BITARRAY_SIZE];
++#define	NICK_IS_USED(n)		(nickbitvector[(n)/8] & (1<<((n)%8)))
++#define	NICK_SET_USED(n)	(nickbitvector[(n)/8] |= (1<<((n)%8)))
++#define	NICK_CLR_USED(n)	(nickbitvector[(n)/8] &= ~(1<<((n)%8)))
++
++/* Number of zero bits in each word of vector */
++static u_char clear_bit_count[CLEAR_BITARRAY_SIZE];
++
++static dladm_handle_t dlhandle;
++static char cfile_present = TRUE;
++
++static nickdb_search_result trill_search_rbridge (struct isis_area *, nickinfo_t *, dnode_t **);
++static void trill_dict_delete_nodes (dict_t *, dict_t *, void *, int);
++static int trill_nick_conflict(nickinfo_t *, nickinfo_t *);
++static int trill_parse_lsp (struct isis_lsp *, nickinfo_t *);
++
++/* Test and mark a nickname in host byte order as allocated or free */
++static int
++trill_nickname_nickbitmap_op(u_int16_t nick, int update, int val)
++{
++  if (nick == RBRIDGE_NICKNAME_NONE || nick == RBRIDGE_NICKNAME_UNUSED)
++    return FALSE;
++  if (val)
++    {
++      if (NICK_IS_USED(nick))
++	return TRUE;
++      if (!update)
++	return FALSE;
++      NICK_SET_USED(nick);
++      if (nick < RBRIDGE_NICKNAME_MINRES)
++	nickavailcnt--;
++      clear_bit_count[nick / CLEAR_BITARRAY_ENTRYLENBITS]--;
++    }
++  else
++    {
++      if (!NICK_IS_USED(nick))
++	return TRUE;
++      if (!update)
++	return FALSE;
++      NICK_CLR_USED(nick);
++      if (nick < RBRIDGE_NICKNAME_MINRES)
++	nickavailcnt++;
++      clear_bit_count[nick / CLEAR_BITARRAY_ENTRYLENBITS]++;
++    }
++  return FALSE;
++}
++
++/*
++ * trill_nickname_gen calls this function to randomly allocate a new nickname
++ * in host byte order. We also keep track of allocated and in-use nicks.
++ */
++static u_int16_t
++trill_nickname_alloc(void)
++{
++  u_int i, j, k;
++  u_int16_t nick;
++  u_int nicknum;
++  u_int freenickcnt = 0;
++
++  if (nickavailcnt < 1)
++    return RBRIDGE_NICKNAME_NONE;
++ 
++  /*
++   * Note that rand() usually returns 15 bits, so we overlap two values to make
++   * sure we're getting at least 16 bits (as long as rand() returns 8 bits or
++   * more).  Using random() instead would be better, but isis_main.c uses
++   * srand.
++   */
++  nicknum = ((rand() << 8) | rand()) % nickavailcnt;
++  for ( i = 0; i < sizeof (clear_bit_count); i++ )
++    {
++      freenickcnt += clear_bit_count[i];
++      if (freenickcnt <= nicknum)
++        continue;
++      nicknum -= freenickcnt - clear_bit_count[i];
++      nick = i * CLEAR_BITARRAY_ENTRYLEN * 8;
++      for ( j = 0; j < CLEAR_BITARRAY_ENTRYLEN; j++)
++	{
++	   for (k = 0; k < 8; k++, nick++)
++	     {
++		if (!NICK_IS_USED(nick) && nicknum-- == 0)
++		  {
++		    trill_nickname_nickbitmap_op (nick, TRUE, TRUE);
++		    return nick;
++		  }
++	     }
++	}
++      break;
++    }
++  assert (0);
++  return 0;
++}
++
++static void trill_nickname_reserve(u_int16_t nick_nbo)
++{
++  trill_nickname_nickbitmap_op(ntohs(nick_nbo), TRUE, TRUE);
++}
++
++static int is_nickname_used(u_int16_t nick_nbo)
++{
++  return trill_nickname_nickbitmap_op(ntohs(nick_nbo), FALSE, TRUE);
++}
++
++static void trill_nickname_free(u_int16_t nick_nbo)
++{
++  trill_nickname_nickbitmap_op(ntohs(nick_nbo), TRUE, FALSE);
++}
++
++static void
++trill_nickname_gen(struct isis_area *area)
++{
++  u_int16_t nick;
++
++  nick = trill_nickname_alloc();
++  if (nick == RBRIDGE_NICKNAME_NONE)
++    {
++      zlog_err("RBridge nickname allocation failed.  No nicknames available.");
++      abort();
++    }
++  else
++    {
++      area->trill->nick.name = htons(nick);
++      dladm_bridge_set_nick(area->trill->name, nick);
++      if (isis->debugs & DEBUG_TRILL_EVENTS)
++	zlog_debug("ISIS TRILL generated nick:%u", nick);
++    }
++}
++
++static int
++nick_cmp(const void *key1, const void *key2)
++{
++  return (memcmp(key1, key2, sizeof(u_int16_t)));
++}
++
++static int
++sysid_cmp(const void *key1, const void *key2)
++{
++  return (memcmp(key1, key2, ISIS_SYS_ID_LEN));
++}
++
++void
++trill_area_init(struct isis_area *area)
++{
++  u_int i;
++
++  area->trill->status = 0;
++  area->trill->nick.priority = DFLT_NICK_PRIORITY;
++  area->trill->root_priority = TRILL_DFLT_ROOT_PRIORITY;
++  area->trill->nickdb = dict_create(MAX_RBRIDGE_NODES, nick_cmp);
++  area->trill->sysidtonickdb = dict_create(MAX_RBRIDGE_NODES, sysid_cmp);
++
++  nickavailcnt = RBRIDGE_NICKNAME_MINRES - RBRIDGE_NICKNAME_NONE - 1;
++  memset(nickbitvector, 0, sizeof(nickbitvector));
++  for (i = 0; i < sizeof (clear_bit_count); i++)
++    clear_bit_count[i] = CLEAR_BITARRAY_ENTRYLENBITS;
++
++  /* These two are always reserved */
++  NICK_SET_USED(RBRIDGE_NICKNAME_NONE);
++  NICK_SET_USED(RBRIDGE_NICKNAME_UNUSED);
++  clear_bit_count[RBRIDGE_NICKNAME_NONE / CLEAR_BITARRAY_ENTRYLENBITS]--;
++  clear_bit_count[RBRIDGE_NICKNAME_UNUSED / CLEAR_BITARRAY_ENTRYLENBITS]--;
++
++  isis_event_system_type_change (area, TRILL_ISIS_LEVEL);
++  memset (area->trill->lspdb_acq_reqs, 0, sizeof(area->trill->lspdb_acq_reqs));
++}
++
++/*
++ * Called from isisd to handle trill nickname command.
++ * Nickname is user configured and in host byte order
++ */
++int
++trill_area_nickname(struct isis_area *area, u_int16_t nickname)
++{
++  int savednick;
++
++  if (nickname == RBRIDGE_NICKNAME_NONE)
++    {
++      /* Called from "no trill nickname" command */
++      trill_nickname_gen (area);
++      SET_FLAG (area->trill->status, TRILL_NICK_SET);
++      SET_FLAG (area->trill->status, TRILL_AUTONICK);
++      lsp_regenerate_schedule (area);
++      return TRUE;
++    }
++
++  nickname = htons(nickname);
++  savednick = area->trill->nick.name;
++  area->trill->nick.name = nickname;
++  area->trill->nick.priority |= CONFIGURED_NICK_PRIORITY;
++
++  /*
++   * Check if we know of another RBridge already using this nickname.
++   * If yes check if it conflicts with the nickname in the database.
++   */
++  if (is_nickname_used(nickname))
++    {
++      nickinfo_t ni;
++      dnode_t *dnode;
++      nicknode_t *tnode;
++
++      ni.nick = area->trill->nick;
++      memcpy(ni.sysid, isis->sysid, ISIS_SYS_ID_LEN);
++      if (trill_search_rbridge (area, &ni, &dnode) == FOUND)
++        {
++          assert (dnode);
++          tnode = dnode_get (dnode);
++          if (trill_nick_conflict (&(tnode->info), &ni))
++            {
++              trill_dict_delete_nodes (area->trill->nickdb,
++		     area->trill->sysidtonickdb, &nickname, FALSE);
++	    }
++	  else
++	    {
++              /* 
++	       * The other nick in our nickdb has greater priority so return
++	       * fail, restore nick and let user configure another nick.
++	       */
++               area->trill->nick.name = savednick; 
++	       area->trill->nick.priority &= ~CONFIGURED_NICK_PRIORITY;
++               return FALSE;
++	    }
++	}
++    }
++
++  trill_nickname_reserve(nickname);
++  SET_FLAG(area->trill->status, TRILL_NICK_SET);
++  UNSET_FLAG(area->trill->status, TRILL_AUTONICK);
++  lsp_regenerate_schedule (area);
++  return TRUE;
++}
++
++static void
++trill_nickname_priority_update(struct isis_area *area, u_int8_t priority)
++{
++  if (priority)
++    {
++      area->trill->nick.priority = priority;
++      SET_FLAG(area->trill->status, TRILL_PRIORITY_SET);
++    }
++  else
++    {
++      /* Called from "no trill nickname priority" command */
++      area->trill->nick.priority = DFLT_NICK_PRIORITY;
++      UNSET_FLAG(area->trill->status, TRILL_PRIORITY_SET);
++    }
++
++  /*
++   * Set the configured nickname priority bit if the
++   * nickname was not automatically generated. 
++   */
++  if (!CHECK_FLAG(area->trill->status, TRILL_AUTONICK))
++     area->trill->nick.priority |= CONFIGURED_NICK_PRIORITY;
++  lsp_regenerate_schedule (area);
++} 
++
++static void
++trill_nickinfo_del(nickinfo_t *ni)
++{
++  if (ni->dt_roots != NULL)
++    list_delete (ni->dt_roots);
++  if (ni->broots != NULL)
++    list_delete (ni->broots);
++}
++
++static void
++trill_dict_remnode ( dict_t *dict, dnode_t *dnode)
++{
++  nicknode_t *tnode;
++
++  assert (dnode);
++  tnode = dnode_get (dnode);
++  assert(tnode->refcnt);
++  tnode->refcnt--;
++  if (tnode->refcnt == 0)
++    {
++      isis_spftree_del (tnode->rdtree);
++      trill_nickinfo_del (&tnode->info);
++      if (tnode->adjnodes)
++        list_delete (tnode->adjnodes);
++      if (tnode->vlans_reachable)
++        list_delete (tnode->vlans_reachable);
++      XFREE (MTYPE_ISIS_TRILL_NICKDB_NODE, tnode);
++    }
++  dict_delete_free (dict, dnode);
++}
++
++static void
++trill_dict_free (dict_t *dict)
++{
++  dnode_t *dnode, *next;
++
++  dnode = dict_first (dict);
++  while (dnode)
++    {
++      next = dict_next (dict, dnode);
++      trill_dict_remnode (dict, dnode);
++      dnode = next;
++    }
++  dict_free_nodes (dict);
++  dict_destroy (dict);
++}
++
++void
++trill_area_free(struct isis_area *area)
++{
++  area->trill->status = 0;
++  trill_dict_free (area->trill->nickdb);
++  trill_dict_free (area->trill->sysidtonickdb);
++  if (area->trill->fwdtbl)
++    list_delete (area->trill->fwdtbl);
++  if (area->trill->adjnodes)
++    list_delete (area->trill->adjnodes);
++  if (area->trill->dt_roots)
++    list_delete (area->trill->dt_roots);
++  if (area->trill->vlans_reachable)
++    list_delete (area->trill->vlans_reachable);
++}
++
++/* 
++ * Delete nickname node in both databases. First a lookup
++ * of the node in first db by key1 and using the found node
++ * a lookup of the node in second db is done. Asserts the
++ * node if exists in one also exist in the second db.
++ */
++static void
++trill_dict_delete_nodes (dict_t *dict1, dict_t *dict2,
++		void *key1, int key2isnick)
++{
++  dnode_t *dnode1;
++  dnode_t *dnode2;
++  nicknode_t *tnode;
++  int nickname;
++
++  dnode1 = dict_lookup (dict1, key1);
++  if (dnode1)
++    {
++      tnode = (nicknode_t *) dnode_get(dnode1);
++      if (tnode)
++        {
++          if (key2isnick)
++	    {
++              dnode2 = dict_lookup (dict2, &(tnode->info.nick.name));
++              nickname = tnode->info.nick.name;
++	    }
++          else 
++            {
++              dnode2 = dict_lookup (dict2, tnode->info.sysid);
++	      nickname = *(int *)key1;
++	    }
++	  assert (dnode2);
++          trill_dict_remnode (dict2, dnode2);
++
++	  /* Mark the nickname as available */
++	  trill_nickname_free(nickname);
++	}
++      trill_dict_remnode (dict1, dnode1);
++    }
++}
++
++static void
++trill_update_nickinfo (nicknode_t *tnode, nickinfo_t *recvd_nick)
++{
++  trill_nickinfo_del(&tnode->info);
++  tnode->info = *recvd_nick;
++  /* clear copied nick */
++  memset(recvd_nick, 0, sizeof (*recvd_nick));
++}
++
++static void
++trill_dict_create_nodes (struct isis_area *area, nickinfo_t *nick)
++{
++  nicknode_t *tnode;
++
++  tnode = XCALLOC (MTYPE_ISIS_TRILL_NICKDB_NODE, sizeof(nicknode_t));
++  tnode->info = *nick;
++  dict_alloc_insert (area->trill->nickdb, &(tnode->info.nick.name), tnode);
++  tnode->refcnt = 1;
++  dict_alloc_insert (area->trill->sysidtonickdb, tnode->info.sysid, tnode);
++  tnode->refcnt++;
++  /* Mark the nickname as reserved */
++  trill_nickname_reserve(nick->nick.name);
++  tnode->rdtree = isis_spftree_new();
++  /* clear copied nick */
++  memset(nick, 0, sizeof (*nick));
++}
++
++/*
++ * Update nickname information in the dictionary objects.
++ */
++static void
++trill_nickdb_update ( struct isis_area *area, nickinfo_t *newnick)
++{
++  dnode_t *dnode;
++  nicknode_t *tnode;
++  nickdb_search_result res;
++
++  res = trill_search_rbridge (area, newnick, &dnode);
++  if (res == NOTFOUND) 
++    {
++      trill_dict_create_nodes (area, newnick);
++      return;
++    }
++
++  assert (dnode);
++  tnode = dnode_get (dnode);
++
++  /* If nickname & system ID of the node in our database match
++   * the nick received then we don't have to change any dictionary
++   * nodes. Update only the node information. Otherwise we update
++   * the dictionary nodes.
++   */
++  if (res == DUPLICATE || res == PRIORITY_CHANGE_ONLY)
++    {
++      trill_update_nickinfo (tnode, newnick);
++      return;
++    }
++
++  /*
++   * If the RBridge has a new nick then update its nick only.
++   */
++  if (res == NICK_CHANGED) 
++    {
++      if (isis->debugs & DEBUG_TRILL_EVENTS)
++        zlog_debug("ISIS TRILL storing new nick:%d from sysID:%s",
++	   ntohs(tnode->info.nick.name), sysid_print(tnode->info.sysid));
++
++      /* Delete the current nick in from our database */
++      trill_dict_delete_nodes (area->trill->sysidtonickdb,
++	      area->trill->nickdb, tnode->info.sysid, TRUE);
++      /* Store the new nick entry */
++      trill_dict_create_nodes (area, newnick);
++    }
++  else
++    {
++      /*